Project import generated by Copybara. NOKEYCHECK=True GitOrigin-RevId: fb8d5c102ccf53861155f48666a27a917d89f198
diff --git a/release_notes.txt b/release_notes.txt new file mode 100755 index 0000000..c74026b --- /dev/null +++ b/release_notes.txt
@@ -0,0 +1,31 @@ +================================ +WLAN DHD Driver Release Notes +================================ + +DHD_REL_1_141_66_4 +* Fix Makefile to resolve __DATE__ & __TIME__ macro build error seen on gcc ver 4.9.0. +* Fix kernel WARN message seen during rmmod. +* Linux 4.x kernel support +* Sync Pattern Matching Timeout Filter review changes from master branch, change + WLC_E_PKT_FILTER event code from 154 to 165 and WLC_E_PKT_FILTER_TIMEOUT code from 0 to 1. + +DHD_REL_1_141_66_3 +* Fix conditional compilation build errors. + +DHD_REL_1_141_66_2 +* Sync wl tool cmd (Pattern Matching Timeout Filter) updates from firmware to DHD branch. +* Add extended event mask updates to support event numbers greater than 128. +* Sync wl tool cmd (Counters, SR Dump, UC Fatal) updates from firmware to DHD branch. +* Fix for Interrupt Stuck issue seen during suspend/resume. +* Sometimes DHD enters into suspend state when bus is still awake due to absence of + wake locks on Non-Android platforms, so perform bus sleep status check using + bus_sleep event to prevent dhd entering into suspend state when bus is still awake. + +DHD_REL_1_141_66_1 +* Avoid wowl config on android systems during suspend. +* Add support for configuring cfg80211 wowlan pattern filters through nl80211. +* Fix typo in get ioctl call in wl_cfg80211_update_power_mode(), it should be false. +* Fix to reload DHD driver without the need for reloading the entire sdio stack modules. +* Fix compilation error related to cleanup_work, because it is not present in kernel version 3.11 onwards. +* And add new dhd build targets to Makefile. +* Fix rmmod crash issue seen in wl_free_wdev function.
diff --git a/src/GNUmakefile.inc b/src/GNUmakefile.inc new file mode 100644 index 0000000..f8b97dc --- /dev/null +++ b/src/GNUmakefile.inc
@@ -0,0 +1,576 @@ +# Top level GNUmakefile for windows builds +# +# It includes makefiles/*.mk for windows buildtype rules +# and sources(windows style makefile). it doesn't depend on +# Makerules.env except to get SRCBASE if not yet defined. +# +# $Id: GNUmakefile.inc 429915 2013-10-16 16:28:57Z $ + +WLAN_ComponentsInUse ?= bcmwifi ppr hal +include $(dir $(lastword $(MAKEFILE_LIST)))makefiles/WLAN_Common.mk + +SHELL=bash +export SHELL +unexport C_DEFINES +HOSTNAME=$(shell hostname) +ERRORS := +WARNINGS := + +ifdef ECLOUD_BUILD_ID + CMDSHELL := $(subst \,/,$(COMSPEC)) + CMDSTART := $(CMDSHELL) /c start /min /separate +else # ECLOUD_BUILD_ID + CMDSHELL := + CMDSTART := +endif # ECLOUD_BUILD_ID + +### if SRCBASE is not defined, set it to wherever Makerules.env is found +ifndef SRCBASE + ifneq ($(wildcard ../Makerules.env), ) + SRCBASE = ../ + else + ifneq ($(wildcard ../../Makerules.env), ) + SRCBASE = ../.. + else + ifneq ($(wildcard ../../../Makerules.env),) + SRCBASE = ../../.. + else + ifneq ($(wildcard ../../../../Makerules.env),) + SRCBASE = ../../../.. + else + ifneq ($(wildcard ../../../../../Makerules.env),) + SRCBASE = ../../../../.. + else + ifneq ($(wildcard ../../../../../../Makerules.env),) + SRCBASE = ../../../../../.. + endif + endif + endif + endif + endif + endif +endif # ifndef SRCBASE + +ifeq ($(strip $(SRCBASE)), ) + ERRORS += "SRCBASE is not defined!" + ERRORS += "This variable must be defined in your sources or GNUsources file," + ERRORS += "or it may be calculated provided you are in a CVS source repository," + ERRORS += "and you are not too far below the root." +endif + +### if TTYPE is not defined, reinvoke this same makefile with TTYPE defined +###retail:free: --> $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=OPT all +###debug:checked: --> $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG all +###%: --> $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG MAKECMDGOALS=$@ $@ + +ifeq ($(origin TTYPE), undefined) + +all : debug free + +release : all + +unexport SRCFILE +ifndef SRCFILE + SRCFILE = ./sources +endif +include $(SRCFILE) + +# In some rare instances you may want to have the makefile synthesize +# explicit rules for all of your source files. You must do this if you +# are building a target with multiple source files of the same name, +# e.g. ./utils.c and ../ntddksim/utils.c. You might also want to use +# this method if you don't want to use VPATHs. +# +ifdef USE_SRCRULES + +SRCRULES=$(SRCFILE).mk +SOURCES.CPP := $(filter %.cpp %.CPP,$(SOURCES)) +SOURCES.C := $(filter %.c %.C,$(SOURCES)) + +$(SRCRULES) : $(SRCFILE) + @echo "building explicit source rules..." + @( \ + echo "# DO NOT EDIT!!!! DO NOT EDIT!!!! DO NOT EDIT!!!!"; \ + echo "# This file is automatically generated."; \ + echo "#"; \ + $(foreach f,$(SOURCES.C), echo '$$(OUTDIR_$$(TTYPE))/$(patsubst %.c,%.obj,$(subst /,_,$(f))) : $(f)'; echo ' $$(c-obj-command)'; echo;) \ + $(foreach f,$(SOURCES.CPP), echo '$$(OUTDIR_$$(TTYPE))/$(patsubst %.cpp,%.obj,$(subst /,_,$(f))) : $(f)'; echo ' $$(cpp-obj-command)'; echo;) \ + ) >$(SRCFILE).mk + +$(SRCFILE) : + echo making $@ + +retail free :: $(SRCRULES) + +debug checked :: $(SRCRULES) + +endif # USE_SRCRULES + +# +# End of rule synthesis section +# + +retail free :: + $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=OPT all + +debug checked :: + $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG all + +%GNUmakefile.inc : + echo making $@ + +GNUmakefile : + echo making $@ + +clean : + $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG MAKECMDGOALS=$@ $@ + +## This catch-all generic rule breaks make targets defined in module which +## call this makefile. +## % : FORCE +## $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG MAKECMDGOALS=$@ $@ + +.PHONY: all release free checked retail debug clean FORCE + + +### if TTYPE is defined, +### define commands, tools and compile rules +### include $(SRCFILE) +### build all :: target :: +else # TTYPE is defined + +# Define default command for printing errors and warnings. This will +# be redefined at the end of this makefile if any errors or warnings +# are encountered. +# +define print-errors +endef + +define print-warnings +endef + +# define the default command for compiling .c files into .obj files. +# Some target types will redefine this command. +# +# %.obj : %.c +define c-obj-command + $(CC) -c $(C$(TTYPE)FLAGS) -I$(OUTDIR_$(TTYPE)) $(CPPFLAGS) $(F$(TTYPE)) -Fo$@ $< +endef + +# define the default command for compiling .cpp files into .obj files. +# Some target types will redefine this command. +# +# %.obj : %.cpp +define cpp-obj-command + $(CC) -c $(C$(TTYPE)FLAGS) -I$(OUTDIR_$(TTYPE)) $(CPPFLAGS) $(F$(TTYPE)) -Fo$@ $< +endef + +# define the default command for compiling .asm files into .obj files. +# Some target types will redefine this command. +# +# %.obj : %.asm +define asm-obj-command + $(AS) -c $(AFLAGS) $(CPPFLAGS) $(F$(TTYPE)) -Fo$@ $< +endef + +# define the default command for compiling .rc files into .res files. +# Some target types will redefine this command. +# +# %.res : %.rc +define rc-res-command + export INCLUDE="$(OUTDIR_$(TTYPE));$(MSINCLUDE)"; \ + $(CMDSTART) $(RC) -r $(RCFLAGS) -fo$@ $< +endef + +all :: + $(print-warnings) +ifdef SHOWBUILDINFO + @echo " -------------------------------------------" + @echo " SRCFILE = $(SRCFILE)" + @echo " SOURCES = $(SOURCES)" + @echo " C_DEFINES = $(C_DEFINES)" + @echo " WLTUNEFILE = $(WLTUNEFILE)" + @echo " TARGETPATH = $(TARGETPATH)" + @echo " TARGETTYPE = $(TARGETTYPE)" + @echo " MAKE_VERSION = $(MAKE_VERSION)" + @echo " TTYPE = $(subst OPT,OPT(free),$(subst DBG,DBG(checked),$(TTYPE)))" + @echo " -------------------------------------------" +endif # SHOWBUILDINFO + +all :: + $(print-errors) + +include $(SRCBASE)/branding.inc + +ifeq ($(origin USEBCMUIO), undefined) +#if defined(USEBCMUIO) +USEBCMUIO=1 +#else +# undefine USEBCMUIO +USEBCMUIO= +#endif +endif + +BIN_OPT=retail +BIN_DBG=debug +BUILDENV_OPT=free +BUILDENV_DBG=checked +MSVSBUILDENV_OPT=Release +MSVSBUILDENV_DBG=Debug +OUTDIR_OPT = $(TARGETPATH)/free +OUTDIR_DBG = $(TARGETPATH)/checked + +OUTDIR_FREE = $(OUTDIR_OPT) +OUTDIR_CHECKED = $(OUTDIR_DBG) + + +CC = cl +AS = ml +RC = rc +MC = mc +LD = link +LIBCMD = lib +MTL = midl + +# Ignore any include path and lib paths that the user imports from +# the environment. +# +INCLUDE = + +ifeq ($(origin TARGETPATH), undefined) + TARGETPATH=. +endif +TARGETPATH := $(subst \,/,$(TARGETPATH)) + +DDKBUILDENV := $(BUILDENV_$(TTYPE)) +MSVSBUILDENV := $(MSVSBUILDENV_$(TTYPE)) +BIN := $(BIN_$(TTYPE)) +MC_FLAGS = -v + +### assume sources as entry point +ifndef SRCFILE + SRCFILE=./sources +endif + +include $(SRCFILE) +SRCRULES=$(SRCFILE).mk + +ifeq ($(findstring $(TARGETTYPE), "EXE DRIVER LIB DLL DLL16 EXE16 DYNLINK DOSEXE PROGRAM DUMMY"), ) + ERRORS += "TARGETTYPE is not defined or not recognized!" + ERRORS += "This variable must be defined with a recognized value" + ERRORS += "in your sources or GNUsources file." +endif + +# include any branding defined if they exist in the environment +ifneq ($(BRAND),) + C_DEFINES += -DBRAND="'$(BRAND)'" +endif # BRAND + +SOURCES.IDL := $(filter %.idl,$(SOURCES)) +SOURCES.TLB := $(patsubst %.idl,%.tlb,$(SOURCES.IDL)) +SOURCES._IC := $(patsubst %.idl,%_i.c,$(SOURCES.IDL)) + +SOURCES.OBJ := $(SOURCES) +SOURCES.OBJ := $(patsubst %.cpp,%.obj,$(SOURCES.OBJ)) +SOURCES.OBJ := $(patsubst %.CPP,%.obj,$(SOURCES.OBJ)) +SOURCES.OBJ := $(patsubst %.asm,%.obj,$(SOURCES.OBJ)) +SOURCES.OBJ := $(patsubst %.ASM,%.obj,$(SOURCES.OBJ)) +SOURCES.OBJ := $(patsubst %.c,%.obj,$(SOURCES.OBJ)) +SOURCES.OBJ := $(patsubst %.C,%.obj,$(SOURCES.OBJ)) +SOURCES.OBJ := $(filter %.obj,$(SOURCES.OBJ)) +# SOURCES.OBJ := $(notdir $(SOURCES.OBJ)) +SOURCES.OBJ := $(subst /,_,$(SOURCES.OBJ)) + +SOURCES.RES := $(patsubst %.rc,%.res,$(filter %.rc,$(SOURCES))) +SOURCES.MSG := $(patsubst %.mc,%.h,$(filter %.mc,$(SOURCES))) + +vpath %.rc .:..:../.. + + +ifdef USE_DEPENDENCIES + +# MAKECMDGOALS is not supported until gnumake version 3.76 so we hack +# it by explicitly setting MAKECMDGOALS in the clean rule at the top +# of this file. +# +ifneq ($(MAKECMDGOALS),clean) + +# BUG -- BUG -- BUG +# This code assumes that files are still unique without the extension. +# So no foo.c and foo.cpp in the same makefile. + +SOURCES.D := $(SOURCES) +SOURCES.D := $(patsubst %.c,%.d,$(SOURCES.D)) +SOURCES.D := $(patsubst %.C,%.d,$(SOURCES.D)) +SOURCES.D := $(patsubst %.cpp,%.d,$(SOURCES.D)) +SOURCES.D := $(patsubst %.CPP,%.d,$(SOURCES.D)) +SOURCES.D := $(filter %.d,$(SOURCES.D)) + +endif # MAKECMDGOALS != clean + +endif # ifdef USE_DEPENDENCIES + +SI_FLAGS = -translate:always,source,package + + + +# Target all just depends upon our target file. +all :: target post-build-target + +# The target file depends upon the directory where it will reside. +target :: $(OUTDIR_$(TTYPE))/NUL + +WLCFGDIR ?= $(SRCBASE)/wl/config +WLTUNEFILE ?= wltunable_sample.h + +# Create target directory if necessary. +$(OUTDIR_$(TTYPE))/NUL : + [ -d "$(@D)" ] || mkdir -p $(@D) +ifeq ($(WLCONF_GEN),true) + @if [ ! -f "$(@D)/wlconf.h" ]; then \ + cp -v $(WLCFGDIR)/$(WLTUNEFILE) $(@D)/wlconf.h; \ + elif ! diff -q $(WLCFGDIR)/$(WLTUNEFILE) $(@D)/wlconf.h; then \ + cp -v $(WLCFGDIR)/$(WLTUNEFILE) $(@D)/wlconf.h; \ + fi +endif + +# +# If the sources file specified a NTTARGETFILE0, build that first. +# +target :: $(NTTARGETFILE0) + + +# calculate some dynamic variables that are useful in build rules. +# +DEPS_OBJ = $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.OBJ)) +DEPS_RES = $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.RES)) +DEPS_TLB = $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.TLB)) +DEPS_MSG = $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.MSG)) +# Finally generate DEPENDENCIES list that are made as explicit dependencies +# in src/makefile/<obj-type>.mk file +DEPENDENCIES = $(DEPS_TLB) $(DEPS_MSG) $(DEPS_OBJ) $(DEPS_RES) +DOS_DEPS= $(shell echo $(filter-out %.tlb %.TLB %.h %.H %.def %.DEF,$^) | sed 's%//\(.\)/%\1:/%g') + + +$(OUTDIR_$(TTYPE))/%.i : %.c + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(CC) -E -P $(C$(TTYPE)FLAGS) $(CPPFLAGS) $(F$(TTYPE)) $< >$@ + +$(OUTDIR_$(TTYPE))/%.i : %.cpp + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(CC) -E -P $(C$(TTYPE)FLAGS) $(CPPFLAGS) $(F$(TTYPE)) $< >$@ + +$(OUTDIR_$(TTYPE))/%.d : %.c + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(calculate_dependencies) + +$(OUTDIR_$(TTYPE))/%.d : %.C + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(calculate_dependencies) + +$(OUTDIR_$(TTYPE))/%.d : %.cpp + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(calculate_dependencies) + +$(OUTDIR_$(TTYPE))/%.d : %.CPP + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(calculate_dependencies) + +$(OUTDIR_$(TTYPE))/%.obj : %.c + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(c-obj-command) + +$(OUTDIR_$(TTYPE))/%.obj : $(OUTDIR_$(TTYPE))/%.c + @echo "Compiling $(notdir $<) -> $(OUTDIR_$(TTYPE))/$(notdir $@)" + $(c-obj-command) + +$(OUTDIR_$(TTYPE))/%.obj : %.C + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(c-obj-command) + +$(OUTDIR_$(TTYPE))/%.obj : %.cpp + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(cpp-obj-command) + +$(OUTDIR_$(TTYPE))/%.obj : %.CPP + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(cpp-obj-command) + +ifdef ECLOUD_BUILD_ID +$(OUTDIR_$(TTYPE))/%.res : RC = rc +endif # ECLOUD_BUILD_ID + +$(OUTDIR_$(TTYPE))/%.res : %.rc + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(rc-res-command) + +# build rule for IDL files. +$(OUTDIR_$(TTYPE))/%.tlb $(OUTDIR_$(TTYPE))/%.h $(OUTDIR_$(TTYPE))/%_i.c : %.idl + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(MTL) /I $(MSSDK)/include /nologo /Oicf /out $(OUTDIR_$(TTYPE)) $< + +# Build rule for message file +$(OUTDIR_$(TTYPE))/%.rc $(OUTDIR_$(TTYPE))/%.h : %.mc + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(MC) -h $(OUTDIR_$(TTYPE)) -r $(OUTDIR_$(TTYPE)) $(MC_FLAGS) $< + +$(OUTDIR_$(TTYPE))/%.obj: %.asm + @echo "Compiling $(notdir $<) -> $(notdir $@)" + $(asm-obj-command) + +FORCE: + +clean :: + rm -rf $(OUTDIR_CHECKED) $(OUTDIR_FREE) $(SRCRULES) + + +ifeq ("$(TARGETTYPE)", "DRIVER") +ifeq ("$(DRIVERTYPE)", "WDM") +include $(SRCBASE)/makefiles/wdm.mk +else +ifeq ("$(DRIVERTYPE)", "WDM2600") + include $(SRCBASE)/makefiles/wdm2600.mk +else + include $(SRCBASE)/makefiles/driver.mk +endif +endif +endif + +ifneq ($(findstring x$(TARGETTYPE)x, "xDLLx xDYNLINKx"), ) +ifneq ($(findstring x$(HOSTOS)x, "xwincex"), ) +include $(SRCBASE)/makefiles/dllce.mk +else +include $(SRCBASE)/makefiles/dll.mk +endif +endif + +ifneq ($(findstring $(TARGETTYPE)x, "DLL16x"), ) +include $(SRCBASE)/makefiles/dll16.mk +endif + +ifneq ($(findstring $(TARGETTYPE)x, "EXE16x"), ) +include $(SRCBASE)/makefiles/exe16.mk +endif + +ifneq ($(findstring $(TARGETTYPE), "LIB"), ) +ifneq ($(findstring x$(HOSTOS)x, "xwincex"), ) +include $(SRCBASE)/makefiles/libce.mk +else +include $(SRCBASE)/makefiles/lib.mk +endif +endif + +ifneq ($(findstring $(TARGETTYPE), "xEXEx xPROGRAMx"), ) +ifneq ($(findstring x$(HOSTOS)x, "xwincex"), ) +include $(SRCBASE)/makefiles/exece.mk +else +include $(SRCBASE)/makefiles/exe.mk +endif +endif + +ifneq ($(findstring x$(TARGETTYPE)x, "xDOSEXEx"), ) +include $(SRCBASE)/makefiles/dosexe.mk +endif + +ifneq ($(findstring $(TARGETTYPE), "DUMMY"), ) +include $(SRCBASE)/makefiles/dummy.mk +endif + +# Set make variables that help find things like DDK's, SDK's, etc, +# depending upon the requirements expressed in the individual +# makefile(s). +include $(SRCBASE)/makefiles/env.mk + +# +# Add some rules so that our target depends on any libraries we are going +# to link against. +# +#target :: $(LIBS) + + +target :: $(OUTDIR_$(TTYPE))/$(TARGET) + +ifneq ($(wildcard ./makefile.inc), ) +include .\makefile.inc +endif + + +# +# If the sources file specified a NTTARGETFILES, build that last. +# + +target :: $(NTTARGETFILES) + + +target :: + @echo Finished compiling $@ + @echo "" + +post-build-target :: + +release: all + +.PHONY: all target release clean $(OUTDIR_$(TTYPE))/.depends + +ifneq ($(wildcard $(SRCRULES)), ) +include $(SRCRULES) +endif + +# only try to do dependency checking if we have some dependencies to check! +# +# It seems counter-intiutive but it looks like the +# include dependencies are evaluated in reverse order from their +# appearance in the makefile. Therefore we include the NUL file from +# the object directory *after* we include the dependency files +# themselves. This results in the object directory getting created +# before we build any of the dependency files. +# +ifneq ($(strip $(SOURCES.D)),) +include $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.D)) +include $(OUTDIR_$(TTYPE))/NUL +endif + +define calculate_dependencies + @ echo making $@ + $(SHELL) -ec 'gcc -MM -w -D_M_IX86=500 $(C_DEFINES) $(CPPFLAGS) $< \ + | sed '\''s?$*\.o[ :]*?$@ &?g'\'' >$@' +endef + +ifdef OTHER_SOURCES +all clean :: $(OTHER_SOURCES) + @echo "Go through OTHER_SOURCES: $(OTHER_SOURCES)" + $(foreach SRCFILE,$(OTHER_SOURCES),$(MAKE) SRCFILE=$(SRCFILE) TTYPE=$(TTYPE) $@; ) +endif + +vpath %.Lib $(LIBVPATH) +vpath %.LIB $(LIBVPATH) +vpath %.lib $(LIBVPATH) + +export PATH:=$(subst $(space),:,$(strip $(NEWPATH))):$(PATH) + +foo: + @echo _SDKROOT=$(_SDKROOT) + @echo NEWPATH=$(NEWPATH) + +endif +### end of ifeq ($(origin TTYPE), undefined) + +printenv: + env + +ifdef WARNING +define print-warnings +@echo "Warning **** Warning **** Warning **** Warning **** Warning" +@for warn in $(WARNING) ; do echo $$warn; done +@echo "Continuing..." +endef +endif # WARNING + +ifdef ERRORS +define print-errors +@echo "Error **** Error **** Error **** Error **** Error" +@for err in $(ERRORS) ; do echo $$err; done +@echo "Exiting makefile." +@exit 1 +endef +endif # ERRORS
diff --git a/src/Makerules b/src/Makerules new file mode 100644 index 0000000..19c8789 --- /dev/null +++ b/src/Makerules
@@ -0,0 +1,604 @@ +# +# Top level Makerules +# it uses Makerules.env for build env vars and optional branding.inc +# +# $ Copyright Open Broadcom Corporation $ +# +# $Id: Makerules 444746 2013-12-20 20:22:37Z $ + +# This is the TOP level makefile rules, which is used by many makefiles. +# Please be cautious on changes, especially compatibilities. +# e.g. new gcc compile option should be protected with version check +# or "check_gcc" trick + +# first rule (default) +all: + +WLAN_ComponentsInUse ?= bcmwifi +include $(dir $(lastword $(MAKEFILE_LIST)))makefiles/WLAN_Common.mk + +# Set up the build environment variables +include ${SRCBASE}/Makerules.env + +ifeq ($(HOSTOS), Windows_NT) + +# force use of bash, otherwise you will get the broken sh.exe. +SHELL=bash + +endif + +# +# Setup make variables depending on target +# + +ifeq ($(TARGETOS), unix) + + # The environment for native unix builds + + EXEEXT = + OBJEXT = .o + GCINCS = $(strip -I$(SRCBASE)/include $(WLAN_ComponentIncPath)) $(WLAN_StdIncPathA) + GCDEFS = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH) + + ifeq ($(TARGETARCH), x86_mmx) + GCDEFS := $(GCDEFS) -D_X86_ -D_MMX_ + endif + ifeq ($(TARGETARCH), x86) + GCDEFS := $(GCDEFS) -D_X86_ + endif + ifeq ($(TARGETARCH), x86_android_ndk_r6b) + GCDEFS := $(GCDEFS) -D_X86_ + endif + ifeq ($(TARGETARCH), mips) + GCDEFS := $(GCDEFS) -D_MIPS_ + endif + ifeq ($(TARGETARCH), mips_be) + GCDEFS := $(GCDEFS) -D_MIPS_ -DIL_BIGENDIAN + endif + ifeq ($(TARGETARCH), arm) + GCDEFS := $(GCDEFS) -D_ARM_ -DIL_BIGENDIAN + endif + ifeq ($(TARGETARCH), arm_le) + GCDEFS := $(GCDEFS) -D_ARM_ + endif + ifeq ($(TARGETARCH), arm_android) + GCDEFS := $(GCDEFS) -D_ARM_ + endif + ifeq ($(TARGETARCH), arm_android_ndk_r6b) + GCDEFS := $(GCDEFS) -D_ARM_ + endif + + ifeq ($(TARGETENV), freebsd) + GCINCS := $(GCINCS) -I/usr/pkg/include -I/usr/include + endif + ifeq ($(TARGETENV), sun4) + GCDEFS := $(GCDEFS) -D_SPARC_ + endif + ifeq ($(TARGETENV), macos) + MACOS_VER := $(shell sw_vers -productVersion) + + ifneq (,$(findstring 10.9,$(MACOS_VER))) + SDK=/Applications/Xcode.app/Contents/Developer/SDKs/MacOSX10.9.sdk + else + ifneq (,$(findstring 10.8,$(MACOS_VER))) + SDK=/Applications/Xcode.app/Contents/Developer/SDKs/MacOSX10.8.sdk + else + ifneq (,$(findstring 10.7,$(MACOS_VER))) + SDK=/Developer/SDKs/MacOSX10.7.sdk + else + ifneq (,$(findstring 10.6,$(MACOS_VER))) + SDK=/Developer/SDKs/MacOSX10.6.sdk + else + ifneq (,$(findstring 10.5,$(MACOS_VER))) + SDK=/Developer/SDKs/MacOSX10.5.sdk + else + SDK=/Developer/SDKs/MacOSX10.4u.sdk + endif + endif + endif + endif + endif + + GCDEFS := $(GCDEFS) -DMACOSX + GCDEFS := $(GCDEFS) -pipe -fpascal-strings -fasm-blocks -fmessage-length=0 + GCDEFS := $(GCDEFS) -fvisibility=hidden -isysroot $(SDK) + + ifeq ($(TARGETARCH), PPC) + GCDEFS := $(GCDEFS) -arch ppc -mtune=G4 + GLDFLAGS = -arch ppc -Wl,-syslibroot,$(SDK) + endif + ifeq ($(TARGETARCH), x86) + GCDEFS := $(GCDEFS) -arch x86_64 + GLDFLAGS = -arch x86_64 + endif + endif + + GCOPTS = + GCFLAGS = -g -Wall + + CC_TARGET =-o $@ + LINK_TARGET =-o $@ + + ifeq ($(TARGETENV), linuxmips) + TARGET_PREFIX = mipsel-linux- + else + ifeq ($(TARGETENV), linuxmips_be) + TARGET_PREFIX = mips-linux- + else + ifeq ($(TARGETENV), linuxarm) + TARGET_PREFIX = armeb-linux- + else + ifeq ($(TARGETENV), linuxarm_le) + TARGET_PREFIX = arm-linux- + else + ifeq ($(TARGETENV), android) + TARGET_PREFIX = arm-eabi- + GCFLAGS += -Dlinux + GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/android-ndk-r3/build/platforms/android-3/arch-arm/usr/include +# GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/arm-eabi/include/bionic/libc/include +# GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/arm-eabi/include/bionic/libc/arch-arm/include/ + GCFLAGS += -I/tools/linux/src/linux-2.6.25-01843-gfea26b0/include/ + else + ifeq ($(TARGETENV), android_ndk_r6b) + #TARGET_PREFIX = arm-linux-androideabi- + + ifeq ($(TARGET_PREFIX),) +$(warning : TARGET_PREFIX is not set!) + endif + ifeq ($(TARGET_NDK),) +$(warning : TARGET_NDK is not set!) + endif + ifeq ($(LINUXDIR),) +$(warning : LINUXDIR is not set!) + endif + GCDEFS := $(GCDEFS) -fno-short-enums + + GCFLAGS += -Dlinux -DTARGETENV_android + ifeq ($(TARGETARCH), arm_android_ndk_r6b) + GCFLAGS += -DTARGETARCH_arm_android + GCFLAGS += -I$(TARGET_NDK)/platforms/android-9/arch-arm/usr/include/ + GCFLAGS += -march=armv5te -mtune=xscale -msoft-float + GCFLAGS += -mthumb-interwork + else + ifeq ($(TARGETARCH), x86_android_ndk_r6b) + GCFLAGS += -DTARGETARCH_x86_android + GCFLAGS += -I$(TARGET_NDK)/platforms/android-9/arch-x86/usr/include/ + GCFLAGS += -march=i686 + endif + endif + GCFLAGS += -fpic -fno-exceptions + GCFLAGS += -ffunction-sections -funwind-tables + GCFLAGS += -fstack-protector -fmessage-length=0 + GCFLAGS += -I$(LINUXDIR)/include/ + else + TARGET_PREFIX = + endif + endif + endif + endif + endif + endif + + CC = $(TARGET_PREFIX)gcc + AS = $(TARGET_PREFIX)as + LD = $(TARGET_PREFIX)ld + AR = $(TARGET_PREFIX)ar + + INSTALL = install -c + + TCFLAGS = + + ifeq ($(TARGETENV), freebsd) + GLDFLAGS = -static + endif + ifeq ($(TARGETENV), linuxarm) + GLDFLAGS = -static + endif + ifeq ($(TARGETENV), linuxarm_le) +# GLDFLAGS = -static + endif + ifeq ($(TARGETENV), android) + GLDFLAGS = -static + endif + ifeq ($(TARGETENV), android_ndk_r6b) + GLDFLAGS = -Bdynamic -Wl,-dynamic-linker,/system/bin/linker + GLDFLAGS += -lm -lc -ldl + GLDFLAGS += -nostdlib + GLDFLAGS += -Wl,--gc-sections -Wl,-z,nocopyreloc + GLDFLAGS += -Wl,--no-undefined + ifeq ($(TARGETARCH), arm_android_ndk_r6b) + GLDFLAGS += -ldl + GLDFLAGS += -Wl,-T,$(TARGET_NDK)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi/lib/ldscripts/armelf_linux_eabi.x + GLDFLAGS += -Wl,-rpath-link=$(TARGET_NDK)/platforms/android-9/arch-arm + GLDFLAGS += -L$(TARGET_NDK)/platforms/android-9/arch-arm/usr/lib + GLDFLAGS += $(TARGET_NDK)/platforms/android-9/arch-arm/usr/lib/crtend_android.o + GLDFLAGS += $(TARGET_NDK)/platforms/android-9/arch-arm/usr/lib/crtbegin_dynamic.o + GLDFLAGS += $(TARGET_NDK)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a + else + ifeq ($(TARGETARCH), x86_android_ndk_r6b) + GLDFLAGS += -m32 -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now + GLDFLAGS += -Wl,-z,relro,-z,now -fPIE -pie + GLDFLAGS += -L$(TARGET_NDK)/platforms/android-9/arch-x86/usr/lib + GLDFLAGS += -Wl,-rpath-link=$(TARGET_NDK)/platforms/android-9/arch-x86 + GLDFLAGS += -lstdc++ + GLDFLAGS += $(TARGET_NDK)/platforms/android-9/arch-x86/usr/lib/crtbegin_dynamic.o + GLDFLAGS += -Wl,--whole-archive -Wl,--no-whole-archive + GLDFLAGS += $(TARGET_NDK)/toolchains/x86-4.4.3/prebuilt/linux-x86/lib/gcc/i686-android-linux/4.4.3/libgcc.a + GLDFLAGS += $(TARGET_NDK)/platforms/android-9/arch-x86/usr/lib/crtend_android.o + endif + endif + endif + + GLDLIBS = -lgcc + +endif # $(TARGETOS) == unix + +ifeq ($(TARGETOS), Windows_NT) + + # The environment for windows builds + + EXEEXT = .exe + + ifeq ($(TARGETENV), win32) + # standard win32 using MS compiler + OBJEXT = .obj + GCINCS = $(strip /I$(SRCBASE)/include $(patsubst -I%,/I%,$(WLAN_StdIncPathA)) $(patsubst -I%,/I%,$(WLAN_ComponentIncPath))) + GCDEFS = /DTARGETENV_$(TARGETENV) /DTARGETOS_$(TARGETOS) \ + /DTARGETARCH_$(TARGETARCH) /D_X86_ + ifeq ($(TARGETARCH), x86_mmx) + GCDEFS += /D_MMX_ + endif + GCOPTS = /nologo + GCFLAGS = /GM /W3 /Z7 + + CC_TARGET =-Fo$@ + LINK_TARGET =-out:$@ + + CC = cl + AS = cl + LD = cl + + TCFLAGS = + GLDFLAGS = /nologo /link /nologo /INCREMENTAL:NO + + GLDLIBS = + else + # cygwin32 based environment + OBJEXT = .o + GCINCS = $(strip -I$(SRCBASE)/include $(WLAN_StdIncPathA) $(WLAN_ComponentIncPath)) + GCDEFS = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \ + -DTARGETARCH_$(TARGETARCH) -D_X86_ + ifeq ($(TARGETARCH), x86_mmx) + GCDEFS += -D_MMX_ + endif + GCOPTS = + GCFLAGS = -g -Wall + + CC_TARGET =-o $@ + LINK_TARGET =-o $@ + + CC = gcc + AS = gcc + LD = gcc + INSTALL = install -c + + TCFLAGS = + GLDFLAGS = + + GLDLIBS = -liberty -lgcc + endif + + # Tools common to cygwin/win32 + + INSTALL = install -c + BUILD = build -ceZ + + # RELEASE_TARGET is a the directory under RELEASE_DIR where + # target dependant files go. It is composed of the OS and + # the CPU, some examples are: winnt40/i386, win98 ... + # + # NEEDSWORK: For now only NT 4.0 stuff uses it. + ifneq ($(findstring $(TARGETPLATFORM), "Wdm wdm"), ) + RELEASE_TARGET = wdm/i386 + else + RELEASE_TARGET = winnt40/i386 + endif + + # RELEASE_TOOLS_DIR is a the directory under RELEASE_DIR where + # common tools go. + # For compatability with previous installs &test scripts, old + # tools still go in "yosemite". + RELEASE_YOS_DIR = yosemite + RELEASE_TOOLS_DIR = tools + +endif # $(TARGETOS) == Windows_NT + +ifeq ($(TARGETOS), vxWorks) + WIND_REGISTRY = sol + ifndef WIND_BASE + ifeq ($(HOSTOS), unix) + WIND_BASE = /dfs/tools/vxWorks + else + WIND_BASE = $(WLAN_WINPFX)/tools/vxWorks + endif + endif + include $(WIND_BASE)/target/h/make/defs.default + + ifeq ($(HOSTENV), Windows_NT) + WIND_HOST_TYPE = x86-win32 + else + ifeq ($(HOSTENV), sun4) + WIND_HOST_TYPE = sun4-solaris2 + else + WIND_HOST_TYPE = i386-freebsd + endif + endif + + ifeq ($(TARGETENV), vxsim) + CPU = SIMSPARCSOLARIS + else + ifeq ($(TARGETENV), vx386) + CPU = i386 + else + CPU = R4650 + VXFLAGS = -DCPU_VAR=$(CPU) + endif + endif + + include $(WIND_BASE)/target/h/make/make.$(CPU)$(TOOL) + include $(WIND_BASE)/target/h/make/defs.$(WIND_HOST_TYPE) + + GCINCS = -I$(WIND_BASE)/target/h -I$(SRCBASE)/include $(WLAN_StdIncPathA) + GCDEFS = $(DEFINE_CC) -DCPU=$(CPU) -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH) + GCOPTS = -g -O2 + GCFLAGS = -Wall $(CC_ARCH_SPEC) + LDFLAGS = $(GLDFLAGS) $(LLDFLAGS) + GLDLIBS = $(LIBS) + + WIND_BIN = $(WIND_BASE)/host/$(WIND_HOST_TYPE)/bin + + AR := $(WIND_BIN)/$(AR) + AS := $(WIND_BIN)/$(AS) + BINHEX := $(WIND_BIN)/$(BINHEX) + CC := $(WIND_BIN)/$(CC) + CF := $(WIND_BIN)/$(CF) + LD := $(CC) + NM := $(WIND_BIN)/$(NM) + RANLIB := $(WIND_BIN)/$(RANLIB) + BINXSYM_NAME := $(WIND_BIN)/$(BINXSYM) + +endif # $(TARGETOS) == vxWorks + +ifeq ($(TARGETENV), nucleusarm) + + # The environment for nucleus builds + ifeq ($(BSP_BASE_DIR),) + BSP_BASE_DIR := $(SRCBASE)/../bsp + endif + + ifeq ($(NUCLEUS_INC_DIR),) + NUCLEUS_INC_DIR := $(BSP_BASE_DIR)/rtos/nucleus/inc + endif + + EXEEXT := + OBJEXT := .o + GCINCS := $(strip -I$(SRCBASE)/include $(WLAN_StdIncPathA) -I$(NUCLEUS_INC_DIR) $(WLAN_ComponentIncPath)) + GCDEFS := -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH) + GCOPTS := + + ifeq ($(OBJDIR),) + OBJDIR := $(TARGETENV)/ + endif + + # --md: This option compiles the source and writes make file dependency lines + # to a file. The output file is suitable for use by a make utility. + # -c: Compiles but does not perform the link phase. + # -O2: High optimization. + # ---memaccess -UL41: This option tells the compiler that the memory in the + # target system has slightly restricted or expanded capabilities. + # Disables unaligned mode for code that uses pre-ARMv6 unaligned + # access behavior. + # "/adsabi" is added to "--apcs /interwork/$(SWST)" so that objects created + # under ADS 1.2 can be linked with objects compiled under RVCT 2.2. + # --diag_suppress 2084,1658 = blocks the diagnostic warning "Warning: C2084W: support for --apcs /adsabi is deprecated" + # 1293: Suppress "assignment in condition" warning. + # 550: Suppress "variable set but never used" warning. + GCFLAGS := --md \ + -c \ + -O2 \ + --memaccess -UL41 \ + --apcs /adsabi/interwork/NOSWST \ + --diag_suppress 2084,1658,1293,550 \ + --li + + # --cpu 'name': This option generates code for a specific ARM processor or architecture. + ifeq ($(TARGETCPU),2153) + GCFLAGS += --cpu ARM1136J-S + else + $(error "Unknown target CPU type!") + endif + + #CPPFLAGS := -embeddedcplusplus + + CC_TARGET =-o $@ + CPP_TARGET =-o $@ + LINK_TARGET =-o $@ + + CC := tcc + CPP := tcpp + AS := armasm + LD := armlink + AR := armar -c -r --create + + INSTALL := install -c + + TCFLAGS := + + GLDFLAGS := + GLDLIBS := --ELF --symbols --debug --map --info sizes,totals --errors link.err --list link.map --verbose + + # Convert windows style directories to cygwin style. + # It should be used in situations where the host environment is cygwin, and + # the host compiler is a native Win32 app (non-cygwin). It will convert the + # Windows style directories in the dependencies list to cygwin style. This is + # necessary for the dependency files to be included by cygwin make. + ifeq ($(HOSTOS),Windows_NT) + FILTER_DEPENDS_IN_C_TO_OBJ_RULE := 1 + endif + +endif # $(TARGETENV) == nucleusarm + +ifeq ($(TARGETENV), bcmmips) + + OBJEXT = .o + GCINCS = $(strip -I$(SRCBASE)/include $(WLAN_StdIncPathA) $(WLAN_ComponentIncPath)) + GCDEFS = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \ + -DTARGETARCH_$(TARGETARCH) -D__mips__ + GCOPTS = -g -O2 + GCFLAGS = -Wall + GLDFLAGS = -Wl,-tidt.dld + + AS = bcmas + CC = bcmgcc + LD = $(CC) + NM = bcmnm + RANLIB = bcmranlib + +endif # $(TARGETENV) == bcmmips + +ifeq ($(TARGETENV), klsi) + + OBJEXT = .obj + GCINCS = $(strip -I$(SRCBASE)/include $(WLAN_StdIncPathA) $(WLAN_ComponentIncPath)) + GCDEFS = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \ + -DTARGETARCH_$(TARGETARCH) -D__klsi__ + + AS = qtasm + GASFLAGS = -m20 + CC = qtcc + TCFLAGS = -w asm=$(GASFLAGS) +c -Vcdv -w cc=+reginfo + +endif # $(TARGETENV) == klsi + +CFLAGS = $(LCINCS) $(GCINCS) $(GCDEFS) $(GCOPTS) $(GCFLAGS) $(TCFLAGS) $(HCFLAGS) \ +$(LCDEFS) $(LCOPTS) $(LCFLAGS) $(CENV) + +ASFLAGS = $(GASFLAGS) $(LASFLAGS) $(ASENV) +LDFLAGS = $(GLDFLAGS) $(LLDFLAGS) $(LDENV) +LDLIBS = $(LLDLIBS) $(GLDLIBS) + +# dependency files including the .d file itself. +# note the example in GNU documentation seems to have a bug: +# two backslashes where one is correct. +%.d: %.c +ifeq ($(findstring s, $(MAKEFLAGS) ),) + @ echo making $@ +endif + @ $(SHELL) -ec '$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< \ + | sed '\''s/$*\.o[ :]*/$@ &/g'\'' >$@' + +ifeq ($(TARGETENV), win32) + +# win32 needs different command line args + +%.s: %.c + $(CC) /FAs $(CFLAGS) $(CPPFLAGS) /Fa$@ /c $< + +%.i: %.c + $(CC) /E $(CFLAGS) $(CPPFLAGS) $< > $@ + +else # !win32 + +%.s: %.c + $(CC) -S $(CFLAGS) $(CPPFLAGS) -o $@ $< + +%.i: %.c + $(CC) -o $@ -E -dD $(CFLAGS) $(CPPFLAGS) $< + +endif # win32 + +ifeq ($(TARGETENV), klsi) + +%$(OBJEXT): %.c + $(CC) $(CFLAGS) $*.c + +%$(OBJEXT): %.asm + $(AS) $(ASFLAGS) $*.asm + +%.asm: %.c + $(CC) $(CFLAGS) -asm $*.c + +%.i: %.c + $(CC) $(CFLAGS) -cc -peep -asm $*.c + mv $*.pp $*.i + +else + + +# This command sequence will: +# - Convert back-slashes to foward-slashes +# - Convert long filenames to 8.3 format (e.g. Program Files --> PROGRA~1) +# - Convert windows-style drive letters to cygwin style. +# +# It should be used in situations where the host environment is cygwin, and +# the host compiler is a native Win32 app (non-cygwin). It will convert the +# Windows style directories in the dependencies list to cygwin style. This is +# necessary for the dependency files to be included by cygwin make. +define FILTER_DEPENDS + sed -e 's/\\/\//g' \ + -e 's/Program Files/PROGRA~1/g' \ + -e 's/\([A-Za-z]\):\//\/cygdrive\/\1\//' < $(notdir $(@:.o=.d)) > $(@:.o=.d) && \ + rm -f $(notdir $(@:.o=.d)) +endef + + +$(OBJDIR)%$(OBJEXT): %.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(CC_TARGET) $< +ifeq ($(FILTER_DEPENDS_IN_C_TO_OBJ_RULE),1) + ${FILTER_DEPENDS} +endif + +$(OBJDIR)%$(OBJEXT): %.cpp + $(CPP) -c $(CFLAGS) $(CPPFLAGS) $(CPP_TARGET) $< +ifeq ($(FILTER_DEPENDS_IN_C_TO_OBJ_RULE),1) + ${FILTER_DEPENDS} +endif + + +endif # klsi + +%.h: %.x + rpcgen -C -h $< > $@ + +%_xdr.c: %.x + @ (if [ ! -f `basename $<` ] ; then ln -s $< . ; fi; true) + rpcgen -C -c -i 0 `basename $<` > $@ + +# Makefile debugging rule +env: + printenv + +# if the user mistakenly specified RELEASE_DIR in unix-style notation, +# convert it to Win32 notation for them. +# +# RELEASE_DIR is assumed to be in windows-style notation if it has both +# backslashes ('\') and colons (':'). +# + +ifneq ("$(subst \,,$(RELEASE_DIR))", "$(RELEASE_DIR)") +ifneq ("$(subst :,,$(RELEASE_DIR))", "$(RELEASE_DIR)") +RELEASE_DIR := $(subst :,,$(RELEASE_DIR)) +RELEASE_DIR := $(subst \,/,$(RELEASE_DIR)) +RELEASE_DIR := //$(RELEASE_DIR) +endif +endif + +# all release rules depend on a valid RELEASE_DIR +release: check_release_dir +check_release_dir: + @if [ "x$(RELEASE_DIR)" = "x" ]; then \ + echo "RELEASE_DIR is not set!"; \ + exit 1; \ + fi; + +include ${SRCBASE}/branding.inc
diff --git a/src/Makerules.env b/src/Makerules.env new file mode 100644 index 0000000..a50f101 --- /dev/null +++ b/src/Makerules.env
@@ -0,0 +1,139 @@ +#******************************************************************************* +# $Id: Makerules.env 389557 2013-03-07 02:50:19Z $ +# Top-level Makerules for defining environment variables +# can be included by anyone doing software at Epigram +#******************************************************************************* + +# HOSTOS is either unix or Windows_NT. +# HOSTENV differentiates HOSTOS and is either freebsd, sun4, or Windows_NT. +# This refers to the *BUILD* environment. All environments use "GNU C" +# except Windows_NT which may use "GNU C" or "Microsoft C". + +ifndef HOSTENV + # Figure what type of host we are in. + UNAME = $(shell uname) + + ifneq ($(findstring "$(UNAME)", "FreeBSD" "NetBSD"), ) + HOSTENV = freebsd + HOSTOS = unix + else + ifneq ($(findstring "$(UNAME)", "sun4" "SunOS"), ) + HOSTENV = sun4 + HOSTOS = unix + else + ifeq ($(UNAME), Linux) + HOSTENV = linux + HOSTOS = unix + else + ifneq ($(findstring CYGWIN,$(UNAME)),) + HOSTENV = Windows_NT + HOSTOS = Windows_NT + else + ifeq ($(UNAME), Darwin) + HOSTENV = macos + HOSTOS = unix + else + HOSTENV = unknown + HOSTOS = unknown + endif + endif + endif + endif + endif +endif +# In case we just defined them, make sure they are known +export HOSTENV +export HOSTOS + +# TARGETENV is one of freebsd, sun4, linux, linuxarm, android, android_ndk_r6b, linuxmips, linuxmips_be, cygwin32, win32, or macos +# TARGETENV defaults to HOSTENV unless HOSTENV is Windows_NT, in +# which case it defaults to win32. + +ifndef TARGETENV + ifeq ($(HOSTENV), Windows_NT) + TARGETENV = win32 + else + TARGETENV = $(HOSTENV) + endif +endif +export TARGETENV + +# TARGETOS defaults to HOSTOS in most cases +ifneq ($(findstring "$(TARGETENV)", "freebsd" "linux" "linuxarm" "linuxarm_le" "android" "android_ndk_r6b" "linuxmips" "linuxmips_be" "sun4" "cygwin32" "win32" "macos"), ) + TARGETOS = $(HOSTOS) +endif +ifeq ($(TARGETENV), bcmmips) + TARGETOS = bcmmips +endif +ifeq ($(TARGETENV), klsi) + TARGETOS = klsi +endif +ifeq ($(TARGETENV), nucleusarm) + TARGETOS = nucleus +endif +ifndef TARGETOS + TARGETOS = unknown +endif +export TARGETOS + +# TARGETARCH is the target processor architecture +# Currently valid values are: x86, x86_mmx, sparc, unknown, or a list of any +# of the valid values. +# For the x86* family, a generic x86 is assuemd if not otherwise specified +# Order is important since "linux" matches both linuxmips and linux. +ifndef TARGETARCH + ifneq ($(findstring "$(TARGETENV)", "android"), ) + TARGETARCH = arm_android + endif + + ifneq ($(findstring "$(TARGETENV)", "android_ndk_r6b"), ) + TARGETARCH = arm_android_ndk_r6b + endif + + ifneq ($(findstring "$(TARGETENV)", "linuxarm_le"), ) + TARGETARCH = arm_le + endif + ifneq ($(findstring "$(TARGETENV)", "linuxarm nucleusarm"), ) + TARGETARCH = arm + endif + ifneq ($(findstring "$(TARGETENV)", "bcmmips" "linuxmips" "linuxmips_be"), ) + TARGETARCH = mips + endif + ifneq ($(findstring "$(TARGETENV)", "sun4"), ) + TARGETARCH = sparc + endif + ifneq ($(findstring "$(TARGETENV)", "freebsd" "linux" "cygwin32" "win32"), ) + TARGETCPU = $(shell uname -m) + ifneq ($(findstring "$(TARGETCPU)", "sparc" "sparc64"), ) + TARGETARCH = $(TARGETCPU) + else + TARGETARCH = x86_mmx + endif + endif + ifeq ($(TARGETENV), macos) + TARGETCPU = $(shell uname -p) + ifneq ($(findstring "$(TARGETCPU)", "powerpc"), ) + TARGETARCH = PPC + else + TARGETARCH = x86 + endif + endif + ifeq ($(TARGETENV), klsi) + TARGETARCH = klsi + endif + ifndef TARGETARCH + TARGETARCH = unknown + endif +endif +export TARGETARCH + +# TARGET_TYPE is either "all" or one or more of: float64, float32, int16 +# default is int16. "all" will get expanded into a list of all possible types +ifndef TARGET_TYPE + TARGET_TYPE = int16 +endif + +ifeq ($(TARGET_TYPE), all) + TARGET_TYPE = int16 float32 float64 +endif +export TARGET_TYPE
diff --git a/src/branding.inc b/src/branding.inc new file mode 100644 index 0000000..88d6d05 --- /dev/null +++ b/src/branding.inc
@@ -0,0 +1,5 @@ +# $ Copyright Open Broadcom Corporation $ +# +BRAND= + +export RELAY_FILE_BASE=bcm42rly
diff --git a/src/common/include/devctrl_if/wlioctl_defs.h b/src/common/include/devctrl_if/wlioctl_defs.h new file mode 100644 index 0000000..d75ac18 --- /dev/null +++ b/src/common/include/devctrl_if/wlioctl_defs.h
@@ -0,0 +1,2032 @@ +/* + * Custom OID/ioctl definitions for + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: wlioctl_defs.h 403826 2013-05-22 16:40:55Z $ + */ + + +#ifndef wlioctl_defs_h +#define wlioctl_defs_h + + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + + + +/* All builds use the new 11ac ratespec/chanspec */ +#undef D11AC_IOTYPES +#define D11AC_IOTYPES + +/* WL_RSPEC defines for rate information */ +#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ +#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ +#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ +#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ +#define WL_RSPEC_TXEXP_MASK 0x00000300 +#define WL_RSPEC_TXEXP_SHIFT 8 +#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ +#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ +#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ +#define WL_RSPEC_TXBF 0x00200000 /* bit indicates TXBF mode */ +#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ +#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ +#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ +#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ +#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */ + +/* WL_RSPEC_ENCODING field defs */ +#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ +#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ +#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ + +/* WL_RSPEC_BW field defs */ +#define WL_RSPEC_BW_UNSPECIFIED 0 +#define WL_RSPEC_BW_20MHZ 0x00010000 +#define WL_RSPEC_BW_40MHZ 0x00020000 +#define WL_RSPEC_BW_80MHZ 0x00030000 +#define WL_RSPEC_BW_160MHZ 0x00040000 + +/* Legacy defines for the nrate iovar */ +#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ +#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ +#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ +#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ +#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ +#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ +#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ +#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ + +#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ +#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ +#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ +#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ + +#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ + +#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ +#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ + +#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ +#define IBSS_HI 25 /* Hi in-bss congestion percentage */ +#define OBSS_MED 12 +#define OBSS_HI 25 +#define INTERFER_MED 5 +#define INTERFER_HI 10 + +#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ +#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ +#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ +#define CCA_FLAGS_PREFER_1_6_11 0x10 +#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ + +#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ +#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ +#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ +#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ +#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ + +#define WL_STA_AID(a) ((a) &~ 0xc000) + +/* Flags for sta_info_t indicating properties of STA */ +#define WL_STA_BRCM 0x00000001 /* Running a Broadcom driver */ +#define WL_STA_WME 0x00000002 /* WMM association */ +#define WL_STA_NONERP 0x00000004 /* No ERP */ +#define WL_STA_AUTHE 0x00000008 /* Authenticated */ +#define WL_STA_ASSOC 0x00000010 /* Associated */ +#define WL_STA_AUTHO 0x00000020 /* Authorized */ +#define WL_STA_WDS 0x00000040 /* Wireless Distribution System */ +#define WL_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing properly */ +#define WL_STA_PS 0x00000100 /* STA is in power save mode from AP's viewpoint */ +#define WL_STA_APSD_BE 0x00000200 /* APSD delv/trigger for AC_BE is default enabled */ +#define WL_STA_APSD_BK 0x00000400 /* APSD delv/trigger for AC_BK is default enabled */ +#define WL_STA_APSD_VI 0x00000800 /* APSD delv/trigger for AC_VI is default enabled */ +#define WL_STA_APSD_VO 0x00001000 /* APSD delv/trigger for AC_VO is default enabled */ +#define WL_STA_N_CAP 0x00002000 /* STA 802.11n capable */ +#define WL_STA_SCBSTATS 0x00004000 /* Per STA debug stats */ +#define WL_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */ +#define WL_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */ +#define WL_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */ +#define WL_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */ +#define WL_STA_RIFS_CAP 0x00080000 /* rifs enabled */ +#define WL_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */ +#define WL_STA_WPS 0x00200000 /* WPS state */ + +#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ + +/* STA HT cap fields */ +#define WL_STA_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ +#define WL_STA_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ +#define WL_STA_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ +#define WL_STA_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ +#define WL_STA_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ +#define WL_STA_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ +#define WL_STA_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ +#define WL_STA_CAP_GF 0x0010 /* Greenfield preamble support */ +#define WL_STA_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ +#define WL_STA_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ +#define WL_STA_CAP_TX_STBC 0x0080 /* Tx STBC support */ +#define WL_STA_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ +#define WL_STA_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ +#define WL_STA_CAP_DELAYED_BA 0x0400 /* delayed BA support */ +#define WL_STA_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ +#define WL_STA_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ +#define WL_STA_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ +#define WL_STA_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ +#define WL_STA_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ + +#define WL_STA_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ +#define WL_STA_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ +#define WL_STA_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ +#define WL_STA_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ + +/* scb vht flags */ +#define WL_STA_VHT_LDPCCAP 0x0001 +#define WL_STA_SGI80 0x0002 +#define WL_STA_SGI160 0x0004 +#define WL_STA_VHT_TX_STBCCAP 0x0008 +#define WL_STA_VHT_RX_STBCCAP 0x0010 +#define WL_STA_SU_BEAMFORMER 0x0020 +#define WL_STA_SU_BEAMFORMEE 0x0040 +#define WL_STA_MU_BEAMFORMER 0x0080 +#define WL_STA_MU_BEAMFORMEE 0x0100 +#define WL_STA_VHT_TXOP_PS 0x0200 +#define WL_STA_HTC_VHT_CAP 0x0400 + +/* Values for TX Filter override mode */ +#define WLC_TXFILTER_OVERRIDE_DISABLED 0 +#define WLC_TXFILTER_OVERRIDE_ENABLED 1 + +#define WL_IOCTL_ACTION_GET 0x0 +#define WL_IOCTL_ACTION_SET 0x1 +#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e +#define WL_IOCTL_ACTION_OVL_RSV 0x20 +#define WL_IOCTL_ACTION_OVL 0x40 +#define WL_IOCTL_ACTION_MASK 0x7e +#define WL_IOCTL_ACTION_OVL_SHIFT 1 + +#define WL_BSSTYPE_INFRA 1 +#define WL_BSSTYPE_INDEP 0 +#define WL_BSSTYPE_ANY 2 + +/* Bitmask for scan_type */ +#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ +#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ +#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ +#define WL_SCANFLAGS_OFFCHAN 0x08 /* allow scanning/reporting off-channel APs */ +#define WL_SCANFLAGS_HOTSPOT 0x10 /* automatic ANQP to hotspot APs */ + +/* wl_iscan_results status values */ +#define WL_SCAN_RESULTS_SUCCESS 0 +#define WL_SCAN_RESULTS_PARTIAL 1 +#define WL_SCAN_RESULTS_PENDING 2 +#define WL_SCAN_RESULTS_ABORTED 3 +#define WL_SCAN_RESULTS_NO_MEM 4 + +#define SCANOL_ENABLED (1 << 0) +#define SCANOL_BCAST_SSID (1 << 1) +#define SCANOL_NOTIFY_BCAST_SSID (1 << 2) +#define SCANOL_RESULTS_PER_CYCLE (1 << 3) + +/* scan times in milliseconds */ +#define SCANOL_HOME_TIME 45 /* for home channel processing */ +#define SCANOL_ASSOC_TIME 20 /* dwell on a channel while associated */ +#define SCANOL_UNASSOC_TIME 40 /* dwell on a channel while unassociated */ +#define SCANOL_PASSIVE_TIME 110 /* listen on a channelfor passive scan */ +#define SCANOL_AWAY_LIMIT 100 /* max time to be away from home channel */ +#define SCANOL_IDLE_REST_TIME 40 +#define SCANOL_IDLE_REST_MULTIPLIER 0 +#define SCANOL_ACTIVE_REST_TIME 20 +#define SCANOL_ACTIVE_REST_MULTIPLIER 0 +#define SCANOL_CYCLE_IDLE_REST_TIME 300000 /* Idle Rest Time between Scan Cycle (msec) */ +#define SCANOL_CYCLE_IDLE_REST_MULTIPLIER 0 /* Idle Rest Time Multiplier */ +#define SCANOL_CYCLE_ACTIVE_REST_TIME 200 +#define SCANOL_CYCLE_ACTIVE_REST_MULTIPLIER 0 +#define SCANOL_MAX_REST_TIME 3600000 /* max rest time between scan cycle (msec) */ +#define SCANOL_CYCLE_DEFAULT 0 /* default for Max Scan Cycle, 0 = forever */ +#define SCANOL_CYCLE_MAX 864000 /* Max Scan Cycle */ + /* 10 sec/scan cycle => 100 days */ +#define SCANOL_NPROBES 2 /* for Active scan; send n probes on each channel */ +#define SCANOL_NPROBES_MAX 5 /* for Active scan; send n probes on each channel */ +#define SCANOL_SCAN_START_DLY 10 /* delay start of offload scan (sec) */ +#define SCANOL_SCAN_START_DLY_MAX 240 /* delay start of offload scan (sec) */ +#define SCANOL_MULTIPLIER_MAX 10 /* Max Multiplier */ +#define SCANOL_UNASSOC_TIME_MAX 100 /* max dwell on a channel while unassociated */ +#define SCANOL_PASSIVE_TIME_MAX 500 /* max listen on a channel for passive scan */ +#define SCANOL_SSID_MAX 16 /* max supported preferred SSID */ + +/* masks for channel and ssid count */ +#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff +#define WL_SCAN_PARAMS_NSSID_SHIFT 16 + +#define WL_SCAN_ACTION_START 1 +#define WL_SCAN_ACTION_CONTINUE 2 +#define WL_SCAN_ACTION_ABORT 3 + +#if defined(SIMPLE_ISCAN) +#define ISCAN_RETRY_CNT 5 +#define ISCAN_STATE_IDLE 0 +#define ISCAN_STATE_SCANING 1 +#define ISCAN_STATE_PENDING 2 +#endif /* SIMPLE_ISCAN */ + +#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ +#define ANTENNA_NUM_2 2 +#define ANTENNA_NUM_3 3 +#define ANTENNA_NUM_4 4 + +#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ +#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ +#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */ +#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */ +#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */ +#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */ + +/* interference source detection and identification mode */ +#define ITFR_MODE_DISABLE 0 /* disable feature */ +#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ +#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ + +/* bit definitions for flags in interference source report */ +#define ITFR_INTERFERENCED 1 /* interference detected */ +#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ +#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ + +#define WL_NUM_RPI_BINS 8 +#define WL_RM_TYPE_BASIC 1 +#define WL_RM_TYPE_CCA 2 +#define WL_RM_TYPE_RPI 3 + +#define WL_RM_FLAG_PARALLEL (1<<0) + +#define WL_RM_FLAG_LATE (1<<1) +#define WL_RM_FLAG_INCAPABLE (1<<2) +#define WL_RM_FLAG_REFUSED (1<<3) + +/* flags */ +#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ + +#define WLC_CIS_DEFAULT 0 /* built-in default */ +#define WLC_CIS_SROM 1 /* source is sprom */ +#define WLC_CIS_OTP 2 /* source is otp */ + +/* PCL - Power Control Loop */ +/* current gain setting is replaced by user input */ +#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ +#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ +/* current gain setting is maintained */ +#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ + +#define PLC_CMD_FAILOVER 1 +#define PLC_CMD_MAC_COST 2 +#define PLC_CMD_LINK_COST 3 +#define PLC_CMD_NODE_LIST 4 + +#define NODE_TYPE_UNKNOWN 0 /* Unknown link */ +#define NODE_TYPE_WIFI_ONLY 1 /* Pure Wireless STA node */ +#define NODE_TYPE_PLC_ONLY 2 /* Pure PLC only node */ +#define NODE_TYPE_WIFI_PLC 3 /* WiFi PLC capable node */ + +/* defines used by poweridx iovar - it controls power in a-band */ +/* current gain setting is maintained */ +#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ +#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ +#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ +#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ +/* value >= 0 causes + * - input to be set to that value + * - PCL to be off + */ + +#define BCM_MAC_STATUS_INDICATION (0x40010200L) + +/* Values for TX Filter override mode */ +#define WLC_TXFILTER_OVERRIDE_DISABLED 0 +#define WLC_TXFILTER_OVERRIDE_ENABLED 1 + +/* magic pattern used for mismatch driver and wl */ +#define WL_TXFIFO_SZ_MAGIC 0xa5a5 + +/* check this magic number */ +#define WLC_IOCTL_MAGIC 0x14e46c77 + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* bss_info_cap_t flags */ +#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ +#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ +#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info received on channel (vs offchannel) */ +#define WL_BSS_FLAGS_HS20 0x08 /* hotspot 2.0 capable */ +#define WL_BSS_FLAGS_RSSI_INVALID 0x10 /* BSS contains invalid RSSI */ +#define WL_BSS_FLAGS_RSSI_INACCURATE 0x20 /* BSS contains inaccurate RSSI */ + +/* bssinfo flag for nbss_cap */ +#define VHT_BI_SGI_80MHZ 0x00000100 +#define VHT_BI_80MHZ 0x00000200 +#define VHT_BI_160MHZ 0x00000400 +#define VHT_BI_8080MHZ 0x00000800 + +/* reference to wl_ioctl_t struct used by usermode driver */ +#define ioctl_subtype set /* subtype param */ +#define ioctl_pid used /* pid param */ +#define ioctl_status needed /* status param */ + + +/* Enumerate crypto algorithms */ +#define CRYPTO_ALGO_OFF 0 +#define CRYPTO_ALGO_WEP1 1 +#define CRYPTO_ALGO_TKIP 2 +#define CRYPTO_ALGO_WEP128 3 +#define CRYPTO_ALGO_AES_CCM 4 +#define CRYPTO_ALGO_AES_OCB_MSDU 5 +#define CRYPTO_ALGO_AES_OCB_MPDU 6 +#if !defined(BCMCCX) && !defined(BCMEXTCCX) +#define CRYPTO_ALGO_NALG 7 +#else +#define CRYPTO_ALGO_CKIP 7 +#define CRYPTO_ALGO_CKIP_MMH 8 +#define CRYPTO_ALGO_WEP_MMH 9 +#define CRYPTO_ALGO_NALG 10 +#endif /* !BCMCCX && !BCMEXTCCX */ + +#define CRYPTO_ALGO_SMS4 11 +#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ +#define CRYPTO_ALGO_BIP 13 /* 802.11w BIP (aes cmac) */ + +#define CRYPTO_ALGO_AES_GCM 14 /* 128 bit GCM */ +#define CRYPTO_ALGO_AES_CCM256 15 /* 256 bit CCM */ +#define CRYPTO_ALGO_AES_GCM256 16 /* 256 bit GCM */ +#define CRYPTO_ALGO_BIP_CMAC256 17 /* 256 bit BIP CMAC */ +#define CRYPTO_ALGO_BIP_GMAC 18 /* 128 bit BIP GMAC */ +#define CRYPTO_ALGO_BIP_GMAC256 19 /* 256 bit BIP GMAC */ + +#define CRYPTO_ALGO_NONE CRYPTO_ALGO_OFF + +#define WSEC_GEN_MIC_ERROR 0x0001 +#define WSEC_GEN_REPLAY 0x0002 +#define WSEC_GEN_ICV_ERROR 0x0004 +#define WSEC_GEN_MFP_ACT_ERROR 0x0008 +#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 +#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 + +#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ +#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ +#if defined(BCMCCX) || defined(BCMEXTCCX) +#define WL_CKIP_KP (1 << 4) /* CMIC */ +#define WL_CKIP_MMH (1 << 5) /* CKIP */ +#else +#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ +#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ +#endif /* BCMCCX || BCMEXTCCX */ +#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ + +/* wireless security bitvec */ +#define WEP_ENABLED 0x0001 +#define TKIP_ENABLED 0x0002 +#define AES_ENABLED 0x0004 +#define WSEC_SWFLAG 0x0008 +#ifdef BCMCCX +#define CKIP_KP_ENABLED 0x0010 +#define CKIP_MIC_ENABLED 0x0020 +#endif /* BCMCCX */ +#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ +#ifdef BCMWAPI_WPI +#define SMS4_ENABLED 0x0100 +#endif /* BCMWAPI_WPI */ + +/* wsec macros for operating on the above definitions */ +#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) +#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) +#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) + +#ifdef BCMCCX +#define WSEC_CKIP_KP_ENABLED(wsec) ((wsec) & CKIP_KP_ENABLED) +#define WSEC_CKIP_MIC_ENABLED(wsec) ((wsec) & CKIP_MIC_ENABLED) +#define WSEC_CKIP_ENABLED(wsec) ((wsec) & (CKIP_KP_ENABLED|CKIP_MIC_ENABLED)) + +#ifdef BCMWAPI_WPI +#define WSEC_ENABLED(wsec) \ + ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | \ + CKIP_MIC_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define WSEC_ENABLED(wsec) \ + ((wsec) & \ + (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | CKIP_MIC_ENABLED)) +#endif /* BCMWAPI_WPI */ +#else /* defined BCMCCX */ +#ifdef BCMWAPI_WPI +#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) +#endif /* BCMWAPI_WPI */ +#endif /* BCMCCX */ +#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) +#ifdef BCMWAPI_WAI +#define WSEC_SMS4_ENABLED(wsec) ((wsec) & SMS4_ENABLED) +#endif /* BCMWAPI_WAI */ + +#define MFP_CAPABLE 0x0200 +#define MFP_REQUIRED 0x0400 +#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ + +/* WPA authentication mode bitvec */ +#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */ +#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ +#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ +#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ +#if defined(BCMCCX) || defined(BCMEXTCCX) +#define WPA_AUTH_CCKM 0x0008 /* CCKM */ +#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ +#endif /* BCMCCX || BCMEXTCCX */ +/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ +#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ +#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ +#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ +#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ +#if defined(BCMWAPI_WAI) || defined(BCMWAPI_WPI) +#define WPA_AUTH_WAPI 0x0400 +#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */ +#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */ +#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */ +#endif /* BCMWAPI_WAI || BCMWAPI_WPI */ +#define WPA2_AUTH_MFP 0x1000 /* MFP (11w) in contrast to CCX */ +#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ +#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ +#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ + +/* pmkid */ +#define MAXPMKID 16 + +#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ +#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ +#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ +#if defined(LCNCONF) || defined(LCN40CONF) +#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */ +#else +#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ +#endif +#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 + +/* common ioctl definitions */ +#define WLC_GET_MAGIC 0 +#define WLC_GET_VERSION 1 +#define WLC_UP 2 +#define WLC_DOWN 3 +#define WLC_GET_LOOP 4 +#define WLC_SET_LOOP 5 +#define WLC_DUMP 6 +#define WLC_GET_MSGLEVEL 7 +#define WLC_SET_MSGLEVEL 8 +#define WLC_GET_PROMISC 9 +#define WLC_SET_PROMISC 10 +/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ +#define WLC_GET_RATE 12 +#define WLC_GET_MAX_RATE 13 +#define WLC_GET_INSTANCE 14 +/* #define WLC_GET_FRAG 15 */ /* no longer supported */ +/* #define WLC_SET_FRAG 16 */ /* no longer supported */ +/* #define WLC_GET_RTS 17 */ /* no longer supported */ +/* #define WLC_SET_RTS 18 */ /* no longer supported */ +#define WLC_GET_INFRA 19 +#define WLC_SET_INFRA 20 +#define WLC_GET_AUTH 21 +#define WLC_SET_AUTH 22 +#define WLC_GET_BSSID 23 +#define WLC_SET_BSSID 24 +#define WLC_GET_SSID 25 +#define WLC_SET_SSID 26 +#define WLC_RESTART 27 +#define WLC_TERMINATED 28 +/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ +#define WLC_GET_CHANNEL 29 +#define WLC_SET_CHANNEL 30 +#define WLC_GET_SRL 31 +#define WLC_SET_SRL 32 +#define WLC_GET_LRL 33 +#define WLC_SET_LRL 34 +#define WLC_GET_PLCPHDR 35 +#define WLC_SET_PLCPHDR 36 +#define WLC_GET_RADIO 37 +#define WLC_SET_RADIO 38 +#define WLC_GET_PHYTYPE 39 +#define WLC_DUMP_RATE 40 +#define WLC_SET_RATE_PARAMS 41 +#define WLC_GET_FIXRATE 42 +#define WLC_SET_FIXRATE 43 +/* #define WLC_GET_WEP 42 */ /* no longer supported */ +/* #define WLC_SET_WEP 43 */ /* no longer supported */ +#define WLC_GET_KEY 44 +#define WLC_SET_KEY 45 +#define WLC_GET_REGULATORY 46 +#define WLC_SET_REGULATORY 47 +#define WLC_GET_PASSIVE_SCAN 48 +#define WLC_SET_PASSIVE_SCAN 49 +#define WLC_SCAN 50 +#define WLC_SCAN_RESULTS 51 +#define WLC_DISASSOC 52 +#define WLC_REASSOC 53 +#define WLC_GET_ROAM_TRIGGER 54 +#define WLC_SET_ROAM_TRIGGER 55 +#define WLC_GET_ROAM_DELTA 56 +#define WLC_SET_ROAM_DELTA 57 +#define WLC_GET_ROAM_SCAN_PERIOD 58 +#define WLC_SET_ROAM_SCAN_PERIOD 59 +#define WLC_EVM 60 /* diag */ +#define WLC_GET_TXANT 61 +#define WLC_SET_TXANT 62 +#define WLC_GET_ANTDIV 63 +#define WLC_SET_ANTDIV 64 +/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ +/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ +#define WLC_GET_CLOSED 67 +#define WLC_SET_CLOSED 68 +#define WLC_GET_MACLIST 69 +#define WLC_SET_MACLIST 70 +#define WLC_GET_RATESET 71 +#define WLC_SET_RATESET 72 +/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ +#define WLC_LONGTRAIN 74 +#define WLC_GET_BCNPRD 75 +#define WLC_SET_BCNPRD 76 +#define WLC_GET_DTIMPRD 77 +#define WLC_SET_DTIMPRD 78 +#define WLC_GET_SROM 79 +#define WLC_SET_SROM 80 +#define WLC_GET_WEP_RESTRICT 81 +#define WLC_SET_WEP_RESTRICT 82 +#define WLC_GET_COUNTRY 83 +#define WLC_SET_COUNTRY 84 +#define WLC_GET_PM 85 +#define WLC_SET_PM 86 +#define WLC_GET_WAKE 87 +#define WLC_SET_WAKE 88 +/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ +#define WLC_GET_FORCELINK 90 /* ndis only */ +#define WLC_SET_FORCELINK 91 /* ndis only */ +#define WLC_FREQ_ACCURACY 92 /* diag */ +#define WLC_CARRIER_SUPPRESS 93 /* diag */ +#define WLC_GET_PHYREG 94 +#define WLC_SET_PHYREG 95 +#define WLC_GET_RADIOREG 96 +#define WLC_SET_RADIOREG 97 +#define WLC_GET_REVINFO 98 +#define WLC_GET_UCANTDIV 99 +#define WLC_SET_UCANTDIV 100 +#define WLC_R_REG 101 +#define WLC_W_REG 102 +/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ +/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ +#define WLC_GET_MACMODE 105 +#define WLC_SET_MACMODE 106 +#define WLC_GET_MONITOR 107 +#define WLC_SET_MONITOR 108 +#define WLC_GET_GMODE 109 +#define WLC_SET_GMODE 110 +#define WLC_GET_LEGACY_ERP 111 +#define WLC_SET_LEGACY_ERP 112 +#define WLC_GET_RX_ANT 113 +#define WLC_GET_CURR_RATESET 114 /* current rateset */ +#define WLC_GET_SCANSUPPRESS 115 +#define WLC_SET_SCANSUPPRESS 116 +#define WLC_GET_AP 117 +#define WLC_SET_AP 118 +#define WLC_GET_EAP_RESTRICT 119 +#define WLC_SET_EAP_RESTRICT 120 +#define WLC_SCB_AUTHORIZE 121 +#define WLC_SCB_DEAUTHORIZE 122 +#define WLC_GET_WDSLIST 123 +#define WLC_SET_WDSLIST 124 +#define WLC_GET_ATIM 125 +#define WLC_SET_ATIM 126 +#define WLC_GET_RSSI 127 +#define WLC_GET_PHYANTDIV 128 +#define WLC_SET_PHYANTDIV 129 +#define WLC_AP_RX_ONLY 130 +#define WLC_GET_TX_PATH_PWR 131 +#define WLC_SET_TX_PATH_PWR 132 +#define WLC_GET_WSEC 133 +#define WLC_SET_WSEC 134 +#define WLC_GET_PHY_NOISE 135 +#define WLC_GET_BSS_INFO 136 +#define WLC_GET_PKTCNTS 137 +#define WLC_GET_LAZYWDS 138 +#define WLC_SET_LAZYWDS 139 +#define WLC_GET_BANDLIST 140 + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +#define WLC_GET_BAND 141 +#define WLC_SET_BAND 142 +#define WLC_SCB_DEAUTHENTICATE 143 +#define WLC_GET_SHORTSLOT 144 +#define WLC_GET_SHORTSLOT_OVERRIDE 145 +#define WLC_SET_SHORTSLOT_OVERRIDE 146 +#define WLC_GET_SHORTSLOT_RESTRICT 147 +#define WLC_SET_SHORTSLOT_RESTRICT 148 +#define WLC_GET_GMODE_PROTECTION 149 +#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 +#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 +#define WLC_UPGRADE 152 +/* #define WLC_GET_MRATE 153 */ /* no longer supported */ +/* #define WLC_SET_MRATE 154 */ /* no longer supported */ +#define WLC_GET_IGNORE_BCNS 155 +#define WLC_SET_IGNORE_BCNS 156 +#define WLC_GET_SCB_TIMEOUT 157 +#define WLC_SET_SCB_TIMEOUT 158 +#define WLC_GET_ASSOCLIST 159 +#define WLC_GET_CLK 160 +#define WLC_SET_CLK 161 +#define WLC_GET_UP 162 +#define WLC_OUT 163 +#define WLC_GET_WPA_AUTH 164 +#define WLC_SET_WPA_AUTH 165 +#define WLC_GET_UCFLAGS 166 +#define WLC_SET_UCFLAGS 167 +#define WLC_GET_PWRIDX 168 +#define WLC_SET_PWRIDX 169 +#define WLC_GET_TSSI 170 +#define WLC_GET_SUP_RATESET_OVERRIDE 171 +#define WLC_SET_SUP_RATESET_OVERRIDE 172 +/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ +/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ +/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ +/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ +/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ +#define WLC_GET_PROTECTION_CONTROL 178 +#define WLC_SET_PROTECTION_CONTROL 179 +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ +#define WLC_GET_PHYLIST 180 +#ifndef LINUX_POSTMOGRIFY_REMOVAL +#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ +#define WLC_DECRYPT_STATUS 182 /* ndis only */ +#define WLC_GET_KEY_SEQ 183 +#define WLC_GET_SCAN_CHANNEL_TIME 184 +#define WLC_SET_SCAN_CHANNEL_TIME 185 +#define WLC_GET_SCAN_UNASSOC_TIME 186 +#define WLC_SET_SCAN_UNASSOC_TIME 187 +#define WLC_GET_SCAN_HOME_TIME 188 +#define WLC_SET_SCAN_HOME_TIME 189 +#define WLC_GET_SCAN_NPROBES 190 +#define WLC_SET_SCAN_NPROBES 191 +#define WLC_GET_PRB_RESP_TIMEOUT 192 +#define WLC_SET_PRB_RESP_TIMEOUT 193 +#define WLC_GET_ATTEN 194 +#define WLC_SET_ATTEN 195 +#define WLC_GET_SHMEM 196 /* diag */ +#define WLC_SET_SHMEM 197 /* diag */ +/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ +/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ +#define WLC_SET_WSEC_TEST 200 +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ +#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 +#ifndef LINUX_POSTMOGRIFY_REMOVAL +#define WLC_TKIP_COUNTERMEASURES 202 +#define WLC_GET_PIOMODE 203 +#define WLC_SET_PIOMODE 204 +#define WLC_SET_ASSOC_PREFER 205 +#define WLC_GET_ASSOC_PREFER 206 +#define WLC_SET_ROAM_PREFER 207 +#define WLC_GET_ROAM_PREFER 208 +#define WLC_SET_LED 209 +#define WLC_GET_LED 210 +#define WLC_GET_INTERFERENCE_MODE 211 +#define WLC_SET_INTERFERENCE_MODE 212 +#define WLC_GET_CHANNEL_QA 213 +#define WLC_START_CHANNEL_QA 214 +#define WLC_GET_CHANNEL_SEL 215 +#define WLC_START_CHANNEL_SEL 216 +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ +#define WLC_GET_VALID_CHANNELS 217 +#define WLC_GET_FAKEFRAG 218 +#define WLC_SET_FAKEFRAG 219 +#define WLC_GET_PWROUT_PERCENTAGE 220 +#define WLC_SET_PWROUT_PERCENTAGE 221 +#define WLC_SET_BAD_FRAME_PREEMPT 222 +#define WLC_GET_BAD_FRAME_PREEMPT 223 +#define WLC_SET_LEAP_LIST 224 +#define WLC_GET_LEAP_LIST 225 +#define WLC_GET_CWMIN 226 +#define WLC_SET_CWMIN 227 +#define WLC_GET_CWMAX 228 +#define WLC_SET_CWMAX 229 +#define WLC_GET_WET 230 +#define WLC_SET_WET 231 +#define WLC_GET_PUB 232 +/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ +/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ +#define WLC_GET_KEY_PRIMARY 235 +#define WLC_SET_KEY_PRIMARY 236 + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ +#define WLC_GET_ACI_ARGS 238 +#define WLC_SET_ACI_ARGS 239 +#define WLC_UNSET_CALLBACK 240 +#define WLC_SET_CALLBACK 241 +#define WLC_GET_RADAR 242 +#define WLC_SET_RADAR 243 +#define WLC_SET_SPECT_MANAGMENT 244 +#define WLC_GET_SPECT_MANAGMENT 245 +#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ +#define WLC_WDS_GET_WPA_SUP 247 +#define WLC_SET_CS_SCAN_TIMER 248 +#define WLC_GET_CS_SCAN_TIMER 249 +#define WLC_MEASURE_REQUEST 250 +#define WLC_INIT 251 +#define WLC_SEND_QUIET 252 +#define WLC_KEEPALIVE 253 +#define WLC_SEND_PWR_CONSTRAINT 254 +#define WLC_UPGRADE_STATUS 255 +#define WLC_CURRENT_PWR 256 +#define WLC_GET_SCAN_PASSIVE_TIME 257 +#define WLC_SET_SCAN_PASSIVE_TIME 258 +#define WLC_LEGACY_LINK_BEHAVIOR 259 +#define WLC_GET_CHANNELS_IN_COUNTRY 260 +#define WLC_GET_COUNTRY_LIST 261 +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ +#define WLC_GET_VAR 262 /* get value of named variable */ +#define WLC_SET_VAR 263 /* set named variable to value */ +#ifndef LINUX_POSTMOGRIFY_REMOVAL +#define WLC_NVRAM_GET 264 /* deprecated */ +#define WLC_NVRAM_SET 265 +#define WLC_NVRAM_DUMP 266 +#define WLC_REBOOT 267 +#endif /* !LINUX_POSTMOGRIFY_REMOVAL */ +#define WLC_SET_WSEC_PMK 268 +#ifndef LINUX_POSTMOGRIFY_REMOVAL +#define WLC_GET_AUTH_MODE 269 +#define WLC_SET_AUTH_MODE 270 +#define WLC_GET_WAKEENTRY 271 +#define WLC_SET_WAKEENTRY 272 +#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ +#define WLC_NVOTPW 274 +#define WLC_OTPW 275 +#define WLC_IOV_BLOCK_GET 276 +#define WLC_IOV_MODULES_GET 277 +#define WLC_SOFT_RESET 278 +#define WLC_GET_ALLOW_MODE 279 +#define WLC_SET_ALLOW_MODE 280 +#define WLC_GET_DESIRED_BSSID 281 +#define WLC_SET_DESIRED_BSSID 282 +#define WLC_DISASSOC_MYAP 283 +#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ +#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ +#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ +#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ +#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ +#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ +#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ +#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ +#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ +#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ +#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ +#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ +#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ +#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ +#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ +#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ +#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ +#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ +#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ +#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ +#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ +#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ +/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ +#define WLC_GET_CMD 309 +/* #define WLC_LAST 310 */ /* Never used - can be reused */ +#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ +#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ +/* #define WLC_GET_WAI_RESTRICT 313 */ /* for WAPI, deprecated use iovar instead */ +/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */ +/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ +#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ +#define WLC_GET_NAT_STATE 317 +#define WLC_GET_TXBF_RATESET 318 +#define WLC_SET_TXBF_RATESET 319 +#define WLC_SCAN_CQ 320 +#define WLC_GET_RSSI_QDB 321 /* qdB portion of the RSSI */ + +#define WLC_LAST 322 +#ifndef EPICTRL_COOKIE +#define EPICTRL_COOKIE 0xABADCEDE +#endif + +/* vx wlc ioctl's offset */ +#define CMN_IOCTL_OFF 0x180 + +/* + * custom OID support + * + * 0xFF - implementation specific OID + * 0xE4 - first byte of Broadcom PCI vendor ID + * 0x14 - second byte of Broadcom PCI vendor ID + * 0xXX - the custom OID number + */ + +/* begin 0x1f values beyond the start of the ET driver range. */ +#define WL_OID_BASE 0xFFE41420 + +/* NDIS overrides */ +#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) +#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) +#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) +#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) +#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) +#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) +#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) + +/* EXT_STA Dongle suuport */ +#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) +#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) +#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) +#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) +#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) +#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) +#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) +#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) +#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) +#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) +#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) +#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) +#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) +#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) +#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) + +/* NAT filter driver support */ +#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) +#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) + +#define WL_DECRYPT_STATUS_SUCCESS 1 +#define WL_DECRYPT_STATUS_FAILURE 2 +#define WL_DECRYPT_STATUS_UNKNOWN 3 + +/* allows user-mode app to poll the status of USB image upgrade */ +#define WLC_UPGRADE_SUCCESS 0 +#define WLC_UPGRADE_PENDING 1 + +/* WLC_GET_AUTH, WLC_SET_AUTH values */ +#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ +#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ +#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ + +/* a large TX Power as an init value to factor out of MIN() calculations, + * keep low enough to fit in an int8, units are .25 dBm + */ +#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ + +/* "diag" iovar argument and error code */ +#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ +#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ +#define WL_DIAG_MEMORY 3 /* d11 memory test */ +#define WL_DIAG_LED 4 /* LED test */ +#define WL_DIAG_REG 5 /* d11/phy register test */ +#define WL_DIAG_SROM 6 /* srom read/crc test */ +#define WL_DIAG_DMA 7 /* DMA test */ +#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ + +#define WL_DIAGERR_SUCCESS 0 +#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ +#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ +#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ +#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ +#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ +#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ +#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ +#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ +#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ +#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ + +#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ +#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ + +/* band types */ +#define WLC_BAND_AUTO 0 /* auto-select */ +#define WLC_BAND_5G 1 /* 5 Ghz */ +#define WLC_BAND_2G 2 /* 2.4 Ghz */ +#define WLC_BAND_ALL 3 /* all bands */ + +/* band range returned by band_range iovar */ +#define WL_CHAN_FREQ_RANGE_2G 0 +#define WL_CHAN_FREQ_RANGE_5GL 1 +#define WL_CHAN_FREQ_RANGE_5GM 2 +#define WL_CHAN_FREQ_RANGE_5GH 3 + +#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4 +#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5 +#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6 +#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7 +#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8 + +#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 +#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 +#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 +#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 + +#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 + +/* MAC list modes */ +#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ +#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ +#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ + +/* + * 54g modes (basic bits may still be overridden) + * + * GMODE_LEGACY_B Rateset: 1b, 2b, 5.5, 11 + * Preamble: Long + * Shortslot: Off + * GMODE_AUTO Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 + * Extended Rateset: 6, 9, 12, 48 + * Preamble: Long + * Shortslot: Auto + * GMODE_ONLY Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54 + * Extended Rateset: 6b, 9, 12b, 48 + * Preamble: Short required + * Shortslot: Auto + * GMODE_B_DEFERRED Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 + * Extended Rateset: 6, 9, 12, 48 + * Preamble: Long + * Shortslot: On + * GMODE_PERFORMANCE Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54 + * Preamble: Short required + * Shortslot: On and required + * GMODE_LRS Rateset: 1b, 2b, 5.5b, 11b + * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54 + * Preamble: Long + * Shortslot: Auto + */ +#define GMODE_LEGACY_B 0 +#define GMODE_AUTO 1 +#define GMODE_ONLY 2 +#define GMODE_B_DEFERRED 3 +#define GMODE_PERFORMANCE 4 +#define GMODE_LRS 5 +#define GMODE_MAX 6 + +/* values for PLCPHdr_override */ +#define WLC_PLCP_AUTO -1 +#define WLC_PLCP_SHORT 0 +#define WLC_PLCP_LONG 1 + +/* values for g_protection_override and n_protection_override */ +#define WLC_PROTECTION_AUTO -1 +#define WLC_PROTECTION_OFF 0 +#define WLC_PROTECTION_ON 1 +#define WLC_PROTECTION_MMHDR_ONLY 2 +#define WLC_PROTECTION_CTS_ONLY 3 + +/* values for g_protection_control and n_protection_control */ +#define WLC_PROTECTION_CTL_OFF 0 +#define WLC_PROTECTION_CTL_LOCAL 1 +#define WLC_PROTECTION_CTL_OVERLAP 2 + +/* values for n_protection */ +#define WLC_N_PROTECTION_OFF 0 +#define WLC_N_PROTECTION_OPTIONAL 1 +#define WLC_N_PROTECTION_20IN40 2 +#define WLC_N_PROTECTION_MIXEDMODE 3 + +/* values for n_preamble_type */ +#define WLC_N_PREAMBLE_MIXEDMODE 0 +#define WLC_N_PREAMBLE_GF 1 +#define WLC_N_PREAMBLE_GF_BRCM 2 + +/* values for band specific 40MHz capabilities (deprecated) */ +#define WLC_N_BW_20ALL 0 +#define WLC_N_BW_40ALL 1 +#define WLC_N_BW_20IN2G_40IN5G 2 + +#define WLC_BW_20MHZ_BIT (1<<0) +#define WLC_BW_40MHZ_BIT (1<<1) +#define WLC_BW_80MHZ_BIT (1<<2) +#define WLC_BW_160MHZ_BIT (1<<3) + +/* Bandwidth capabilities */ +#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_160MHZ (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ + WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_UNRESTRICTED 0xFF + +#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) +#define WL_BW_CAP_160MHZ(bw_cap)(((bw_cap) & WLC_BW_160MHZ_BIT) ? TRUE : FALSE) + +/* values to force tx/rx chain */ +#define WLC_N_TXRX_CHAIN0 0 +#define WLC_N_TXRX_CHAIN1 1 + +/* bitflags for SGI support (sgi_rx iovar) */ +#define WLC_N_SGI_20 0x01 +#define WLC_N_SGI_40 0x02 +#define WLC_VHT_SGI_80 0x04 + +/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ +#define WLC_SGI_ALL 0x02 + +#define LISTEN_INTERVAL 10 +/* interference mitigation options */ +#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ +#define INTERFERE_NONE 0 /* off */ +#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ +#define WLAN_MANUAL 2 /* ACI: no auto detection */ +#define WLAN_AUTO 3 /* ACI: auto detect */ +#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ +#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ + +/* interfernece mode bit-masks (ACPHY) */ +#define ACPHY_ACI_GLITCHBASED_DESENSE 1 /* bit 0 */ +#define ACPHY_ACI_HWACI_PKTGAINLMT 2 /* bit 1 */ +#define ACPHY_ACI_W2NB_PKTGAINLMT 4 /* bit 2 */ +#define ACPHY_ACI_PREEMPTION 8 /* bit 3 */ +#define ACPHY_ACI_MAX_MODE 15 + +/* AP environment */ +#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ +#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ +#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ +#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ + +#define TRIGGER_NOW 0 +#define TRIGGER_CRS 0x01 +#define TRIGGER_CRSDEASSERT 0x02 +#define TRIGGER_GOODFCS 0x04 +#define TRIGGER_BADFCS 0x08 +#define TRIGGER_BADPLCP 0x10 +#define TRIGGER_CRSGLITCH 0x20 + +#define WL_SAMPLEDATA_HEADER_TYPE 1 +#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ +#define WL_SAMPLEDATA_TYPE 2 +#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ +#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ + +/* WL_OTA START */ +#define WL_OTA_ARG_PARSE_BLK_SIZE 1200 +#define WL_OTA_TEST_MAX_NUM_RATE 30 +#define WL_OTA_TEST_MAX_NUM_SEQ 100 + +#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ + +/* radar iovar SET defines */ +#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ +#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ +#define WL_RADAR_SIMULATED 2 /* force radar detector to declare + * detection once + */ +#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ +#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */ +#define WL_ANT_HT_RX_MAX 3 /* max 3 receive antennas/cores */ +#define WL_ANT_IDX_1 0 /* antenna index 1 */ +#define WL_ANT_IDX_2 1 /* antenna index 2 */ + +#ifndef WL_RSSI_ANT_MAX +#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ +#elif WL_RSSI_ANT_MAX != 4 +#error "WL_RSSI_ANT_MAX does not match" +#endif + +/* dfs_status iovar-related defines */ + +/* cac - channel availability check, + * ism - in-service monitoring + * csa - channel switching announcement + */ + +/* cac state values */ +#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ +#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ +#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ +#define WL_DFS_CACSTATE_CSA 3 /* csa */ +#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ +#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ +#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ +#define WL_DFS_CACSTATES 7 /* this many states exist */ + +/* Defines used with channel_bandwidth for curpower */ +#define WL_BW_20MHZ 0 +#define WL_BW_40MHZ 1 +#define WL_BW_80MHZ 2 +#define WL_BW_160MHZ 3 + +/* tx_power_t.flags bits */ +#define WL_TX_POWER_F_ENABLED 1 +#define WL_TX_POWER_F_HW 2 +#define WL_TX_POWER_F_MIMO 4 +#define WL_TX_POWER_F_SISO 8 +#define WL_TX_POWER_F_HT 0x10 +#define WL_TX_POWER_F_VHT 0x20 +#define WL_TX_POWER_F_OPENLOOP 0x40 + +/* Message levels */ +#define WL_ERROR_VAL 0x00000001 +#define WL_TRACE_VAL 0x00000002 +#define WL_PRHDRS_VAL 0x00000004 +#define WL_PRPKT_VAL 0x00000008 +#define WL_INFORM_VAL 0x00000010 +#define WL_TMP_VAL 0x00000020 +#define WL_OID_VAL 0x00000040 +#define WL_RATE_VAL 0x00000080 +#define WL_ASSOC_VAL 0x00000100 +#define WL_PRUSR_VAL 0x00000200 +#define WL_PS_VAL 0x00000400 +#define WL_TXPWR_VAL 0x00000800 /* retired in TOT on 6/10/2009 */ +#define WL_PORT_VAL 0x00001000 +#define WL_DUAL_VAL 0x00002000 +#define WL_WSEC_VAL 0x00004000 +#define WL_WSEC_DUMP_VAL 0x00008000 +#define WL_LOG_VAL 0x00010000 +#define WL_NRSSI_VAL 0x00020000 /* retired in TOT on 6/10/2009 */ +#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */ +#define WL_REGULATORY_VAL 0x00080000 +#define WL_PHYCAL_VAL 0x00100000 /* retired in TOT on 6/10/2009 */ +#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */ +#define WL_MPC_VAL 0x00400000 +#define WL_APSTA_VAL 0x00800000 +#define WL_DFS_VAL 0x01000000 +#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */ +#define WL_ACI_VAL 0x04000000 +#define WL_MBSS_VAL 0x04000000 +#define WL_CAC_VAL 0x08000000 +#define WL_AMSDU_VAL 0x10000000 +#define WL_AMPDU_VAL 0x20000000 +#define WL_FFPLD_VAL 0x40000000 + +/* wl_msg_level is full. For new bits take the next one and AND with + * wl_msg_level2 in wl_dbg.h + */ +#define WL_DPT_VAL 0x00000001 +#define WL_SCAN_VAL 0x00000002 +#define WL_WOWL_VAL 0x00000004 +#define WL_COEX_VAL 0x00000008 +#define WL_RTDC_VAL 0x00000010 +#define WL_PROTO_VAL 0x00000020 +#define WL_BTA_VAL 0x00000040 +#define WL_CHANINT_VAL 0x00000080 +#define WL_WMF_VAL 0x00000100 +#define WL_P2P_VAL 0x00000200 +#define WL_ITFR_VAL 0x00000400 +#define WL_MCHAN_VAL 0x00000800 +#define WL_TDLS_VAL 0x00001000 +#define WL_MCNX_VAL 0x00002000 +#define WL_PROT_VAL 0x00004000 +#define WL_PSTA_VAL 0x00008000 +#define WL_TSO_VAL 0x00010000 +#define WL_TRF_MGMT_VAL 0x00020000 +#define WL_LPC_VAL 0x00040000 +#define WL_L2FILTER_VAL 0x00080000 +#define WL_TXBF_VAL 0x00100000 +#define WL_P2PO_VAL 0x00200000 +#define WL_TBTT_VAL 0x00400000 +#define WL_NIC_VAL 0x00800000 +#define WL_MQ_VAL 0x01000000 + +/* This level is currently used in Phoenix2 only */ +#define WL_SRSCAN_VAL 0x02000000 + +#define WL_WNM_VAL 0x04000000 +#define WL_PWRSEL_VAL 0x10000000 +#define WL_NET_DETECT_VAL 0x20000000 +#define WL_PCIE_VAL 0x40000000 + +/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier + * rather than a message-type of its own + */ +#define WL_TIMESTAMP_VAL 0x80000000 + +/* max # of leds supported by GPIO (gpio pin# == led index#) */ +#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ + +/* led per-pin behaviors */ +#define WL_LED_OFF 0 /* always off */ +#define WL_LED_ON 1 /* always on */ +#define WL_LED_ACTIVITY 2 /* activity */ +#define WL_LED_RADIO 3 /* radio enabled */ +#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ +#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ +#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ +#define WL_LED_WI1 7 +#define WL_LED_WI2 8 +#define WL_LED_WI3 9 +#define WL_LED_ASSOC 10 /* associated state indicator */ +#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ +#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ +#define WL_LED_WI4 13 +#define WL_LED_WI5 14 +#define WL_LED_BLINKSLOW 15 /* blink slow */ +#define WL_LED_BLINKMED 16 /* blink med */ +#define WL_LED_BLINKFAST 17 /* blink fast */ +#define WL_LED_BLINKCUSTOM 18 /* blink custom */ +#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ +#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ + /* keep on for 300 sec */ +#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ +#define WL_LED_WI6 22 +#define WL_LED_WI7 23 +#define WL_LED_WI8 24 +#define WL_LED_NUMBEHAVIOR 25 + +/* led behavior numeric value format */ +#define WL_LED_BEH_MASK 0x7f /* behavior mask */ +#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ + +/* number of bytes needed to define a proper bit mask for MAC event reporting */ +#define BCMIO_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#define BCMIO_NBBY 8 +/* number of bytes needed to define a mask for MAC event reporting */ +#define WL_EVENTING_MASK_LEN (((WLC_E_LAST) / 8) + (((WLC_E_LAST % 8) > 0) ? 1 : 0)) + + +/* join preference types */ +#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ +#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ +#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ +#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ +#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ + +/* band preference */ +#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ + +/* any multicast cipher suite */ +#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" + +/* 802.11h measurement types */ +#define WLC_MEASURE_TPC 1 +#define WLC_MEASURE_CHANNEL_BASIC 2 +#define WLC_MEASURE_CHANNEL_CCA 3 +#define WLC_MEASURE_CHANNEL_RPI 4 + +/* regulatory enforcement levels */ +#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ +#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ +#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ +#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ +/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE + * adoption is done regardless of capability spectrum_management + */ +#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ + +#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ +#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ +#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ +#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ +#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ +#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ +#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ + +/* BTC mode used by "btc_mode" iovar */ +#define WL_BTC_DISABLE 0 /* disable BT coexistence */ +#define WL_BTC_FULLTDM 1 /* full TDM COEX */ +#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ +#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ +#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ +#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ +#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ +#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ +#define WL_INF_BTC_DISABLE 0 +#define WL_INF_BTC_ENABLE 1 +#define WL_INF_BTC_AUTO 3 + +/* BTC wire used by "btc_wire" iovar */ +#define WL_BTC_DEFWIRE 0 /* use default wire setting */ +#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ +#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ +#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ + +/* BTC flags: BTC configuration that can be set by host */ +#define WL_BTC_FLAG_PREMPT (1 << 0) +#define WL_BTC_FLAG_BT_DEF (1 << 1) +#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) +#define WL_BTC_FLAG_SIM_RSP (1 << 3) +#define WL_BTC_FLAG_PS_PROTECT (1 << 4) +#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) +#define WL_BTC_FLAG_ECI (1 << 6) +#define WL_BTC_FLAG_LIGHT (1 << 7) +#define WL_BTC_FLAG_PARALLEL (1 << 8) + +/* maximum channels returned by the get valid channels iovar */ +#define WL_NUMCHANNELS 64 + +/* max number of chanspecs (used by the iovar to calc. buf space) */ +#define WL_NUMCHANSPECS 110 + +/* WDS link local endpoint WPA role */ +#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ +#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ +#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ + +/* Base offset values */ +#define WL_PKT_FILTER_BASE_PKT 0 +#define WL_PKT_FILTER_BASE_END 1 +#define WL_PKT_FILTER_BASE_D11_H 2 /* May be removed */ +#define WL_PKT_FILTER_BASE_D11_D 3 /* May be removed */ +#define WL_PKT_FILTER_BASE_ETH_H 4 +#define WL_PKT_FILTER_BASE_ETH_D 5 +#define WL_PKT_FILTER_BASE_ARP_H 6 +#define WL_PKT_FILTER_BASE_ARP_D 7 /* May be removed */ +#define WL_PKT_FILTER_BASE_IP4_H 8 +#define WL_PKT_FILTER_BASE_IP4_D 9 +#define WL_PKT_FILTER_BASE_IP6_H 10 +#define WL_PKT_FILTER_BASE_IP6_D 11 +#define WL_PKT_FILTER_BASE_TCP_H 12 +#define WL_PKT_FILTER_BASE_TCP_D 13 /* May be removed */ +#define WL_PKT_FILTER_BASE_UDP_H 14 +#define WL_PKT_FILTER_BASE_UDP_D 15 +#define WL_PKT_FILTER_BASE_IP6_P 16 +#define WL_PKT_FILTER_BASE_COUNT 17 /* May be removed */ + +/* String mapping for bases that may be used by applications or debug */ +#define WL_PKT_FILTER_BASE_NAMES \ + { "START", WL_PKT_FILTER_BASE_PKT }, \ + { "END", WL_PKT_FILTER_BASE_END }, \ + { "ETH_H", WL_PKT_FILTER_BASE_ETH_H }, \ + { "ETH_D", WL_PKT_FILTER_BASE_ETH_D }, \ + { "D11_H", WL_PKT_FILTER_BASE_D11_H }, \ + { "D11_D", WL_PKT_FILTER_BASE_D11_D }, \ + { "ARP_H", WL_PKT_FILTER_BASE_ARP_H }, \ + { "IP4_H", WL_PKT_FILTER_BASE_IP4_H }, \ + { "IP4_D", WL_PKT_FILTER_BASE_IP4_D }, \ + { "IP6_H", WL_PKT_FILTER_BASE_IP6_H }, \ + { "IP6_D", WL_PKT_FILTER_BASE_IP6_D }, \ + { "IP6_P", WL_PKT_FILTER_BASE_IP6_P }, \ + { "TCP_H", WL_PKT_FILTER_BASE_TCP_H }, \ + { "TCP_D", WL_PKT_FILTER_BASE_TCP_D }, \ + { "UDP_H", WL_PKT_FILTER_BASE_UDP_H }, \ + { "UDP_D", WL_PKT_FILTER_BASE_UDP_D } + +/* Flags for a pattern list element */ +#define WL_PKT_FILTER_MFLAG_NEG 0x0001 + +/* + * Packet engine interface + */ + +#define WL_PKTENG_PER_TX_START 0x01 +#define WL_PKTENG_PER_TX_STOP 0x02 +#define WL_PKTENG_PER_RX_START 0x04 +#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 +#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 +#define WL_PKTENG_PER_RX_STOP 0x08 +#define WL_PKTENG_PER_MASK 0xff + +#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ + +#define WL_PKTENG_MAXPKTSZ 16384 /* max pktsz limit for pkteng */ + +#define NUM_80211b_RATES 4 +#define NUM_80211ag_RATES 8 +#define NUM_80211n_RATES 32 +#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) + +/* + * WOWL capability/override settings + */ +#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ +#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ +#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ +#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ +#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ +#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ +#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ +#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ +#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ +#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ +#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ +#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ +#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ +#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ +#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ +#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ +#define WL_WOWL_SCANOL (1 << 16) /* If the bit is set, scan offload is enabled */ +#define WL_WOWL_TCPKEEP_TIME (1 << 17) /* Wakeup on tcpkeep alive timeout */ +#define WL_WOWL_MDNS_CONFLICT (1 << 18) /* Wakeup on mDNS Conflict Resolution */ +#define WL_WOWL_MDNS_SERVICE (1 << 19) /* Wakeup on mDNS Service Connect */ +#define WL_WOWL_TCPKEEP_DATA (1 << 20) /* tcp keepalive got data */ +#define WL_WOWL_FW_HALT (1 << 21) /* Firmware died in wowl mode */ +#define WL_WOWL_ENAB_HWRADIO (1 << 22) /* Enable detection of radio button changes */ +#define WL_WOWL_MIC_FAIL (1 << 23) /* Offloads detected MIC failure(s) */ +#define WL_WOWL_LINKDOWN (1 << 31) /* Link Down indication in WoWL mode */ + +#define WL_WOWL_TCPKEEP (1 << 20) /* temp copy to satisfy automerger */ +#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ + +#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ +#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ + +#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ +#define MAGIC_PKT_NUM_MAC_ADDRS 16 + + +/* Overlap BSS Scan parameters default, minimum, maximum */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ + +#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ + +#define WL_COEX_INFO_MASK 0x07 +#define WL_COEX_INFO_REQ 0x01 +#define WL_COEX_40MHZ_INTOLERANT 0x02 +#define WL_COEX_WIDTH20 0x04 + +#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ + +#define MAX_RSSI_LEVELS 8 + +/* **** EXTLOG **** */ +#define EXTLOG_CUR_VER 0x0100 + +#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ + +/* log modules (bitmap) */ +#define LOG_MODULE_COMMON 0x0001 +#define LOG_MODULE_ASSOC 0x0002 +#define LOG_MODULE_EVENT 0x0004 +#define LOG_MODULE_MAX 3 /* Update when adding module */ + +/* log levels */ +#define WL_LOG_LEVEL_DISABLE 0 +#define WL_LOG_LEVEL_ERR 1 +#define WL_LOG_LEVEL_WARN 2 +#define WL_LOG_LEVEL_INFO 3 +#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ + +/* flag */ +#define LOG_FLAG_EVENT 1 + +/* log arg_type */ +#define LOG_ARGTYPE_NULL 0 +#define LOG_ARGTYPE_STR 1 /* %s */ +#define LOG_ARGTYPE_INT 2 /* %d */ +#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ +#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ + +/* 802.11 Mgmt Packet flags */ +#define VNDR_IE_BEACON_FLAG 0x1 +#define VNDR_IE_PRBRSP_FLAG 0x2 +#define VNDR_IE_ASSOCRSP_FLAG 0x4 +#define VNDR_IE_AUTHRSP_FLAG 0x8 +#define VNDR_IE_PRBREQ_FLAG 0x10 +#define VNDR_IE_ASSOCREQ_FLAG 0x20 +#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ +#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ + +#if defined(WLP2P) +/* P2P Action Frames flags (spec ordered) */ +#define VNDR_IE_GONREQ_FLAG 0x001000 +#define VNDR_IE_GONRSP_FLAG 0x002000 +#define VNDR_IE_GONCFM_FLAG 0x004000 +#define VNDR_IE_INVREQ_FLAG 0x008000 +#define VNDR_IE_INVRSP_FLAG 0x010000 +#define VNDR_IE_DISREQ_FLAG 0x020000 +#define VNDR_IE_DISRSP_FLAG 0x040000 +#define VNDR_IE_PRDREQ_FLAG 0x080000 +#define VNDR_IE_PRDRSP_FLAG 0x100000 + +#define VNDR_IE_P2PAF_SHIFT 12 +#endif /* WLP2P */ + +/* channel interference measurement (chanim) related defines */ + +/* chanim mode */ +#define CHANIM_DISABLE 0 /* disabled */ +#define CHANIM_DETECT 1 /* detection only */ +#define CHANIM_EXT 2 /* external state machine */ +#define CHANIM_ACT 3 /* full internal state machine, detect + act */ +#define CHANIM_MODE_MAX 4 + +/* define for apcs reason code */ +#define APCS_INIT 0 +#define APCS_IOCTL 1 +#define APCS_CHANIM 2 +#define APCS_CSTIMER 3 +#define APCS_BTA 4 +#define APCS_TXDLY 5 +#define APCS_NONACSD 6 +#define APCS_DFS_REENTRY 7 +#define APCS_TXFAIL 8 +#define APCS_MAX 9 + +/* number of ACS record entries */ +#define CHANIM_ACS_RECORD 10 + +/* CHANIM */ +#define CCASTATS_TXDUR 0 +#define CCASTATS_INBSS 1 +#define CCASTATS_OBSS 2 +#define CCASTATS_NOCTG 3 +#define CCASTATS_NOPKT 4 +#define CCASTATS_DOZE 5 +#define CCASTATS_TXOP 6 +#define CCASTATS_GDTXDUR 7 +#define CCASTATS_BDTXDUR 8 +#define CCASTATS_MAX 9 + +#define WL_CHANIM_COUNT_ALL 0xff +#define WL_CHANIM_COUNT_ONE 0x1 + +/* ap tpc modes */ +#define AP_TPC_OFF 0 +#define AP_TPC_BSS_PWR 1 /* BSS power control */ +#define AP_TPC_AP_PWR 2 /* AP power control */ +#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ +#define AP_TPC_MAX_LINK_MARGIN 127 + +/* ap tpc modes */ +#define AP_TPC_OFF 0 +#define AP_TPC_BSS_PWR 1 /* BSS power control */ +#define AP_TPC_AP_PWR 2 /* AP power control */ +#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ +#define AP_TPC_MAX_LINK_MARGIN 127 + +/* state */ +#define WL_P2P_DISC_ST_SCAN 0 +#define WL_P2P_DISC_ST_LISTEN 1 +#define WL_P2P_DISC_ST_SEARCH 2 + +/* i/f type */ +#define WL_P2P_IF_CLIENT 0 +#define WL_P2P_IF_GO 1 +#define WL_P2P_IF_DYNBCN_GO 2 +#define WL_P2P_IF_DEV 3 + +/* count */ +#define WL_P2P_SCHED_RSVD 0 +#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ + +#define WL_P2P_SCHED_FIXED_LEN 3 + +/* schedule type */ +#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ +#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ + +/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ +#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ +#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ +/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ +#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ +/* schedule option - WL_P2P_SCHED_TYPE_XXX */ +#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ + +/* schedule option - WL_P2P_SCHED_TYPE_ABS */ +#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ +#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ +/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ +#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with + * start being an offset of the 'current' TSF + */ + +/* feature flags */ +#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ +#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe + * requests + */ +#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ + +/* n-mode support capability */ +/* 2x2 includes both 1x1 & 2x2 devices + * reserved #define 2 for future when we want to separate 1x1 & 2x2 and + * control it independently + */ +#define WL_11N_2x2 1 +#define WL_11N_3x3 3 +#define WL_11N_4x4 4 + +/* define 11n feature disable flags */ +#define WLFEATURE_DISABLE_11N 0x00000001 +#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 +#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 +#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 +#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 +#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 +#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 +#define WLFEATURE_DISABLE_11N_GF 0x00000080 + +/* Proxy STA modes */ +#define PSTA_MODE_DISABLED 0 +#define PSTA_MODE_PROXY 1 +#define PSTA_MODE_REPEATER 2 + +/* op code in nat_cfg */ +#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ +#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ +#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ + +/* NAT state */ +#define NAT_STATE_ENABLED 1 /* NAT is enabled */ +#define NAT_STATE_DISABLED 2 /* NAT is disabled */ + +#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ +#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ +#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ +#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ + +/* D0 Coalescing */ +#define IPV4_ARP_FILTER 0x0001 +#define IPV4_NETBT_FILTER 0x0002 +#define IPV4_LLMNR_FILTER 0x0004 +#define IPV4_SSDP_FILTER 0x0008 +#define IPV4_WSD_FILTER 0x0010 +#define IPV6_NETBT_FILTER 0x0200 +#define IPV6_LLMNR_FILTER 0x0400 +#define IPV6_SSDP_FILTER 0x0800 +#define IPV6_WSD_FILTER 0x1000 + +/* Network Offload Engine */ +#define NWOE_OL_ENABLE 0x00000001 + +/* + * Traffic management structures/defines. + */ + +/* Traffic management bandwidth parameters */ +#define TRF_MGMT_MAX_PRIORITIES 3 + +#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ +#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Don't shape traffic */ +#define TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC 0x0008 /* Manage traffic over our local subnet */ +#define TRF_MGMT_FLAG_FILTER_ON_MACADDR 0x0010 /* filter on MAC address */ +#define TRF_MGMT_FLAG_NO_RX 0x0020 /* do not apply fiters to rx packets */ + +#define TRF_FILTER_MAC_ADDR 0x0001 /* L2 filter use dst mac address for filtering */ +#define TRF_FILTER_IP_ADDR 0x0002 /* L3 filter use ip ddress for filtering */ +#define TRF_FILTER_L4 0x0004 /* L4 filter use tcp/udp for filtering */ +#define TRF_FILTER_DWM 0x0008 /* L3 filter use DSCP for filtering */ +#define TRF_FILTER_FAVORED 0x0010 /* Tag the packet FAVORED */ + +/* WNM/NPS subfeatures mask */ +#define WL_WNM_BSSTRANS 0x00000001 +#define WL_WNM_PROXYARP 0x00000002 +#define WL_WNM_MAXIDLE 0x00000004 +#define WL_WNM_TIMBC 0x00000008 +#define WL_WNM_TFS 0x00000010 +#define WL_WNM_SLEEP 0x00000020 +#define WL_WNM_DMS 0x00000040 +#define WL_WNM_FMS 0x00000080 +#define WL_WNM_NOTIF 0x00000100 +#define WL_WNM_MAX 0x00000200 + +#ifndef ETHER_MAX_DATA +#define ETHER_MAX_DATA 1500 +#endif /* ETHER_MAX_DATA */ + +/* Different discovery modes for dpt */ +#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ +#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ +#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ + +/* different path selection values */ +#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ +#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ +#define DPT_PATHSEL_APPATH 2 /* always use AP path */ + +/* different ops for deny list */ +#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ +#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ + +/* different ops for manual end point */ +#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ +#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ +#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ + +/* flags to indicate DPT status */ +#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ +#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ +#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ + +#ifdef WLTDLS +/* different ops for manual end point */ +#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ +#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ +#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ +#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ +#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ +#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ +#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ +#define TDLS_MANUAL_EP_WFD_TPQ 8 /* WiFi-Display Tunneled Probe reQuest */ + +/* modes */ +#define TDLS_WFD_IE_TX 0 +#define TDLS_WFD_IE_RX 1 +#define TDLS_WFD_PROBE_IE_TX 2 +#define TDLS_WFD_PROBE_IE_RX 3 +#endif /* WLTDLS */ + +/* define for flag */ +#define TSPEC_PENDING 0 /* TSPEC pending */ +#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ +#define TSPEC_REJECTED 2 /* TSPEC rejected */ +#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ +#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ + +#ifdef BCMCCX +/* "wlan_reason" iovar interface */ +#define WL_WLAN_ASSOC_REASON_NORMAL_NETWORK 0 /* normal WLAN network setup */ +#define WL_WLAN_ASSOC_REASON_ROAM_FROM_CELLULAR_NETWORK 1 /* roam from Cellular network */ +#define WL_WLAN_ASSOC_REASON_ROAM_FROM_LAN 2 /* roam from LAN */ +#define WL_WLAN_ASSOC_REASON_MAX 2 /* largest value allowed */ +#endif /* BCMCCX */ + +/* Software feature flag defines used by wlfeatureflag */ +#ifdef WLAFTERBURNER +#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ +#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ +#endif /* WLAFTERBURNER */ +#define WL_SWFL_NOHWRADIO 0x0004 +#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ +#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ + +#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ + +#define CSA_BROADCAST_ACTION_FRAME 0 /* csa broadcast action frame */ +#define CSA_UNICAST_ACTION_FRAME 1 /* csa unicast action frame */ + +/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. + * + * (-100 < value < 0) value is used directly as a roaming trigger in dBm + * (0 <= value) value specifies a logical roaming trigger level from + * the list below + * + * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never + * the logical roam trigger value. + */ +#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ +#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ +#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ +#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ +#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ + +#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ + +/* Preferred Network Offload (PNO, formerly PFN) defines */ +#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ + +#define SORT_CRITERIA_BIT 0 +#define AUTO_NET_SWITCH_BIT 1 +#define ENABLE_BKGRD_SCAN_BIT 2 +#define IMMEDIATE_SCAN_BIT 3 +#define AUTO_CONNECT_BIT 4 +#define ENABLE_BD_SCAN_BIT 5 +#define ENABLE_ADAPTSCAN_BIT 6 +#define IMMEDIATE_EVENT_BIT 8 +#define SUPPRESS_SSID_BIT 9 +#define ENABLE_NET_OFFLOAD_BIT 10 + +#define SORT_CRITERIA_MASK 0x0001 +#define AUTO_NET_SWITCH_MASK 0x0002 +#define ENABLE_BKGRD_SCAN_MASK 0x0004 +#define IMMEDIATE_SCAN_MASK 0x0008 +#define AUTO_CONNECT_MASK 0x0010 + +#define ENABLE_BD_SCAN_MASK 0x0020 +#define ENABLE_ADAPTSCAN_MASK 0x00c0 +#define IMMEDIATE_EVENT_MASK 0x0100 +#define SUPPRESS_SSID_MASK 0x0200 +#define ENABLE_NET_OFFLOAD_MASK 0x0400 + +#define PFN_VERSION 2 +#define PFN_SCANRESULT_VERSION 1 +#define MAX_PFN_LIST_COUNT 16 + +#define PFN_COMPLETE 1 +#define PFN_INCOMPLETE 0 + +#define DEFAULT_BESTN 2 +#define DEFAULT_MSCAN 0 +#define DEFAULT_REPEAT 10 +#define DEFAULT_EXP 2 + +#define WL_PFN_SUPPRESSFOUND_MASK 0x08 +#define WL_PFN_SUPPRESSLOST_MASK 0x10 +#define WL_PFN_RSSI_MASK 0xff00 +#define WL_PFN_RSSI_SHIFT 8 + +#define WL_PFN_REPORT_ALLNET 0 +#define WL_PFN_REPORT_SSIDNET 1 +#define WL_PFN_REPORT_BSSIDNET 2 + +#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ +#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ + +#define WL_PFN_HIDDEN_BIT 2 +#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ +#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ +#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ +#define WL_PFN_HIDDEN_MASK 0x4 + +/* TCP Checksum Offload error injection for testing */ +#define TOE_ERRTEST_TX_CSUM 0x00000001 +#define TOE_ERRTEST_RX_CSUM 0x00000002 +#define TOE_ERRTEST_RX_CSUM2 0x00000004 + +/* ARP Offload feature flags for arp_ol iovar */ +#define ARP_OL_AGENT 0x00000001 +#define ARP_OL_SNOOP 0x00000002 +#define ARP_OL_HOST_AUTO_REPLY 0x00000004 +#define ARP_OL_PEER_AUTO_REPLY 0x00000008 + +/* ARP Offload error injection */ +#define ARP_ERRTEST_REPLY_PEER 0x1 +#define ARP_ERRTEST_REPLY_HOST 0x2 + +#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ +#define ND_MULTIHOMING_MAX 10 /* Maximum local host IP addresses */ +#define ND_REQUEST_MAX 5 /* Max set of offload params */ + + +/* AOAC wake event flag */ +#define WAKE_EVENT_NLO_DISCOVERY_BIT 1 +#define WAKE_EVENT_AP_ASSOCIATION_LOST_BIT 2 +#define WAKE_EVENT_GTK_HANDSHAKE_ERROR_BIT 4 +#define WAKE_EVENT_4WAY_HANDSHAKE_REQUEST_BIT 8 + +#define MAX_NUM_WOL_PATTERN 16 /* LOGO requirements min 16 */ + +/* Packet filter operation mode */ +/* True: 1; False: 0 */ +#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 +/* Enable and disable pkt_filter as a whole */ +#define PKT_FILTER_MODE_DISABLE 2 +/* Cache first matched rx pkt(be queried by host later) */ +#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 +/* If pkt_filter is enabled and no filter is set, don't forward anything */ +#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 + +#ifdef DONGLEOVERLAYS +#define OVERLAY_IDX_MASK 0x000000ff +#define OVERLAY_IDX_SHIFT 0 +#define OVERLAY_FLAGS_MASK 0xffffff00 +#define OVERLAY_FLAGS_SHIFT 8 +/* overlay written to device memory immediately after loading the base image */ +#define OVERLAY_FLAG_POSTLOAD 0x100 +/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ +#define OVERLAY_FLAG_DEFER_DL 0x200 +/* overlay downloaded prior to the host going to sleep */ +#define OVERLAY_FLAG_PRESLEEP 0x400 +#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 +#endif /* DONGLEOVERLAYS */ + +/* reuse two number in the sc/rc space */ +#define SMFS_CODE_MALFORMED 0xFFFE +#define SMFS_CODE_IGNORED 0xFFFD + +/* RFAWARE def */ +#define BCM_ACTION_RFAWARE 0x77 +#define BCM_ACTION_RFAWARE_DCS 0x01 + +/* DCS reason code define */ +#define BCM_DCS_IOVAR 0x1 +#define BCM_DCS_UNKNOWN 0xFF + + +#ifdef PROP_TXSTATUS +/* Bit definitions for tlv iovar */ +/* + * enable RSSI signals: + * WLFC_CTL_TYPE_RSSI + */ +#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 + +/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: + * + * WLFC_CTL_TYPE_MAC_OPEN + * WLFC_CTL_TYPE_MAC_CLOSE + * + * WLFC_CTL_TYPE_INTERFACE_OPEN + * WLFC_CTL_TYPE_INTERFACE_CLOSE + * + * WLFC_CTL_TYPE_MACDESC_ADD + * WLFC_CTL_TYPE_MACDESC_DEL + * + */ +#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 + +/* enable (status, fifo_credit, mac_credit) signals + * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT + * WLFC_CTL_TYPE_TXSTATUS + * WLFC_CTL_TYPE_FIFO_CREDITBACK + */ +#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 + +#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 +#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 +#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 +#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 +#define WLFC_FLAGS_PKT_STAMP_SIGNALS 0x0080 + +#endif /* PROP_TXSTATUS */ + +#define WL_TIMBC_STATUS_AP_UNKNOWN 255 /* AP status for internal use only */ + +#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ +#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ +#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ + +/* Definitions for Reliable Multicast */ +#define WL_RELMCAST_MAX_CLIENT 32 +#define WL_RELMCAST_FLAG_INBLACKLIST 1 +#define WL_RELMCAST_FLAG_ACTIVEACKER 2 +#define WL_RELMCAST_FLAG_RELMCAST 4 + +/* structures for proximity detection device role */ +#define WL_PROXD_MODE_DISABLE 0 +#define WL_PROXD_MODE_NEUTRAL 1 +#define WL_PROXD_MODE_INITIATOR 2 +#define WL_PROXD_MODE_TARGET 3 +#define WL_PROXD_RANDOM_WAKEUP 0x8000 + + +#ifdef NET_DETECT +#define NET_DETECT_MAX_WAKE_DATA_SIZE 2048 +#define NET_DETECT_MAX_PROFILES 16 +#define NET_DETECT_MAX_CHANNELS 50 +#endif /* NET_DETECT */ + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* Bit masks for radio disabled status - returned by WL_GET_RADIO */ +#define WL_RADIO_SW_DISABLE (1<<0) +#define WL_RADIO_HW_DISABLE (1<<1) +#define WL_RADIO_MPC_DISABLE (1<<2) +#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */ + +#define WL_SPURAVOID_OFF 0 +#define WL_SPURAVOID_ON1 1 +#define WL_SPURAVOID_ON2 2 + + +#define WL_4335_SPURAVOID_ON1 1 +#define WL_4335_SPURAVOID_ON2 2 +#define WL_4335_SPURAVOID_ON3 3 +#define WL_4335_SPURAVOID_ON4 4 +#define WL_4335_SPURAVOID_ON5 5 +#define WL_4335_SPURAVOID_ON6 6 +#define WL_4335_SPURAVOID_ON7 7 +#define WL_4335_SPURAVOID_ON8 8 +#define WL_4335_SPURAVOID_ON9 9 + +/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ +#define WL_TXPWR_OVERRIDE (1U<<31) +#define WL_TXPWR_NEG (1U<<30) + + +/* phy types (returned by WLC_GET_PHYTPE) */ +#define WLC_PHY_TYPE_A 0 +#define WLC_PHY_TYPE_B 1 +#define WLC_PHY_TYPE_G 2 +#define WLC_PHY_TYPE_N 4 +#define WLC_PHY_TYPE_LP 5 +#define WLC_PHY_TYPE_SSN 6 +#define WLC_PHY_TYPE_HT 7 +#define WLC_PHY_TYPE_LCN 8 +#define WLC_PHY_TYPE_LCN40 10 +#define WLC_PHY_TYPE_AC 11 +#define WLC_PHY_TYPE_NULL 0xf + +/* Values for PM */ +#define PM_OFF 0 +#define PM_MAX 1 +#define PM_FAST 2 +#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ + +#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ + +/* fbt_cap: FBT assoc / reassoc modes. */ +#define WLC_FBT_CAP_DRV_4WAY_AND_REASSOC 1 /* Driver 4-way handshake & reassoc (WLFBT). */ + +/* monitor_promisc_level bits */ +#define WL_MONPROMISC_PROMISC 0x0001 +#define WL_MONPROMISC_CTRL 0x0002 +#define WL_MONPROMISC_FCS 0x0004 + +/* TCP Checksum Offload defines */ +#define TOE_TX_CSUM_OL 0x00000001 +#define TOE_RX_CSUM_OL 0x00000002 + +#endif /* wlioctl_defs_h */
diff --git a/src/common/include/proto/802.11.h b/src/common/include/proto/802.11.h new file mode 100644 index 0000000..b26593c --- /dev/null +++ b/src/common/include/proto/802.11.h
@@ -0,0 +1,3686 @@ +/* + * $Copyright Open Broadcom Corporation$ + * + * Fundamental types and constants relating to 802.11 + * + * $Id: 802.11.h 444070 2013-12-18 13:20:12Z $ + */ + +#ifndef _802_11_H_ +#define _802_11_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +#ifndef _NET_ETHERNET_H_ +#include <proto/ethernet.h> +#endif + +#include <proto/wpa.h> + + +#include <packed_section_start.h> + + +#define DOT11_TU_TO_US 1024 + + +#define DOT11_A3_HDR_LEN 24 +#define DOT11_A4_HDR_LEN 30 +#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN +#define DOT11_FCS_LEN 4 +#define DOT11_ICV_LEN 4 +#define DOT11_ICV_AES_LEN 8 +#define DOT11_QOS_LEN 2 +#define DOT11_HTC_LEN 4 + +#define DOT11_KEY_INDEX_SHIFT 6 +#define DOT11_IV_LEN 4 +#define DOT11_IV_TKIP_LEN 8 +#define DOT11_IV_AES_OCB_LEN 4 +#define DOT11_IV_AES_CCM_LEN 8 +#define DOT11_IV_MAX_LEN 8 + + +#define DOT11_MAX_MPDU_BODY_LEN 2304 + +#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ + DOT11_QOS_LEN + \ + DOT11_IV_AES_CCM_LEN + \ + DOT11_MAX_MPDU_BODY_LEN + \ + DOT11_ICV_LEN + \ + DOT11_FCS_LEN) + +#define DOT11_MAX_SSID_LEN 32 + + +#define DOT11_DEFAULT_RTS_LEN 2347 +#define DOT11_MAX_RTS_LEN 2347 + + +#define DOT11_MIN_FRAG_LEN 256 +#define DOT11_MAX_FRAG_LEN 2346 +#define DOT11_DEFAULT_FRAG_LEN 2346 + + +#define DOT11_MIN_BEACON_PERIOD 1 +#define DOT11_MAX_BEACON_PERIOD 0xFFFF + + +#define DOT11_MIN_DTIM_PERIOD 1 +#define DOT11_MAX_DTIM_PERIOD 0xFF + + +#define DOT11_LLC_SNAP_HDR_LEN 8 +#define DOT11_OUI_LEN 3 +BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { + uint8 dsap; + uint8 ssap; + uint8 ctl; + uint8 oui[DOT11_OUI_LEN]; + uint16 type; +} BWL_POST_PACKED_STRUCT; + + +#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) + + + +BWL_PRE_PACKED_STRUCT struct dot11_header { + uint16 fc; + uint16 durid; + struct ether_addr a1; + struct ether_addr a2; + struct ether_addr a3; + uint16 seq; + struct ether_addr a4; +} BWL_POST_PACKED_STRUCT; + + + +BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +#define DOT11_RTS_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { + uint16 fc; + uint16 durid; + struct ether_addr ra; +} BWL_POST_PACKED_STRUCT; +#define DOT11_CTS_LEN 10 + +BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { + uint16 fc; + uint16 durid; + struct ether_addr ra; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACK_LEN 10 + +BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { + uint16 fc; + uint16 durid; + struct ether_addr bssid; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +#define DOT11_PS_POLL_LEN 16 + +BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +#define DOT11_CS_END_LEN 16 + + +BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1040]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; + + +BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; + +#define DOT11_ACTION_VS_HDR_LEN 6 + +#define BCM_ACTION_OUI_BYTE0 0x00 +#define BCM_ACTION_OUI_BYTE1 0x90 +#define BCM_ACTION_OUI_BYTE2 0x4c + + +#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 +#define DOT11_BA_CTL_POLICY_NOACK 0x0001 +#define DOT11_BA_CTL_POLICY_MASK 0x0001 + +#define DOT11_BA_CTL_MTID 0x0002 +#define DOT11_BA_CTL_COMPRESSED 0x0004 + +#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 +#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 + +#define DOT11_BA_CTL_TID_MASK 0xF000 +#define DOT11_BA_CTL_TID_SHIFT 12 + + +BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +#define DOT11_CTL_HDR_LEN 16 + + +BWL_PRE_PACKED_STRUCT struct dot11_bar { + uint16 bar_control; + uint16 seqnum; +} BWL_POST_PACKED_STRUCT; +#define DOT11_BAR_LEN 4 + +#define DOT11_BA_BITMAP_LEN 128 +#define DOT11_BA_CMP_BITMAP_LEN 8 + +BWL_PRE_PACKED_STRUCT struct dot11_ba { + uint16 ba_control; + uint16 seqnum; + uint8 bitmap[DOT11_BA_BITMAP_LEN]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_BA_LEN 4 + + +BWL_PRE_PACKED_STRUCT struct dot11_management_header { + uint16 fc; + uint16 durid; + struct ether_addr da; + struct ether_addr sa; + struct ether_addr bssid; + uint16 seq; +} BWL_POST_PACKED_STRUCT; +#define DOT11_MGMT_HDR_LEN 24 + + + +BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { + uint32 timestamp[2]; + uint16 beacon_interval; + uint16 capability; +} BWL_POST_PACKED_STRUCT; +#define DOT11_BCN_PRB_LEN 12 +#define DOT11_BCN_PRB_FIXED_LEN 12 + +BWL_PRE_PACKED_STRUCT struct dot11_auth { + uint16 alg; + uint16 seq; + uint16 status; +} BWL_POST_PACKED_STRUCT; +#define DOT11_AUTH_FIXED_LEN 6 + +BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { + uint16 capability; + uint16 listen; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_REQ_FIXED_LEN 4 + +BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { + uint16 capability; + uint16 listen; + struct ether_addr ap; +} BWL_POST_PACKED_STRUCT; +#define DOT11_REASSOC_REQ_FIXED_LEN 10 + +BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { + uint16 capability; + uint16 status; + uint16 aid; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_RESP_FIXED_LEN 6 + +BWL_PRE_PACKED_STRUCT struct dot11_action_measure { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACTION_MEASURE_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { + uint8 category; + uint8 action; + uint8 ch_width; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { + uint8 category; + uint8 action; + uint8 control; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { + uint8 category; + uint8 action; + uint16 id; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { + uint8 category; + uint8 action; + uint8 mode; +} BWL_POST_PACKED_STRUCT; + +#define SM_PWRSAVE_ENABLE 1 +#define SM_PWRSAVE_MODE 2 + + +BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { + uint8 id; + uint8 len; + uint8 power; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_power_cnst dot11_power_cnst_t; + +BWL_PRE_PACKED_STRUCT struct dot11_power_cap { + uint8 min; + uint8 max; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_power_cap dot11_power_cap_t; + +BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { + uint8 id; + uint8 len; + uint8 tx_pwr; + uint8 margin; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tpc_rep dot11_tpc_rep_t; +#define DOT11_MNG_IE_TPC_REPORT_LEN 2 + +BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { + uint8 id; + uint8 len; + uint8 first_channel; + uint8 num_channels; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_supp_channels dot11_supp_channels_t; + + +BWL_PRE_PACKED_STRUCT struct dot11_extch { + uint8 id; + uint8 len; + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extch dot11_extch_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + uint8 extch; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; + +#define BRCM_EXTCH_IE_LEN 5 +#define BRCM_EXTCH_IE_TYPE 53 +#define DOT11_EXTCH_IE_LEN 1 +#define DOT11_EXT_CH_MASK 0x03 +#define DOT11_EXT_CH_UPPER 0x01 +#define DOT11_EXT_CH_LOWER 0x03 +#define DOT11_EXT_CH_NONE 0x00 + +BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { + uint8 category; + uint8 action; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_ACTION_FRMHDR_LEN 2 + + +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { + uint8 id; + uint8 len; + uint8 mode; + uint8 channel; + uint8 count; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch dot11_chan_switch_ie_t; + +#define DOT11_SWITCH_IE_LEN 3 + +#define DOT11_CSA_MODE_ADVISORY 0 +#define DOT11_CSA_MODE_NO_TX 1 + +BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { + uint8 category; + uint8 action; + dot11_chan_switch_ie_t chan_switch_ie; + dot11_brcm_extch_ie_t extch_ie; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11_csa_body { + uint8 mode; + uint8 reg; + uint8 channel; + uint8 count; +} BWL_POST_PACKED_STRUCT; + + +BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { + uint8 id; + uint8 len; + struct dot11_csa_body b; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ext_csa dot11_ext_csa_ie_t; +#define DOT11_EXT_CSA_IE_LEN 4 + +BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { + uint8 category; + uint8 action; + dot11_ext_csa_ie_t chan_switch_ie; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { + uint8 category; + uint8 action; + struct dot11_csa_body b; +} BWL_POST_PACKED_STRUCT; + + +BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { + uint8 id; + uint8 len; + uint8 channel_width; + uint8 center_frequency_segment_0; + uint8 center_frequency_segment_1; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; + +#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { + uint8 id; + uint8 len; + dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; + + +BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { + uint8 id; + uint8 len; + uint8 transmit_power_info; + uint8 local_max_transmit_power_20; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; + + +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1 +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2 +#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3 + +BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { + uint8 id; + uint8 len; + uint8 info; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_coex dot11_obss_coex_t; +#define DOT11_OBSS_COEXINFO_LEN 1 + +#define DOT11_OBSS_COEX_INFO_REQ 0x01 +#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 +#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 + +BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { + uint8 id; + uint8 len; + uint8 regclass; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; +#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 + +BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { + uint8 id; + uint8 len; + uint8 cap[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap_ie dot11_extcap_ie_t; + +#define DOT11_EXTCAP_LEN_MAX 8 + +#define DOT11_EXTCAP_LEN_COEX 1 +#define DOT11_EXTCAP_LEN_BT 3 +#define DOT11_EXTCAP_LEN_IW 4 +#define DOT11_EXTCAP_LEN_SI 6 + +#define DOT11_EXTCAP_LEN_TDLS 5 +#define DOT11_11AC_EXTCAP_LEN_TDLS 8 + +#define DOT11_EXTCAP_LEN_FMS 2 +#define DOT11_EXTCAP_LEN_PROXY_ARP 2 +#define DOT11_EXTCAP_LEN_TFS 3 +#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 +#define DOT11_EXTCAP_LEN_TIMBC 3 +#define DOT11_EXTCAP_LEN_BSSTRANS 3 +#define DOT11_EXTCAP_LEN_DMS 4 +#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 +#define DOT11_EXTCAP_LEN_TDLS_WBW 8 +#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 + +BWL_PRE_PACKED_STRUCT struct dot11_extcap { + uint8 extcap[DOT11_EXTCAP_LEN_MAX]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap dot11_extcap_t; + + +#define DOT11_TDLS_CAP_TDLS 37 +#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 +#define DOT11_TDLS_CAP_PEER_PSM 20 +#define DOT11_TDLS_CAP_CH_SW 30 +#define DOT11_TDLS_CAP_PROH 38 +#define DOT11_TDLS_CAP_CH_SW_PROH 39 +#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 + +#define TDLS_CAP_MAX_BIT 39 + + + +#define DOT11_MEASURE_TYPE_BASIC 0 +#define DOT11_MEASURE_TYPE_CCA 1 +#define DOT11_MEASURE_TYPE_RPI 2 +#define DOT11_MEASURE_TYPE_CHLOAD 3 +#define DOT11_MEASURE_TYPE_NOISE 4 +#define DOT11_MEASURE_TYPE_BEACON 5 +#define DOT11_MEASURE_TYPE_FRAME 6 +#define DOT11_MEASURE_TYPE_STAT 7 +#define DOT11_MEASURE_TYPE_LCI 8 +#define DOT11_MEASURE_TYPE_TXSTREAM 9 +#define DOT11_MEASURE_TYPE_PAUSE 255 + + +#define DOT11_MEASURE_MODE_PARALLEL (1<<0) +#define DOT11_MEASURE_MODE_ENABLE (1<<1) +#define DOT11_MEASURE_MODE_REQUEST (1<<2) +#define DOT11_MEASURE_MODE_REPORT (1<<3) +#define DOT11_MEASURE_MODE_DUR (1<<4) + +#define DOT11_MEASURE_MODE_LATE (1<<0) +#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) +#define DOT11_MEASURE_MODE_REFUSED (1<<2) + +#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) +#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) +#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) +#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) +#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) + +BWL_PRE_PACKED_STRUCT struct dot11_meas_req { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 channel; + uint8 start_time[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_req dot11_meas_req_t; +#define DOT11_MNG_IE_MREQ_LEN 14 + +#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + BWL_PRE_PACKED_STRUCT union + { + BWL_PRE_PACKED_STRUCT struct { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; + } BWL_POST_PACKED_STRUCT basic; + uint8 data[1]; + } BWL_POST_PACKED_STRUCT rep; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_rep dot11_meas_rep_t; + + +#define DOT11_MNG_IE_MREP_FIXED_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; +#define DOT11_MEASURE_BASIC_REP_LEN 12 + +BWL_PRE_PACKED_STRUCT struct dot11_quiet { + uint8 id; + uint8 len; + uint8 count; + uint8 period; + uint16 duration; + uint16 offset; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_quiet dot11_quiet_t; + +BWL_PRE_PACKED_STRUCT struct chan_map_tuple { + uint8 channel; + uint8 map; +} BWL_POST_PACKED_STRUCT; +typedef struct chan_map_tuple chan_map_tuple_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { + uint8 id; + uint8 len; + uint8 eaddr[ETHER_ADDR_LEN]; + uint8 interval; + chan_map_tuple_t map[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; + + +#define WME_OUI "\x00\x50\xf2" +#define WME_OUI_LEN 3 +#define WME_OUI_TYPE 2 +#define WME_TYPE 2 +#define WME_SUBTYPE_IE 0 +#define WME_SUBTYPE_PARAM_IE 1 +#define WME_SUBTYPE_TSPEC 2 +#define WME_VER 1 + + +#define AC_BE 0 +#define AC_BK 1 +#define AC_VI 2 +#define AC_VO 3 +#define AC_COUNT 4 + +typedef uint8 ac_bitmap_t; + +#define AC_BITMAP_NONE 0x0 +#define AC_BITMAP_ALL 0xf +#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) +#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) +#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) + + +BWL_PRE_PACKED_STRUCT struct wme_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_ie wme_ie_t; +#define WME_IE_LEN 7 + +BWL_PRE_PACKED_STRUCT struct edcf_acparam { + uint8 ACI; + uint8 ECW; + uint16 TXOP; +} BWL_POST_PACKED_STRUCT; +typedef struct edcf_acparam edcf_acparam_t; + + +BWL_PRE_PACKED_STRUCT struct wme_param_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct wme_param_ie wme_param_ie_t; +#define WME_PARAM_IE_LEN 24 + + +#define WME_QI_AP_APSD_MASK 0x80 +#define WME_QI_AP_APSD_SHIFT 7 +#define WME_QI_AP_COUNT_MASK 0x0f +#define WME_QI_AP_COUNT_SHIFT 0 + + +#define WME_QI_STA_MAXSPLEN_MASK 0x60 +#define WME_QI_STA_MAXSPLEN_SHIFT 5 +#define WME_QI_STA_APSD_ALL_MASK 0xf +#define WME_QI_STA_APSD_ALL_SHIFT 0 +#define WME_QI_STA_APSD_BE_MASK 0x8 +#define WME_QI_STA_APSD_BE_SHIFT 3 +#define WME_QI_STA_APSD_BK_MASK 0x4 +#define WME_QI_STA_APSD_BK_SHIFT 2 +#define WME_QI_STA_APSD_VI_MASK 0x2 +#define WME_QI_STA_APSD_VI_SHIFT 1 +#define WME_QI_STA_APSD_VO_MASK 0x1 +#define WME_QI_STA_APSD_VO_SHIFT 0 + + +#define EDCF_AIFSN_MIN 1 +#define EDCF_AIFSN_MAX 15 +#define EDCF_AIFSN_MASK 0x0f +#define EDCF_ACM_MASK 0x10 +#define EDCF_ACI_MASK 0x60 +#define EDCF_ACI_SHIFT 5 +#define EDCF_AIFSN_SHIFT 12 + + +#define EDCF_ECW_MIN 0 +#define EDCF_ECW_MAX 15 +#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) +#define EDCF_ECWMIN_MASK 0x0f +#define EDCF_ECWMAX_MASK 0xf0 +#define EDCF_ECWMAX_SHIFT 4 + + +#define EDCF_TXOP_MIN 0 +#define EDCF_TXOP_MAX 65535 +#define EDCF_TXOP2USEC(txop) ((txop) << 5) + + +#define NON_EDCF_AC_BE_ACI_STA 0x02 + + +#define EDCF_AC_BE_ACI_STA 0x03 +#define EDCF_AC_BE_ECW_STA 0xA4 +#define EDCF_AC_BE_TXOP_STA 0x0000 +#define EDCF_AC_BK_ACI_STA 0x27 +#define EDCF_AC_BK_ECW_STA 0xA4 +#define EDCF_AC_BK_TXOP_STA 0x0000 +#define EDCF_AC_VI_ACI_STA 0x42 +#define EDCF_AC_VI_ECW_STA 0x43 +#define EDCF_AC_VI_TXOP_STA 0x005e +#define EDCF_AC_VO_ACI_STA 0x62 +#define EDCF_AC_VO_ECW_STA 0x32 +#define EDCF_AC_VO_TXOP_STA 0x002f + + +#define EDCF_AC_BE_ACI_AP 0x03 +#define EDCF_AC_BE_ECW_AP 0x64 +#define EDCF_AC_BE_TXOP_AP 0x0000 +#define EDCF_AC_BK_ACI_AP 0x27 +#define EDCF_AC_BK_ECW_AP 0xA4 +#define EDCF_AC_BK_TXOP_AP 0x0000 +#define EDCF_AC_VI_ACI_AP 0x41 +#define EDCF_AC_VI_ECW_AP 0x43 +#define EDCF_AC_VI_TXOP_AP 0x005e +#define EDCF_AC_VO_ACI_AP 0x61 +#define EDCF_AC_VO_ECW_AP 0x32 +#define EDCF_AC_VO_TXOP_AP 0x002f + + +BWL_PRE_PACKED_STRUCT struct edca_param_ie { + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} BWL_POST_PACKED_STRUCT; +typedef struct edca_param_ie edca_param_ie_t; +#define EDCA_PARAM_IE_LEN 18 + + +BWL_PRE_PACKED_STRUCT struct qos_cap_ie { + uint8 qosinfo; +} BWL_POST_PACKED_STRUCT; +typedef struct qos_cap_ie qos_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { + uint8 id; + uint8 length; + uint16 station_count; + uint8 channel_utilization; + uint16 aac; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; +#define BSS_LOAD_IE_SIZE 7 + + +#define FIXED_MSDU_SIZE 0x8000 +#define MSDU_SIZE_MASK 0x7fff + + + +#define INTEGER_SHIFT 13 +#define FRACTION_MASK 0x1FFF + + +BWL_PRE_PACKED_STRUCT struct dot11_management_notification { + uint8 category; + uint8 action; + uint8 token; + uint8 status; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +#define DOT11_MGMT_NOTIFICATION_LEN 4 + + +BWL_PRE_PACKED_STRUCT struct ti_ie { + uint8 ti_type; + uint32 ti_val; +} BWL_POST_PACKED_STRUCT; +typedef struct ti_ie ti_ie_t; +#define TI_TYPE_REASSOC_DEADLINE 1 +#define TI_TYPE_KEY_LIFETIME 2 + + +#define WME_ADDTS_REQUEST 0 +#define WME_ADDTS_RESPONSE 1 +#define WME_DELTS_REQUEST 2 + + +#define WME_ADMISSION_ACCEPTED 0 +#define WME_INVALID_PARAMETERS 1 +#define WME_ADMISSION_REFUSED 3 + + +#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) + + +#define DOT11_OPEN_SYSTEM 0 +#define DOT11_SHARED_KEY 1 +#define DOT11_FAST_BSS 2 +#define DOT11_CHALLENGE_LEN 128 + + +#define FC_PVER_MASK 0x3 +#define FC_PVER_SHIFT 0 +#define FC_TYPE_MASK 0xC +#define FC_TYPE_SHIFT 2 +#define FC_SUBTYPE_MASK 0xF0 +#define FC_SUBTYPE_SHIFT 4 +#define FC_TODS 0x100 +#define FC_TODS_SHIFT 8 +#define FC_FROMDS 0x200 +#define FC_FROMDS_SHIFT 9 +#define FC_MOREFRAG 0x400 +#define FC_MOREFRAG_SHIFT 10 +#define FC_RETRY 0x800 +#define FC_RETRY_SHIFT 11 +#define FC_PM 0x1000 +#define FC_PM_SHIFT 12 +#define FC_MOREDATA 0x2000 +#define FC_MOREDATA_SHIFT 13 +#define FC_WEP 0x4000 +#define FC_WEP_SHIFT 14 +#define FC_ORDER 0x8000 +#define FC_ORDER_SHIFT 15 + + +#define SEQNUM_SHIFT 4 +#define SEQNUM_MAX 0x1000 +#define FRAGNUM_MASK 0xF + + + + +#define FC_TYPE_MNG 0 +#define FC_TYPE_CTL 1 +#define FC_TYPE_DATA 2 + + +#define FC_SUBTYPE_ASSOC_REQ 0 +#define FC_SUBTYPE_ASSOC_RESP 1 +#define FC_SUBTYPE_REASSOC_REQ 2 +#define FC_SUBTYPE_REASSOC_RESP 3 +#define FC_SUBTYPE_PROBE_REQ 4 +#define FC_SUBTYPE_PROBE_RESP 5 +#define FC_SUBTYPE_BEACON 8 +#define FC_SUBTYPE_ATIM 9 +#define FC_SUBTYPE_DISASSOC 10 +#define FC_SUBTYPE_AUTH 11 +#define FC_SUBTYPE_DEAUTH 12 +#define FC_SUBTYPE_ACTION 13 +#define FC_SUBTYPE_ACTION_NOACK 14 + + +#define FC_SUBTYPE_CTL_WRAPPER 7 +#define FC_SUBTYPE_BLOCKACK_REQ 8 +#define FC_SUBTYPE_BLOCKACK 9 +#define FC_SUBTYPE_PS_POLL 10 +#define FC_SUBTYPE_RTS 11 +#define FC_SUBTYPE_CTS 12 +#define FC_SUBTYPE_ACK 13 +#define FC_SUBTYPE_CF_END 14 +#define FC_SUBTYPE_CF_END_ACK 15 + + +#define FC_SUBTYPE_DATA 0 +#define FC_SUBTYPE_DATA_CF_ACK 1 +#define FC_SUBTYPE_DATA_CF_POLL 2 +#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 +#define FC_SUBTYPE_NULL 4 +#define FC_SUBTYPE_CF_ACK 5 +#define FC_SUBTYPE_CF_POLL 6 +#define FC_SUBTYPE_CF_ACK_POLL 7 +#define FC_SUBTYPE_QOS_DATA 8 +#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 +#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 +#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 +#define FC_SUBTYPE_QOS_NULL 12 +#define FC_SUBTYPE_QOS_CF_POLL 14 +#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 + + +#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) +#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) +#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) +#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) +#define FC_SUBTYPE_ANY_PSPOLL(s) (((s) & 10) != 0) + + +#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) + +#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) + +#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) +#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) + +#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) +#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) +#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) +#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) +#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) +#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) +#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) +#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) +#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) +#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) +#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) +#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) + +#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) +#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) +#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) +#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) +#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) +#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) +#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) +#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) +#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) + +#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) +#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) +#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) +#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) +#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) + + + + +#define QOS_PRIO_SHIFT 0 +#define QOS_PRIO_MASK 0x0007 +#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) + + +#define QOS_TID_SHIFT 0 +#define QOS_TID_MASK 0x000f +#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) + + +#define QOS_EOSP_SHIFT 4 +#define QOS_EOSP_MASK 0x0010 +#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) + + +#define QOS_ACK_NORMAL_ACK 0 +#define QOS_ACK_NO_ACK 1 +#define QOS_ACK_NO_EXP_ACK 2 +#define QOS_ACK_BLOCK_ACK 3 +#define QOS_ACK_SHIFT 5 +#define QOS_ACK_MASK 0x0060 +#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) + + +#define QOS_AMSDU_SHIFT 7 +#define QOS_AMSDU_MASK 0x0080 + + + + + + +#define DOT11_MNG_AUTH_ALGO_LEN 2 +#define DOT11_MNG_AUTH_SEQ_LEN 2 +#define DOT11_MNG_BEACON_INT_LEN 2 +#define DOT11_MNG_CAP_LEN 2 +#define DOT11_MNG_AP_ADDR_LEN 6 +#define DOT11_MNG_LISTEN_INT_LEN 2 +#define DOT11_MNG_REASON_LEN 2 +#define DOT11_MNG_AID_LEN 2 +#define DOT11_MNG_STATUS_LEN 2 +#define DOT11_MNG_TIMESTAMP_LEN 8 + + +#define DOT11_AID_MASK 0x3fff + + +#define DOT11_RC_RESERVED 0 +#define DOT11_RC_UNSPECIFIED 1 +#define DOT11_RC_AUTH_INVAL 2 +#define DOT11_RC_DEAUTH_LEAVING 3 +#define DOT11_RC_INACTIVITY 4 +#define DOT11_RC_BUSY 5 +#define DOT11_RC_INVAL_CLASS_2 6 +#define DOT11_RC_INVAL_CLASS_3 7 +#define DOT11_RC_DISASSOC_LEAVING 8 +#define DOT11_RC_NOT_AUTH 9 +#define DOT11_RC_BAD_PC 10 +#define DOT11_RC_BAD_CHANNELS 11 + + + +#define DOT11_RC_UNSPECIFIED_QOS 32 +#define DOT11_RC_INSUFFCIENT_BW 33 +#define DOT11_RC_EXCESSIVE_FRAMES 34 +#define DOT11_RC_TX_OUTSIDE_TXOP 35 +#define DOT11_RC_LEAVING_QBSS 36 +#define DOT11_RC_BAD_MECHANISM 37 +#define DOT11_RC_SETUP_NEEDED 38 +#define DOT11_RC_TIMEOUT 39 + +#define DOT11_RC_MAX 23 + +#define DOT11_RC_TDLS_PEER_UNREACH 25 +#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 + + +#define DOT11_SC_SUCCESS 0 +#define DOT11_SC_FAILURE 1 +#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 + +#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 +#define DOT11_SC_TDLS_SEC_DISABLED 5 +#define DOT11_SC_LIFETIME_REJ 6 +#define DOT11_SC_NOT_SAME_BSS 7 +#define DOT11_SC_CAP_MISMATCH 10 +#define DOT11_SC_REASSOC_FAIL 11 +#define DOT11_SC_ASSOC_FAIL 12 +#define DOT11_SC_AUTH_MISMATCH 13 +#define DOT11_SC_AUTH_SEQ 14 +#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 +#define DOT11_SC_AUTH_TIMEOUT 16 +#define DOT11_SC_ASSOC_BUSY_FAIL 17 +#define DOT11_SC_ASSOC_RATE_MISMATCH 18 +#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 +#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 +#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 +#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 +#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 +#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 +#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 +#define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 26 +#define DOT11_SC_ASSOC_HT_REQUIRED 27 +#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 +#define DOT11_SC_ASSOC_TRY_LATER 30 +#define DOT11_SC_ASSOC_MFP_VIOLATION 31 + +#define DOT11_SC_DECLINED 37 +#define DOT11_SC_INVALID_PARAMS 38 +#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 +#define DOT11_SC_INVALID_AKMP 43 +#define DOT11_SC_INVALID_RSNIE_CAP 45 +#define DOT11_SC_DLS_NOT_ALLOWED 48 +#define DOT11_SC_INVALID_PMKID 53 +#define DOT11_SC_INVALID_MDID 54 +#define DOT11_SC_INVALID_FTIE 55 + +#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 +#define DOT11_SC_NO_OUTSTAND_REQ 60 +#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 +#define DOT11_SC_TIMEOUT 62 +#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 +#define DOT11_SC_SERVER_UNREACHABLE 65 + +#define DOT11_SC_UNEXP_MSG 70 +#define DOT11_SC_INVALID_SNONCE 71 +#define DOT11_SC_INVALID_RSNIE 72 +#define DOT11_SC_ASSOC_VHT_REQUIRED 104 + +#define DOT11_SC_TRANSMIT_FAILURE 79 + + +#define DOT11_MNG_DS_PARAM_LEN 1 +#define DOT11_MNG_IBSS_PARAM_LEN 2 + + +#define DOT11_MNG_TIM_FIXED_LEN 3 +#define DOT11_MNG_TIM_DTIM_COUNT 0 +#define DOT11_MNG_TIM_DTIM_PERIOD 1 +#define DOT11_MNG_TIM_BITMAP_CTL 2 +#define DOT11_MNG_TIM_PVB 3 + + +#define TLV_TAG_OFF 0 +#define TLV_LEN_OFF 1 +#define TLV_HDR_LEN 2 +#define TLV_BODY_OFF 2 +#define TLV_BODY_LEN_MAX 255 + + +#define DOT11_MNG_SSID_ID 0 +#define DOT11_MNG_RATES_ID 1 +#define DOT11_MNG_FH_PARMS_ID 2 +#define DOT11_MNG_DS_PARMS_ID 3 +#define DOT11_MNG_CF_PARMS_ID 4 +#define DOT11_MNG_TIM_ID 5 +#define DOT11_MNG_IBSS_PARMS_ID 6 +#define DOT11_MNG_COUNTRY_ID 7 +#define DOT11_MNG_HOPPING_PARMS_ID 8 +#define DOT11_MNG_HOPPING_TABLE_ID 9 +#define DOT11_MNG_REQUEST_ID 10 +#define DOT11_MNG_QBSS_LOAD_ID 11 +#define DOT11_MNG_EDCA_PARAM_ID 12 +#define DOT11_MNG_TSPEC_ID 13 +#define DOT11_MNG_TCLAS_ID 14 +#define DOT11_MNG_CHALLENGE_ID 16 +#define DOT11_MNG_PWR_CONSTRAINT_ID 32 +#define DOT11_MNG_PWR_CAP_ID 33 +#define DOT11_MNG_TPC_REQUEST_ID 34 +#define DOT11_MNG_TPC_REPORT_ID 35 +#define DOT11_MNG_SUPP_CHANNELS_ID 36 +#define DOT11_MNG_CHANNEL_SWITCH_ID 37 +#define DOT11_MNG_MEASURE_REQUEST_ID 38 +#define DOT11_MNG_MEASURE_REPORT_ID 39 +#define DOT11_MNG_QUIET_ID 40 +#define DOT11_MNG_IBSS_DFS_ID 41 +#define DOT11_MNG_ERP_ID 42 +#define DOT11_MNG_TS_DELAY_ID 43 +#define DOT11_MNG_TCLAS_PROC_ID 44 +#define DOT11_MNG_HT_CAP 45 +#define DOT11_MNG_QOS_CAP_ID 46 +#define DOT11_MNG_NONERP_ID 47 +#define DOT11_MNG_RSN_ID 48 +#define DOT11_MNG_EXT_RATES_ID 50 +#define DOT11_MNG_AP_CHREP_ID 51 +#define DOT11_MNG_NEIGHBOR_REP_ID 52 +#define DOT11_MNG_RCPI_ID 53 +#define DOT11_MNG_MDIE_ID 54 +#define DOT11_MNG_FTIE_ID 55 +#define DOT11_MNG_FT_TI_ID 56 +#define DOT11_MNG_RDE_ID 57 +#define DOT11_MNG_REGCLASS_ID 59 +#define DOT11_MNG_EXT_CSA_ID 60 +#define DOT11_MNG_HT_ADD 61 +#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 +#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 +#define DOT11_MNG_ANTENNA_ID 64 +#define DOT11_MNG_RSNI_ID 65 +#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 +#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 +#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 +#define DOT11_MNG_WAPI_ID 68 +#define DOT11_MNG_TIME_ADVERTISE_ID 69 +#define DOT11_MNG_RRM_CAP_ID 70 +#define DOT11_MNG_MULTIPLE_BSSID_ID 71 +#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 +#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 +#define DOT11_MNG_HT_OBSS_ID 74 +#define DOT11_MNG_MMIE_ID 76 +#define DOT11_MNG_FMS_DESCR_ID 86 +#define DOT11_MNG_FMS_REQ_ID 87 +#define DOT11_MNG_FMS_RESP_ID 88 +#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 +#define DOT11_MNG_TFS_REQUEST_ID 91 +#define DOT11_MNG_TFS_RESPONSE_ID 92 +#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 +#define DOT11_MNG_TIMBC_REQ_ID 94 +#define DOT11_MNG_TIMBC_RESP_ID 95 +#define DOT11_MNG_CHANNEL_USAGE 97 +#define DOT11_MNG_TIME_ZONE_ID 98 +#define DOT11_MNG_DMS_REQUEST_ID 99 +#define DOT11_MNG_DMS_RESPONSE_ID 100 +#define DOT11_MNG_LINK_IDENTIFIER_ID 101 +#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 +#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 +#define DOT11_MNG_PTI_CONTROL_ID 105 +#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 +#define DOT11_MNG_INTERWORKING_ID 107 +#define DOT11_MNG_ADVERTISEMENT_ID 108 +#define DOT11_MNG_EXP_BW_REQ_ID 109 +#define DOT11_MNG_QOS_MAP_ID 110 +#define DOT11_MNG_ROAM_CONSORT_ID 111 +#define DOT11_MNG_EMERGCY_ALERT_ID 112 +#define DOT11_MNG_EXT_CAP_ID 127 +#define DOT11_MNG_VHT_CAP_ID 191 +#define DOT11_MNG_VHT_OPERATION_ID 192 +#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 +#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 +#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 +#define DOT11_MNG_AID_ID 197 +#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 + + +#define DOT11_MNG_WPA_ID 221 +#define DOT11_MNG_PROPR_ID 221 + +#define DOT11_MNG_VS_ID 221 + + + + + +#define DOT11_RATE_1M 2 +#define DOT11_RATE_2M 4 +#define DOT11_RATE_5M5 11 +#define DOT11_RATE_11M 22 +#define DOT11_RATE_6M 12 +#define DOT11_RATE_9M 18 +#define DOT11_RATE_12M 24 +#define DOT11_RATE_18M 36 +#define DOT11_RATE_24M 48 +#define DOT11_RATE_36M 72 +#define DOT11_RATE_48M 96 +#define DOT11_RATE_54M 108 +#define DOT11_RATE_MAX 108 + + +#define DOT11_RATE_BASIC 0x80 +#define DOT11_RATE_MASK 0x7F + + +#define DOT11_BSS_MEMBERSHIP_HT 0xFF +#define DOT11_BSS_MEMBERSHIP_VHT 0xFE + + +#define DOT11_MNG_ERP_LEN 1 +#define DOT11_MNG_NONERP_PRESENT 0x01 +#define DOT11_MNG_USE_PROTECTION 0x02 +#define DOT11_MNG_BARKER_PREAMBLE 0x04 + +#define DOT11_MGN_TS_DELAY_LEN 4 +#define TS_DELAY_FIELD_SIZE 4 + + +#define DOT11_CAP_ESS 0x0001 +#define DOT11_CAP_IBSS 0x0002 +#define DOT11_CAP_POLLABLE 0x0004 +#define DOT11_CAP_POLL_RQ 0x0008 +#define DOT11_CAP_PRIVACY 0x0010 +#define DOT11_CAP_SHORT 0x0020 +#define DOT11_CAP_PBCC 0x0040 +#define DOT11_CAP_AGILITY 0x0080 +#define DOT11_CAP_SPECTRUM 0x0100 +#define DOT11_CAP_QOS 0x0200 +#define DOT11_CAP_SHORTSLOT 0x0400 +#define DOT11_CAP_APSD 0x0800 +#define DOT11_CAP_RRM 0x1000 +#define DOT11_CAP_CCK_OFDM 0x2000 +#define DOT11_CAP_DELAY_BA 0x4000 +#define DOT11_CAP_IMMEDIATE_BA 0x8000 + + + +#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 + +#define DOT11_EXT_CAP_EXT_CHAN_SWITCHING 2 + +#define DOT11_EXT_CAP_SPSMP 6 + +#define DOT11_EXT_CAP_FMS 11 + +#define DOT11_EXT_CAP_PROXY_ARP 12 + +#define DOT11_EXT_CAP_TFS 16 + +#define DOT11_EXT_CAP_WNM_SLEEP 17 + +#define DOT11_EXT_CAP_TIMBC 18 + +#define DOT11_EXT_CAP_BSSTRANS_MGMT 19 + +#define DOT11_EXT_CAP_DMS 26 + +#define DOT11_EXT_CAP_IW 31 + +#define DOT11_EXT_CAP_SI 41 +#define DOT11_EXT_CAP_SI_MASK 0x0E + +#define DOT11_EXT_CAP_WNM_NOTIF 46 + +#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62 + + +#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 +#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 +#define DOT11_OPER_MODE_RXNSS_SHIFT 4 +#define DOT11_OPER_MODE_RXNSS_MASK 0x70 +#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 +#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 + +#define DOT11_OPER_MODE(type, nss, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ + (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ + >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) +#define DOT11_OPER_MODE_RXNSS(mode) \ + ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ + >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) +#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ + (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ + >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) + +#define DOT11_OPER_MODE_20MHZ 0 +#define DOT11_OPER_MODE_40MHZ 1 +#define DOT11_OPER_MODE_80MHZ 2 +#define DOT11_OPER_MODE_160MHZ 3 +#define DOT11_OPER_MODE_8080MHZ 3 + +#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ) + + +BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { + uint8 mode; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; + +#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 + + +#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 + + +#define DOT11_ACTION_HDR_LEN 2 +#define DOT11_ACTION_CAT_OFF 0 +#define DOT11_ACTION_ACT_OFF 1 + + +#define DOT11_ACTION_CAT_ERR_MASK 0x80 +#define DOT11_ACTION_CAT_MASK 0x7F +#define DOT11_ACTION_CAT_SPECT_MNG 0 +#define DOT11_ACTION_CAT_QOS 1 +#define DOT11_ACTION_CAT_DLS 2 +#define DOT11_ACTION_CAT_BLOCKACK 3 +#define DOT11_ACTION_CAT_PUBLIC 4 +#define DOT11_ACTION_CAT_RRM 5 +#define DOT11_ACTION_CAT_FBT 6 +#define DOT11_ACTION_CAT_HT 7 +#define DOT11_ACTION_CAT_SA_QUERY 8 +#define DOT11_ACTION_CAT_PDPA 9 +#define DOT11_ACTION_CAT_WNM 10 +#define DOT11_ACTION_CAT_UWNM 11 +#define DOT11_ACTION_NOTIFICATION 17 +#define DOT11_ACTION_CAT_VHT 21 +#define DOT11_ACTION_CAT_VSP 126 +#define DOT11_ACTION_CAT_VS 127 + + +#define DOT11_SM_ACTION_M_REQ 0 +#define DOT11_SM_ACTION_M_REP 1 +#define DOT11_SM_ACTION_TPC_REQ 2 +#define DOT11_SM_ACTION_TPC_REP 3 +#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 +#define DOT11_SM_ACTION_EXT_CSA 5 + + +#define DOT11_ACTION_ID_HT_CH_WIDTH 0 +#define DOT11_ACTION_ID_HT_MIMO_PS 1 + + +#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 +#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 +#define DOT11_PUB_ACTION_GAS_CB_REQ 12 + + +#define DOT11_BA_ACTION_ADDBA_REQ 0 +#define DOT11_BA_ACTION_ADDBA_RESP 1 +#define DOT11_BA_ACTION_DELBA 2 + + +#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 +#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 +#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 +#define DOT11_ADDBA_PARAM_TID_MASK 0x003c +#define DOT11_ADDBA_PARAM_TID_SHIFT 2 +#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 +#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 + +#define DOT11_ADDBA_POLICY_DELAYED 0 +#define DOT11_ADDBA_POLICY_IMMEDIATE 1 + + +#define DOT11_FT_ACTION_FT_RESERVED 0 +#define DOT11_FT_ACTION_FT_REQ 1 +#define DOT11_FT_ACTION_FT_RES 2 +#define DOT11_FT_ACTION_FT_CON 3 +#define DOT11_FT_ACTION_FT_ACK 4 + + +#define DOT11_DLS_ACTION_REQ 0 +#define DOT11_DLS_ACTION_RESP 1 +#define DOT11_DLS_ACTION_TD 2 + + +#define DOT11_WNM_ACTION_EVENT_REQ 0 +#define DOT11_WNM_ACTION_EVENT_REP 1 +#define DOT11_WNM_ACTION_DIAG_REQ 2 +#define DOT11_WNM_ACTION_DIAG_REP 3 +#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 +#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 +#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 +#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 +#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 +#define DOT11_WNM_ACTION_FMS_REQ 9 +#define DOT11_WNM_ACTION_FMS_RESP 10 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 +#define DOT11_WNM_ACTION_TFS_REQ 13 +#define DOT11_WNM_ACTION_TFS_RESP 14 +#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15 +#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 +#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 +#define DOT11_WNM_ACTION_TIMBC_REQ 18 +#define DOT11_WNM_ACTION_TIMBC_RESP 19 +#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 +#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 +#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 +#define DOT11_WNM_ACTION_DMS_REQ 23 +#define DOT11_WNM_ACTION_DMS_RESP 24 +#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 +#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 +#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 +#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28 + + +#define DOT11_UWNM_ACTION_TIM 0 +#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 + +#define DOT11_MNG_COUNTRY_ID_LEN 3 + + +#define DOT11_VHT_ACTION_CBF 0 +#define DOT11_VHT_ACTION_GID_MGMT 1 +#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 + + +BWL_PRE_PACKED_STRUCT struct dot11_dls_req { + uint8 category; + uint8 action; + struct ether_addr da; + struct ether_addr sa; + uint16 cap; + uint16 timeout; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dls_req dot11_dls_req_t; +#define DOT11_DLS_REQ_LEN 18 + + +BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { + uint8 category; + uint8 action; + uint16 status; + struct ether_addr da; + struct ether_addr sa; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dls_resp dot11_dls_resp_t; +#define DOT11_DLS_RESP_LEN 16 + + + + + +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { + uint8 category; + uint8 action; + uint8 token; + uint8 reason; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; +#define DOT11_BSSTRANS_QUERY_LEN 4 + + +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { + uint8 category; + uint8 action; + uint8 token; + uint8 reqmode; + uint16 disassoc_tmr; + uint8 validity_intrvl; + uint8 data[1]; + +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; +#define DOT11_BSSTRANS_REQ_LEN 7 + + +#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 +#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 +#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 +#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 +#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 + + +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { + uint8 category; + uint8 action; + uint8 token; + uint8 status; + uint8 term_delay; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; +#define DOT11_BSSTRANS_RESP_LEN 5 + + +#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 +#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 + + + +BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { + uint8 id; + uint8 len; + uint16 max_idle_period; + uint8 idle_opt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; +#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 +#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 + + +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { + uint8 id; + uint8 len; + uint8 interval; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; +#define DOT11_TIMBC_REQ_IE_LEN 1 + + +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req dot11_timbc_req_t; +#define DOT11_TIMBC_REQ_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { + uint8 id; + uint8 len; + uint8 status; + uint8 interval; + int32 offset; + uint16 high_rate; + uint16 low_rate; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; +#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 +#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 + +#define DOT11_TIMBC_STATUS_ACCEPT 0 +#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 +#define DOT11_TIMBC_STATUS_DENY 2 +#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 +#define DOT11_TIMBC_STATUS_RESERVED 4 + + +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp dot11_timbc_resp_t; +#define DOT11_TIMBC_RESP_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { + uint8 id; + uint8 len; + uint8 dtim_count; + uint8 dtim_period; + uint8 bitmap_control; + uint8 pvb[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tim_ie dot11_tim_ie_t; +#define DOT11_TIM_IE_FIXED_LEN 3 +#define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 + + +BWL_PRE_PACKED_STRUCT struct dot11_timbc { + uint8 category; + uint8 action; + uint8 check_beacon; + uint8 tsf[8]; + dot11_tim_ie_t tim_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc dot11_timbc_t; +#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) +#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) +#define DOT11_TIMBC_LEN 11 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { + uint8 type; + uint8 mask; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; +#define DOT11_TCLAS_FC_HDR_LEN 2 + +#define DOT11_TCLAS_MASK_0 0x1 +#define DOT11_TCLAS_MASK_1 0x2 +#define DOT11_TCLAS_MASK_2 0x4 +#define DOT11_TCLAS_MASK_3 0x8 +#define DOT11_TCLAS_MASK_4 0x10 +#define DOT11_TCLAS_MASK_5 0x20 +#define DOT11_TCLAS_MASK_6 0x40 +#define DOT11_TCLAS_MASK_7 0x80 + +#define DOT11_TCLAS_FC_0_ETH 0 +#define DOT11_TCLAS_FC_1_IP 1 +#define DOT11_TCLAS_FC_2_8021Q 2 +#define DOT11_TCLAS_FC_3_OFFSET 3 +#define DOT11_TCLAS_FC_4_IP_HIGHER 4 +#define DOT11_TCLAS_FC_5_8021D 5 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { + uint8 type; + uint8 mask; + uint8 sa[ETHER_ADDR_LEN]; + uint8 da[ETHER_ADDR_LEN]; + uint16 eth_type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; +#define DOT11_TCLAS_FC_0_ETH_LEN 16 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { + uint8 type; + uint8 mask; + uint8 version; + uint32 src_ip; + uint32 dst_ip; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 protocol; + uint8 reserved; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; +#define DOT11_TCLAS_FC_1_IPV4_LEN 18 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { + uint8 type; + uint8 mask; + uint16 tci; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; +#define DOT11_TCLAS_FC_2_8021Q_LEN 4 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { + uint8 type; + uint8 mask; + uint16 offset; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; +#define DOT11_TCLAS_FC_3_FILTER_LEN 4 + + +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; +#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { + uint8 type; + uint8 mask; + uint8 version; + uint8 saddr[16]; + uint8 daddr[16]; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 nexthdr; + uint8 flow_lbl[3]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; +#define DOT11_TCLAS_FC_4_IPV6_LEN 44 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { + uint8 type; + uint8 mask; + uint8 pcp; + uint8 cfi; + uint16 vid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; +#define DOT11_TCLAS_FC_5_8021D_LEN 6 + + +BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { + uint8 data[1]; + dot11_tclas_fc_hdr_t hdr; + dot11_tclas_fc_0_eth_t t0_eth; + dot11_tclas_fc_1_ipv4_t t1_ipv4; + dot11_tclas_fc_2_8021q_t t2_8021q; + dot11_tclas_fc_3_filter_t t3_filter; + dot11_tclas_fc_4_ipv4_t t4_ipv4; + dot11_tclas_fc_4_ipv6_t t4_ipv6; + dot11_tclas_fc_5_8021d_t t5_8021d; +} BWL_POST_PACKED_STRUCT; +typedef union dot11_tclas_fc dot11_tclas_fc_t; + +#define DOT11_TCLAS_FC_MIN_LEN 4 +#define DOT11_TCLAS_FC_MAX_LEN 254 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { + uint8 id; + uint8 len; + uint8 user_priority; + dot11_tclas_fc_t fc; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_ie dot11_tclas_ie_t; +#define DOT11_TCLAS_IE_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { + uint8 id; + uint8 len; + uint8 process; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; +#define DOT11_TCLAS_PROC_IE_LEN 3 + +#define DOT11_TCLAS_PROC_MATCHALL 0 +#define DOT11_TCLAS_PROC_MATCHONE 1 +#define DOT11_TCLAS_PROC_NONMATCH 2 + + + +#define DOT11_TSPEC_IE_LEN 57 + + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { + uint8 id; + uint8 len; + uint8 tfs_id; + uint8 actcode; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; +#define DOT11_TFS_REQ_IE_LEN 2 + + +#define DOT11_TFS_ACTCODE_DELETE 1 +#define DOT11_TFS_ACTCODE_NOTIFY 2 + + +#define DOT11_TFS_REQ_TFS_SE_ID 1 +#define DOT11_TFS_REQ_VENDOR_SE_ID 221 + + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { + uint8 sub_id; + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_se dot11_tfs_se_t; + + + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { + uint8 id; + uint8 len; + uint8 tfs_id; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; +#define DOT11_TFS_RESP_IE_LEN 1 + + +#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1 +#define DOT11_TFS_RESP_TFS_SE_ID 2 +#define DOT11_TFS_RESP_VENDOR_SE_ID 221 + + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { + uint8 sub_id; + uint8 len; + uint8 resp_st; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; +#define DOT11_TFS_STATUS_SE_LEN 1 + + + +#define DOT11_TFS_STATUS_ACCEPT 0 +#define DOT11_TFS_STATUS_DENY_FORMAT 1 +#define DOT11_TFS_STATUS_DENY_RESOURCE 2 +#define DOT11_TFS_STATUS_DENY_POLICY 4 +#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5 +#define DOT11_TFS_STATUS_ALTPREF_POLICY 7 +#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14 + + +#define DOT11_FMS_TFS_STATUS_ACCEPT 0 +#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1 +#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2 +#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3 +#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4 +#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5 +#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6 +#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7 +#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8 +#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9 +#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10 +#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11 +#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12 +#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13 +#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14 + + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req dot11_tfs_req_t; +#define DOT11_TFS_REQ_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp dot11_tfs_resp_t; +#define DOT11_TFS_RESP_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req { + uint8 category; + uint8 action; + uint8 tfs_id_cnt; + uint8 tfs_id[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t; +#define DOT11_TFS_NOTIFY_REQ_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp { + uint8 category; + uint8 action; + uint8 tfs_id_cnt; + uint8 tfs_id[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t; +#define DOT11_TFS_NOTIFY_RESP_LEN 3 + + + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; +#define DOT11_WNM_SLEEP_REQ_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { + uint8 category; + uint8 action; + uint8 token; + uint16 key_len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; +#define DOT11_WNM_SLEEP_RESP_LEN 5 + +#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 +#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { + uint8 sub_id; + uint8 len; + uint16 key_info; + uint8 key_length; + uint8 rsc[8]; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 +#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { + uint8 sub_id; + uint8 len; + uint16 key_id; + uint8 pn[6]; + uint8 key[16]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { + uint8 id; + uint8 len; + uint8 act_type; + uint8 resp_status; + uint16 interval; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; +#define DOT11_WNM_SLEEP_IE_LEN 4 + +#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 +#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 + +#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 +#define DOT11_WNM_SLEEP_RESP_UPDATE 1 +#define DOT11_WNM_SLEEP_RESP_DENY 2 +#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 +#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 +#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 +#define DOT11_WNM_SLEEP_RESP_LAST 6 + + +BWL_PRE_PACKED_STRUCT struct dot11_dms_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req dot11_dms_req_t; +#define DOT11_DMS_REQ_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp dot11_dms_resp_t; +#define DOT11_DMS_RESP_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { + uint8 id; + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; +#define DOT11_DMS_REQ_IE_LEN 2 + + +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { + uint8 id; + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; +#define DOT11_DMS_RESP_IE_LEN 2 + + +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { + uint8 dms_id; + uint8 len; + uint8 type; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; +#define DOT11_DMS_REQ_DESC_LEN 3 + +#define DOT11_DMS_REQ_TYPE_ADD 0 +#define DOT11_DMS_REQ_TYPE_REMOVE 1 +#define DOT11_DMS_REQ_TYPE_CHANGE 2 + + +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { + uint8 dms_id; + uint8 len; + uint8 type; + uint16 lsc; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; +#define DOT11_DMS_RESP_STATUS_LEN 5 + +#define DOT11_DMS_RESP_TYPE_ACCEPT 0 +#define DOT11_DMS_RESP_TYPE_DENY 1 +#define DOT11_DMS_RESP_TYPE_TERM 2 + +#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF + + +BWL_PRE_PACKED_STRUCT struct dot11_fms_req { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_req dot11_fms_req_t; +#define DOT11_FMS_REQ_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_fms_resp { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_resp dot11_fms_resp_t; +#define DOT11_FMS_RESP_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct dot11_fms_desc { + uint8 id; + uint8 len; + uint8 num_fms_cnt; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_desc dot11_fms_desc_t; +#define DOT11_FMS_DESC_LEN 1 + +#define DOT11_FMS_CNTR_MAX 0x8 +#define DOT11_FMS_CNTR_ID_MASK 0x7 +#define DOT11_FMS_CNTR_ID_SHIFT 0x0 +#define DOT11_FMS_CNTR_COUNT_MASK 0xf1 +#define DOT11_FMS_CNTR_SHIFT 0x3 + + +BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie { + uint8 id; + uint8 len; + uint8 fms_token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_req_ie dot11_fms_req_ie_t; +#define DOT11_FMS_REQ_IE_FIX_LEN 1 + +BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field { + uint8 mask; + uint8 mcs_idx; + uint16 rate; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rate_id_field dot11_rate_id_field_t; +#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7 +#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0 +#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18 +#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3 +#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t) + + +BWL_PRE_PACKED_STRUCT struct dot11_fms_se { + uint8 sub_id; + uint8 len; + uint8 interval; + uint8 max_interval; + dot11_rate_id_field_t rate; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_se dot11_fms_se_t; +#define DOT11_FMS_REQ_SE_LEN 6 + +#define DOT11_FMS_REQ_SE_ID_FMS 1 +#define DOT11_FMS_REQ_SE_ID_VS 221 + + +BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie { + uint8 id; + uint8 len; + uint8 fms_token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t; +#define DOT11_FMS_RESP_IE_FIX_LEN 1 + + +#define DOT11_FMS_STATUS_SE_ID_FMS 1 +#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 +#define DOT11_FMS_STATUS_SE_ID_VS 221 + + +BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se { + uint8 sub_id; + uint8 len; + uint8 status; + uint8 interval; + uint8 max_interval; + uint8 fmsid; + uint8 counter; + dot11_rate_id_field_t rate; + uint8 mcast_addr[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_fms_status_se dot11_fms_status_se_t; +#define DOT11_FMS_STATUS_SE_LEN 15 + + +BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se { + uint8 sub_id; + uint8 len; + uint8 fmsid; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_status_se dot11_tclas_status_se_t; +#define DOT11_TCLAS_STATUS_SE_LEN 1 + +BWL_PRE_PACKED_STRUCT struct dot11_addba_req { + uint8 category; + uint8 action; + uint8 token; + uint16 addba_param_set; + uint16 timeout; + uint16 start_seqnum; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_req dot11_addba_req_t; +#define DOT11_ADDBA_REQ_LEN 9 + +BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { + uint8 category; + uint8 action; + uint8 token; + uint16 status; + uint16 addba_param_set; + uint16 timeout; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_resp dot11_addba_resp_t; +#define DOT11_ADDBA_RESP_LEN 9 + + +#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 +#define DOT11_DELBA_PARAM_INIT_SHIFT 11 +#define DOT11_DELBA_PARAM_TID_MASK 0xf000 +#define DOT11_DELBA_PARAM_TID_SHIFT 12 + +BWL_PRE_PACKED_STRUCT struct dot11_delba { + uint8 category; + uint8 action; + uint16 delba_param_set; + uint16 reason; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_delba dot11_delba_t; +#define DOT11_DELBA_LEN 6 + + +#define SA_QUERY_REQUEST 0 +#define SA_QUERY_RESPONSE 1 + + + + +BWL_PRE_PACKED_STRUCT struct dot11_ft_req { + uint8 category; + uint8 action; + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_req dot11_ft_req_t; +#define DOT11_FT_REQ_FIXED_LEN 14 + + +BWL_PRE_PACKED_STRUCT struct dot11_ft_res { + uint8 category; + uint8 action; + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint16 status; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_res dot11_ft_res_t; +#define DOT11_FT_RES_FIXED_LEN 16 + + +BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { + uint8 id; + uint8 length; + uint8 rde_id; + uint8 rd_count; + uint16 status; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rde_ie dot11_rde_ie_t; + + +#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) + + + + + +#define DOT11_RRM_CAP_LEN 5 +#define RCPI_IE_LEN 1 +#define RSNI_IE_LEN 1 +BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { + uint8 cap[DOT11_RRM_CAP_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; + + +#define DOT11_RRM_CAP_LINK 0 +#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 +#define DOT11_RRM_CAP_PARALLEL 2 +#define DOT11_RRM_CAP_REPEATED 3 +#define DOT11_RRM_CAP_BCN_PASSIVE 4 +#define DOT11_RRM_CAP_BCN_ACTIVE 5 +#define DOT11_RRM_CAP_BCN_TABLE 6 +#define DOT11_RRM_CAP_BCN_REP_COND 7 +#define DOT11_RRM_CAP_FM 8 +#define DOT11_RRM_CAP_CLM 9 +#define DOT11_RRM_CAP_NHM 10 +#define DOT11_RRM_CAP_SM 11 +#define DOT11_RRM_CAP_LCIM 12 +#define DOT11_RRM_CAP_LCIA 13 +#define DOT11_RRM_CAP_TSCM 14 +#define DOT11_RRM_CAP_TTSCM 15 +#define DOT11_RRM_CAP_AP_CHANREP 16 +#define DOT11_RRM_CAP_RMMIB 17 + +#define DOT11_RRM_CAP_MPTI 27 +#define DOT11_RRM_CAP_NBRTSFO 28 +#define DOT11_RRM_CAP_RCPI 29 +#define DOT11_RRM_CAP_RSNI 30 +#define DOT11_RRM_CAP_BSSAAD 31 +#define DOT11_RRM_CAP_BSSAAC 32 +#define DOT11_RRM_CAP_AI 33 + + +#define DOT11_OP_CLASS_NONE 255 + +BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { + uint8 id; + uint8 len; + uint8 reg; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct do11_ap_chrep dot11_ap_chrep_t; + + +#define DOT11_RM_ACTION_RM_REQ 0 +#define DOT11_RM_ACTION_RM_REP 1 +#define DOT11_RM_ACTION_LM_REQ 2 +#define DOT11_RM_ACTION_LM_REP 3 +#define DOT11_RM_ACTION_NR_REQ 4 +#define DOT11_RM_ACTION_NR_REP 5 + + +BWL_PRE_PACKED_STRUCT struct dot11_rm_action { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_action dot11_rm_action_t; +#define DOT11_RM_ACTION_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq { + uint8 category; + uint8 action; + uint8 token; + uint16 reps; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq dot11_rmreq_t; +#define DOT11_RMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_ie dot11_rm_ie_t; +#define DOT11_RM_IE_LEN 5 + + +#define DOT11_RMREQ_MODE_PARALLEL 1 +#define DOT11_RMREQ_MODE_ENABLE 2 +#define DOT11_RMREQ_MODE_REQUEST 4 +#define DOT11_RMREQ_MODE_REPORT 8 +#define DOT11_RMREQ_MODE_DURMAND 0x10 + + +#define DOT11_RMREP_MODE_LATE 1 +#define DOT11_RMREP_MODE_INCAPABLE 2 +#define DOT11_RMREP_MODE_REFUSED 4 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 bcn_mode; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; +#define DOT11_RMREQ_BCN_LEN 18 + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 frame_info; + uint8 rcpi; + uint8 rsni; + struct ether_addr bssid; + uint8 antenna_id; + uint32 parent_tsf; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; +#define DOT11_RMREP_BCN_LEN 26 + + +#define DOT11_RMREQ_BCN_PASSIVE 0 +#define DOT11_RMREQ_BCN_ACTIVE 1 +#define DOT11_RMREQ_BCN_TABLE 2 + + +#define DOT11_RMREQ_BCN_SSID_ID 0 +#define DOT11_RMREQ_BCN_REPINFO_ID 1 +#define DOT11_RMREQ_BCN_REPDET_ID 2 +#define DOT11_RMREQ_BCN_REQUEST_ID 10 +#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID + + +#define DOT11_RMREQ_BCN_REPDET_FIXED 0 +#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 +#define DOT11_RMREQ_BCN_REPDET_ALL 2 + + +#define DOT11_RMREP_BCN_FRM_BODY 1 + + +#define DOT11_RMREP_FRAME_COUNT_REPORT 1 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; +#define DOT11_RMREQ_CHANLOAD_LEN 11 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 channel_load; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; +#define DOT11_RMREP_CHANLOAD_LEN 13 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; +#define DOT11_RMREQ_NOISE_LEN 11 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 antid; + uint8 anpi; + uint8 ipi0_dens; + uint8 ipi1_dens; + uint8 ipi2_dens; + uint8 ipi3_dens; + uint8 ipi4_dens; + uint8 ipi5_dens; + uint8 ipi6_dens; + uint8 ipi7_dens; + uint8 ipi8_dens; + uint8 ipi9_dens; + uint8 ipi10_dens; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; +#define DOT11_RMREP_NOISE_LEN 25 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 req_type; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; +#define DOT11_RMREQ_FRAME_LEN 18 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; +#define DOT11_RMREP_FRAME_LEN 12 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { + struct ether_addr ta; + struct ether_addr bssid; + uint8 phy_type; + uint8 avg_rcpi; + uint8 last_rsni; + uint8 last_rcpi; + uint8 ant_id; + uint16 frame_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; +#define DOT11_RMREP_FRMENTRY_LEN 19 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + struct ether_addr peer; + uint16 interval; + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; +#define DOT11_RMREQ_STAT_LEN 16 + + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; + + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 interval; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 bin0_range; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; + + +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { + uint32 starttime[2]; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 reason; + uint32 txmsdu_cnt; + uint32 msdu_discarded_cnt; + uint32 msdufailed_cnt; + uint32 msduretry_cnt; + uint32 cfpolls_lost_cnt; + uint32 avrqueue_delay; + uint32 avrtx_delay; + uint8 bin0_range; + uint32 bin0; + uint32 bin1; + uint32 bin2; + uint32 bin3; + uint32 bin4; + uint32 bin5; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; + + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 pause_time; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; + + + +#define DOT11_NGBR_TSF_INFO_SE_ID 1 +#define DOT11_NGBR_CCS_SE_ID 2 +#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 +#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 +#define DOT11_NGBR_BEARING_SE_ID 5 + + +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { + uint8 sub_id; + uint8 len; + uint8 preference; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; +#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 + + +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { + uint8 sub_id; + uint8 len; + uint8 tsf[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; +#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 + + +#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 +#define DOT11_NGBR_BI_REACHABILTY 0x0003 +#define DOT11_NGBR_BI_SEC 0x0004 +#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 +#define DOT11_NGBR_BI_CAP 0x03f0 +#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 +#define DOT11_NGBR_BI_CAP_QOS 0x0020 +#define DOT11_NGBR_BI_CAP_APSD 0x0040 +#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 +#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 +#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 +#define DOT11_NGBR_BI_MOBILITY 0x0400 +#define DOT11_NGBR_BI_HT 0x0800 + + +BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; + uint8 channel; + uint8 phytype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; +#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13 + + + +#define DOT11_BSSTYPE_INFRASTRUCTURE 0 +#define DOT11_BSSTYPE_INDEPENDENT 1 +#define DOT11_BSSTYPE_ANY 2 +#define DOT11_SCANTYPE_ACTIVE 0 +#define DOT11_SCANTYPE_PASSIVE 1 + + +BWL_PRE_PACKED_STRUCT struct dot11_lmreq { + uint8 category; + uint8 action; + uint8 token; + uint8 txpwr; + uint8 maxtxpwr; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmreq dot11_lmreq_t; +#define DOT11_LMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_lmrep { + uint8 category; + uint8 action; + uint8 token; + dot11_tpc_rep_t tpc; + uint8 rxant; + uint8 txant; + uint8 rcpi; + uint8 rsni; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmrep dot11_lmrep_t; +#define DOT11_LMREP_LEN 11 + + +#define PREN_PREAMBLE 24 +#define PREN_MM_EXT 12 +#define PREN_PREAMBLE_EXT 4 + + +#define RIFS_11N_TIME 2 + + + +#define HT_SIG1_MCS_MASK 0x00007F +#define HT_SIG1_CBW 0x000080 +#define HT_SIG1_HT_LENGTH 0xFFFF00 + + +#define HT_SIG2_SMOOTHING 0x000001 +#define HT_SIG2_NOT_SOUNDING 0x000002 +#define HT_SIG2_RESERVED 0x000004 +#define HT_SIG2_AGGREGATION 0x000008 +#define HT_SIG2_STBC_MASK 0x000030 +#define HT_SIG2_STBC_SHIFT 4 +#define HT_SIG2_FEC_CODING 0x000040 +#define HT_SIG2_SHORT_GI 0x000080 +#define HT_SIG2_ESS_MASK 0x000300 +#define HT_SIG2_ESS_SHIFT 8 +#define HT_SIG2_CRC 0x03FC00 +#define HT_SIG2_TAIL 0x1C0000 + + +#define HT_T_LEG_PREAMBLE 16 +#define HT_T_L_SIG 4 +#define HT_T_SIG 8 +#define HT_T_LTF1 4 +#define HT_T_GF_LTF1 8 +#define HT_T_LTFs 4 +#define HT_T_STF 4 +#define HT_T_GF_STF 8 +#define HT_T_SYML 4 + +#define HT_N_SERVICE 16 +#define HT_N_TAIL 6 + + +#define APHY_SLOT_TIME 9 +#define APHY_SIFS_TIME 16 +#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) +#define APHY_PREAMBLE_TIME 16 +#define APHY_SIGNAL_TIME 4 +#define APHY_SYMBOL_TIME 4 +#define APHY_SERVICE_NBITS 16 +#define APHY_TAIL_NBITS 6 +#define APHY_CWMIN 15 + + +#define BPHY_SLOT_TIME 20 +#define BPHY_SIFS_TIME 10 +#define BPHY_DIFS_TIME 50 +#define BPHY_PLCP_TIME 192 +#define BPHY_PLCP_SHORT_TIME 96 +#define BPHY_CWMIN 31 + + +#define DOT11_OFDM_SIGNAL_EXTENSION 6 + +#define PHY_CWMAX 1023 + +#define DOT11_MAXNUMFRAGS 16 + + + +typedef int vht_group_id_t; + + + +#define VHT_SIGA1_CONST_MASK 0x800004 + +#define VHT_SIGA1_BW_MASK 0x000003 +#define VHT_SIGA1_20MHZ_VAL 0x000000 +#define VHT_SIGA1_40MHZ_VAL 0x000001 +#define VHT_SIGA1_80MHZ_VAL 0x000002 +#define VHT_SIGA1_160MHZ_VAL 0x000003 + +#define VHT_SIGA1_STBC 0x000008 + +#define VHT_SIGA1_GID_MASK 0x0003f0 +#define VHT_SIGA1_GID_SHIFT 4 +#define VHT_SIGA1_GID_TO_AP 0x00 +#define VHT_SIGA1_GID_NOT_TO_AP 0x3f +#define VHT_SIGA1_GID_MAX_GID 0x3f + +#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 +#define VHT_SIGA1_NSTS_SHIFT 10 + +#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 +#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 + +#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 + + +#define VHT_SIGA2_GI_NONE 0x000000 +#define VHT_SIGA2_GI_SHORT 0x000001 +#define VHT_SIGA2_GI_W_MOD10 0x000002 +#define VHT_SIGA2_CODING_LDPC 0x000004 +#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 +#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 +#define VHT_SIGA2_MCS_SHIFT 4 + +#define VHT_SIGA2_B9_RESERVED 0x000200 +#define VHT_SIGA2_TAIL_MASK 0xfc0000 +#define VHT_SIGA2_TAIL_VALUE 0x000000 + + +#define VHT_T_LEG_PREAMBLE 16 +#define VHT_T_L_SIG 4 +#define VHT_T_SIG_A 8 +#define VHT_T_LTF 4 +#define VHT_T_STF 4 +#define VHT_T_SIG_B 4 +#define VHT_T_SYML 4 + +#define VHT_N_SERVICE 16 +#define VHT_N_TAIL 6 + + + +typedef struct d11cnt { + uint32 txfrag; + uint32 txmulti; + uint32 txfail; + uint32 txretry; + uint32 txretrie; + uint32 rxdup; + uint32 txrts; + uint32 txnocts; + uint32 txnoack; + uint32 rxfrag; + uint32 rxmulti; + uint32 rxcrc; + uint32 txfrmsnt; + uint32 rxundec; +} d11cnt_t; + +#define BRCM_PROP_OUI "\x00\x90\x4C" + + + +#define RWL_WIFI_DEFAULT 0 +#define RWL_WIFI_FIND_MY_PEER 9 +#define RWL_WIFI_FOUND_PEER 10 +#define RWL_ACTION_WIFI_FRAG_TYPE 85 + +#define PROXD_AF_TYPE 11 +#define BRCM_RELMACST_AF_TYPE 12 + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +#define BRCM_EVT_WL_BSS_INFO 64 + + +BWL_PRE_PACKED_STRUCT struct brcm_prop_ie_s { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + uint16 cap; +} BWL_POST_PACKED_STRUCT; +typedef struct brcm_prop_ie_s brcm_prop_ie_t; + +#define BRCM_PROP_IE_LEN 6 + +#define DPT_IE_TYPE 2 +#define BRCM_SYSCAP_IE_TYPE 3 +#define WET_TUNNEL_IE_TYPE 3 +#endif + + +#define BRCM_SYSCAP_WET_TUNNEL 0x0100 + +#define BRCM_OUI "\x00\x10\x18" + + +BWL_PRE_PACKED_STRUCT struct brcm_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 ver; + uint8 assoc; + uint8 flags; + uint8 flags1; + uint16 amsdu_mtu_pref; +} BWL_POST_PACKED_STRUCT; +typedef struct brcm_ie brcm_ie_t; +#define BRCM_IE_LEN 11 +#define BRCM_IE_VER 2 +#define BRCM_IE_LEGACY_AES_VER 1 + + +#define BRF_LZWDS 0x4 +#define BRF_BLOCKACK 0x8 + + +#define BRF1_AMSDU 0x1 +#define BRF1_WMEPS 0x4 +#define BRF1_PSOFIX 0x8 +#define BRF1_RX_LARGE_AGG 0x10 +#define BRF1_RFAWARE_DCS 0x20 +#define BRF1_SOFTAP 0x40 +#define BRF1_DWDS 0x80 + + +BWL_PRE_PACKED_STRUCT struct vndr_ie { + uchar id; + uchar len; + uchar oui [3]; + uchar data [1]; +} BWL_POST_PACKED_STRUCT; +typedef struct vndr_ie vndr_ie_t; + +#define VNDR_IE_HDR_LEN 2 +#define VNDR_IE_MIN_LEN 3 +#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) + +#define VNDR_IE_MAX_LEN 255 + + +BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { + uchar id; + uchar len; + uchar oui[3]; + uint8 type; + struct ether_addr ea; +} BWL_POST_PACKED_STRUCT; +typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; + +#define MEMBER_OF_BRCM_PROP_IE_LEN 10 +#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t)) +#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 + + +BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + struct ether_addr ea; + struct ether_addr mcast_ea; + uint8 updtmo; +} BWL_POST_PACKED_STRUCT; +typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; + + + +#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8))) + +#define RELMCAST_BRCM_PROP_IE_TYPE 55 + + +#define MCSSET_LEN 16 +#define MAX_MCS_NUM (128) + +BWL_PRE_PACKED_STRUCT struct ht_cap_ie { + uint16 cap; + uint8 params; + uint8 supp_mcs[MCSSET_LEN]; + uint16 ext_htcap; + uint32 txbf_cap; + uint8 as_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_cap_ie ht_cap_ie_t; + +BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { + uint8 id; + uint8 len; + ht_cap_ie_t ht_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; + + + +BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + ht_cap_ie_t cap_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; + +#define HT_PROP_IE_OVERHEAD 4 +#define HT_CAP_IE_LEN 26 +#define HT_CAP_IE_TYPE 51 + +#define HT_CAP_LDPC_CODING 0x0001 +#define HT_CAP_40MHZ 0x0002 +#define HT_CAP_MIMO_PS_MASK 0x000C +#define HT_CAP_MIMO_PS_SHIFT 0x0002 +#define HT_CAP_MIMO_PS_OFF 0x0003 +#define HT_CAP_MIMO_PS_RTS 0x0001 +#define HT_CAP_MIMO_PS_ON 0x0000 +#define HT_CAP_GF 0x0010 +#define HT_CAP_SHORT_GI_20 0x0020 +#define HT_CAP_SHORT_GI_40 0x0040 +#define HT_CAP_TX_STBC 0x0080 +#define HT_CAP_RX_STBC_MASK 0x0300 +#define HT_CAP_RX_STBC_SHIFT 8 +#define HT_CAP_DELAYED_BA 0x0400 +#define HT_CAP_MAX_AMSDU 0x0800 + +#define HT_CAP_DSSS_CCK 0x1000 +#define HT_CAP_PSMP 0x2000 +#define HT_CAP_40MHZ_INTOLERANT 0x4000 +#define HT_CAP_LSIG_TXOP 0x8000 + +#define HT_CAP_RX_STBC_NO 0x0 +#define HT_CAP_RX_STBC_ONE_STREAM 0x1 +#define HT_CAP_RX_STBC_TWO_STREAM 0x2 +#define HT_CAP_RX_STBC_THREE_STREAM 0x3 + + +#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 +#define HT_CAP_TXBF_CAP_NDP_TX 0x8 +#define HT_CAP_TXBF_CAP_NDP_RX 0x10 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 +#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 +#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 + +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 + +#define HT_CAP_TXBF_FB_TYPE_NONE 0 +#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 +#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 +#define HT_CAP_TXBF_FB_TYPE_BOTH 3 + +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 + +#define VHT_MAX_MPDU 11454 +#define VHT_MPDU_MSDU_DELTA 56 + +#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) + +#define HT_MAX_AMSDU 7935 +#define HT_MIN_AMSDU 3835 + +#define HT_PARAMS_RX_FACTOR_MASK 0x03 +#define HT_PARAMS_DENSITY_MASK 0x1C +#define HT_PARAMS_DENSITY_SHIFT 2 + + +#define AMPDU_MAX_MPDU_DENSITY 7 +#define AMPDU_DENSITY_NONE 0 +#define AMPDU_DENSITY_1over4_US 1 +#define AMPDU_DENSITY_1over2_US 2 +#define AMPDU_DENSITY_1_US 3 +#define AMPDU_DENSITY_2_US 4 +#define AMPDU_DENSITY_4_US 5 +#define AMPDU_DENSITY_8_US 6 +#define AMPDU_DENSITY_16_US 7 +#define AMPDU_RX_FACTOR_8K 0 +#define AMPDU_RX_FACTOR_16K 1 +#define AMPDU_RX_FACTOR_32K 2 +#define AMPDU_RX_FACTOR_64K 3 + + +#define AMPDU_RX_FACTOR_128K 4 +#define AMPDU_RX_FACTOR_256K 5 +#define AMPDU_RX_FACTOR_512K 6 +#define AMPDU_RX_FACTOR_1024K 7 + +#define AMPDU_RX_FACTOR_BASE 8*1024 +#define AMPDU_RX_FACTOR_BASE_PWR 13 + +#define AMPDU_DELIMITER_LEN 4 +#define AMPDU_DELIMITER_LEN_MAX 63 + +#define HT_CAP_EXT_PCO 0x0001 +#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 +#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 +#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 +#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 +#define HT_CAP_EXT_HTC 0x0400 +#define HT_CAP_EXT_RD_RESP 0x0800 + +BWL_PRE_PACKED_STRUCT struct ht_add_ie { + uint8 ctl_ch; + uint8 byte1; + uint16 opmode; + uint16 misc_bits; + uint8 basic_mcs[MCSSET_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_add_ie ht_add_ie_t; + + + +BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + ht_add_ie_t add_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ht_prop_add_ie ht_prop_add_ie_t; + +#define HT_ADD_IE_LEN 22 +#define HT_ADD_IE_TYPE 52 + + +#define HT_BW_ANY 0x04 +#define HT_RIFS_PERMITTED 0x08 + + +#define HT_OPMODE_MASK 0x0003 +#define HT_OPMODE_SHIFT 0 +#define HT_OPMODE_PURE 0x0000 +#define HT_OPMODE_OPTIONAL 0x0001 +#define HT_OPMODE_HT20IN40 0x0002 +#define HT_OPMODE_MIXED 0x0003 +#define HT_OPMODE_NONGF 0x0004 +#define DOT11N_TXBURST 0x0008 +#define DOT11N_OBSS_NONHT 0x0010 + + +#define HT_BASIC_STBC_MCS 0x007f +#define HT_DUAL_STBC_PROT 0x0080 +#define HT_SECOND_BCN 0x0100 +#define HT_LSIG_TXOP 0x0200 +#define HT_PCO_ACTIVE 0x0400 +#define HT_PCO_PHASE 0x0800 +#define HT_DUALCTS_PROTECTION 0x0080 + + +#define DOT11N_2G_TXBURST_LIMIT 6160 +#define DOT11N_5G_TXBURST_LIMIT 3080 + + +#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + >> HT_OPMODE_SHIFT) +#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_MIXED) +#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_HT20IN40) +#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_OPTIONAL) +#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ + HT_MIXEDMODE_PRESENT((add_ie))) +#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ + == HT_OPMODE_NONGF) +#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ + == DOT11N_TXBURST) +#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ + == DOT11N_OBSS_NONHT) + +BWL_PRE_PACKED_STRUCT struct obss_params { + uint16 passive_dwell; + uint16 active_dwell; + uint16 bss_widthscan_interval; + uint16 passive_total; + uint16 active_total; + uint16 chanwidth_transition_dly; + uint16 activity_threshold; +} BWL_POST_PACKED_STRUCT; +typedef struct obss_params obss_params_t; + +BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { + uint8 id; + uint8 len; + obss_params_t obss_params; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_obss_ie dot11_obss_ie_t; +#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) + + +#define HT_CTRL_LA_TRQ 0x00000002 +#define HT_CTRL_LA_MAI 0x0000003C +#define HT_CTRL_LA_MAI_SHIFT 2 +#define HT_CTRL_LA_MAI_MRQ 0x00000004 +#define HT_CTRL_LA_MAI_MSI 0x00000038 +#define HT_CTRL_LA_MFSI 0x000001C0 +#define HT_CTRL_LA_MFSI_SHIFT 6 +#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 +#define HT_CTRL_LA_MFB_ASELC_SH 9 +#define HT_CTRL_LA_ASELC_CMD 0x00000C00 +#define HT_CTRL_LA_ASELC_DATA 0x0000F000 +#define HT_CTRL_CAL_POS 0x00030000 +#define HT_CTRL_CAL_SEQ 0x000C0000 +#define HT_CTRL_CSI_STEERING 0x00C00000 +#define HT_CTRL_CSI_STEER_SHIFT 22 +#define HT_CTRL_CSI_STEER_NFB 0 +#define HT_CTRL_CSI_STEER_CSI 1 +#define HT_CTRL_CSI_STEER_NCOM 2 +#define HT_CTRL_CSI_STEER_COM 3 +#define HT_CTRL_NDP_ANNOUNCE 0x01000000 +#define HT_CTRL_AC_CONSTRAINT 0x40000000 +#define HT_CTRL_RDG_MOREPPDU 0x80000000 + + + + + +BWL_PRE_PACKED_STRUCT struct vht_cap_ie { + uint32 vht_cap_info; + + uint16 rx_mcs_map; + uint16 rx_max_rate; + uint16 tx_mcs_map; + uint16 tx_max_rate; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_cap_ie vht_cap_ie_t; + + +#define VHT_CAP_IE_LEN 12 + + +#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 +#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c +#define VHT_CAP_INFO_LDPC 0x00000010 +#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 +#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 +#define VHT_CAP_INFO_TX_STBC 0x00000080 +#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 +#define VHT_CAP_INFO_RX_STBC_SHIFT 8 +#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 +#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 +#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 +#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 +#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 +#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 +#define VHT_CAP_INFO_TXOPPS 0x00200000 +#define VHT_CAP_INFO_HTCVHT 0x00400000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 +#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 +#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 + + +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_MCS_MAP_0_7 0 +#define VHT_CAP_MCS_MAP_0_8 1 +#define VHT_CAP_MCS_MAP_0_9 2 +#define VHT_CAP_MCS_MAP_NONE 3 +#define VHT_CAP_MCS_MAP_S 2 +#define VHT_CAP_MCS_MAP_M 0x3 + +#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff + +#define VHT_CAP_MCS_MAP_0_9_NSS3 \ + ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) + +#define VHT_CAP_MCS_MAP_NSS_MAX 8 + + +#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ + do { \ + int i; \ + for (i = 1; i <= nss; i++) { \ + VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ + } \ + } while (0) + + +#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ + ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? 0xff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_8) ? 0x1ff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_9) ? 0x3ff : 0) + + +#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ + ((mcs_map == 0xff) ? VHT_CAP_MCS_MAP_0_7 : \ + (mcs_map == 0x1ff) ? VHT_CAP_MCS_MAP_0_8 : \ + (mcs_map == 0x3ff) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) + + +typedef enum vht_cap_chan_width { + VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, + VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, + VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 +} vht_cap_chan_width_t; + + +typedef enum vht_cap_max_mpdu_len { + VHT_CAP_MPDU_MAX_4K = 0x00, + VHT_CAP_MPDU_MAX_8K = 0x01, + VHT_CAP_MPDU_MAX_11K = 0x02 +} vht_cap_max_mpdu_len_t; + + +#define VHT_MPDU_LIMIT_4K 3895 +#define VHT_MPDU_LIMIT_8K 7991 +#define VHT_MPDU_LIMIT_11K 11454 + + + + +BWL_PRE_PACKED_STRUCT struct vht_op_ie { + uint8 chan_width; + uint8 chan1; + uint8 chan2; + uint16 supp_mcs; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_op_ie vht_op_ie_t; + + +#define VHT_OP_IE_LEN 5 + +typedef enum vht_op_chan_width { + VHT_OP_CHAN_WIDTH_20_40 = 0, + VHT_OP_CHAN_WIDTH_80 = 1, + VHT_OP_CHAN_WIDTH_160 = 2, + VHT_OP_CHAN_WIDTH_80_80 = 3 +} vht_op_chan_width_t; + + +#define AID_IE_LEN 2 + +#define VHT_FEATURES_IE_TYPE 0x4 +BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { + uint8 oui[3]; + uint8 type; + uint8 rate_mask; +} BWL_POST_PACKED_STRUCT; +typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; + + +#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) +#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ + (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) +#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ + do { \ + (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ + (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ + } while (0) +#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ + (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) + + + +#define WPA_OUI "\x00\x50\xF2" +#define WPA_OUI_LEN 3 +#define WPA_OUI_TYPE 1 +#define WPA_VERSION 1 +#define WPA2_OUI "\x00\x0F\xAC" +#define WPA2_OUI_LEN 3 +#define WPA2_VERSION 1 +#define WPA2_VERSION_LEN 2 + + +#define WPS_OUI "\x00\x50\xF2" +#define WPS_OUI_LEN 3 +#define WPS_OUI_TYPE 4 + + + +#ifdef P2P_IE_OVRD +#define WFA_OUI MAC_OUI +#else +#define WFA_OUI "\x50\x6F\x9A" +#endif +#define WFA_OUI_LEN 3 +#ifdef P2P_IE_OVRD +#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P +#else +#define WFA_OUI_TYPE_TPC 8 +#define WFA_OUI_TYPE_P2P 9 +#endif + +#define WFA_OUI_TYPE_TPC 8 +#ifdef WLTDLS +#define WFA_OUI_TYPE_TPQ 4 +#define WFA_OUI_TYPE_TPS 5 +#define WFA_OUI_TYPE_WFD 10 +#endif +#define WFA_OUI_TYPE_HS20 0x10 + + +#define RSN_AKM_NONE 0 +#define RSN_AKM_UNSPECIFIED 1 +#define RSN_AKM_PSK 2 +#define RSN_AKM_FBT_1X 3 +#define RSN_AKM_FBT_PSK 4 +#define RSN_AKM_MFP_1X 5 +#define RSN_AKM_MFP_PSK 6 +#define RSN_AKM_TPK 7 + + +#define DOT11_MAX_DEFAULT_KEYS 4 +#define DOT11_MAX_IGTK_KEYS 2 +#define DOT11_MAX_KEY_SIZE 32 +#define DOT11_MAX_IV_SIZE 16 +#define DOT11_EXT_IV_FLAG (1<<5) +#define DOT11_WPA_KEY_RSC_LEN 8 + +#define WEP1_KEY_SIZE 5 +#define WEP1_KEY_HEX_SIZE 10 +#define WEP128_KEY_SIZE 13 +#define WEP128_KEY_HEX_SIZE 26 +#define TKIP_MIC_SIZE 8 +#define TKIP_EOM_SIZE 7 +#define TKIP_EOM_FLAG 0x5a +#define TKIP_KEY_SIZE 32 +#define TKIP_TK_SIZE 16 +#define TKIP_MIC_KEY_SIZE 8 +#define TKIP_MIC_AUTH_TX 16 +#define TKIP_MIC_AUTH_RX 24 +#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX +#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX +#define AES_KEY_SIZE 16 +#define AES_MIC_SIZE 8 +#define BIP_KEY_SIZE 16 +#define BIP_MIC_SIZE 8 + +#define AES_GCM_MIC_SIZE 16 + +#define AES256_KEY_SIZE 32 +#define AES256_MIC_SIZE 16 + + +#define WCN_OUI "\x00\x50\xf2" +#define WCN_TYPE 4 + +#ifdef BCMWAPI_WPI +#define SMS4_KEY_LEN 16 +#define SMS4_WPI_CBC_MAC_LEN 16 +#endif + + + + +BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { + uint8 id; + uint8 len; + uint16 mdid; + uint8 cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_mdid_ie dot11_mdid_ie_t; + +#define FBT_MDID_CAP_OVERDS 0x01 +#define FBT_MDID_CAP_RRP 0x02 + + +BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { + uint8 id; + uint8 len; + uint16 mic_control; + uint8 mic[16]; + uint8 anonce[32]; + uint8 snonce[32]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_ie dot11_ft_ie_t; + +#define TIE_TYPE_RESERVED 0 +#define TIE_TYPE_REASSOC_DEADLINE 1 +#define TIE_TYPE_KEY_LIEFTIME 2 +#define TIE_TYPE_ASSOC_COMEBACK 3 +BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { + uint8 id; + uint8 len; + uint8 type; + uint32 value; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timeout_ie dot11_timeout_ie_t; + + +BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { + uint8 id; + uint8 len; + uint16 key_info; + uint8 key_len; + uint8 rsc[8]; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_gtk_ie dot11_gtk_ie_t; + + +BWL_PRE_PACKED_STRUCT struct mmic_ie { + uint8 id; + uint8 len; + uint16 key_id; + uint8 ipn[6]; + uint8 mic[16]; +} BWL_POST_PACKED_STRUCT; +typedef struct mmic_ie mmic_ie_t; + +#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" +#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" + +#ifdef BCMWAPI_WAI +#define WAPI_IE_MIN_LEN 20 +#define WAPI_VERSION 1 +#define WAPI_VERSION_LEN 2 +#define WAPI_OUI "\x00\x14\x72" +#define WAPI_OUI_LEN DOT11_OUI_LEN +#endif + + +#define WMM_OUI "\x00\x50\xF2" +#define WMM_OUI_LEN 3 +#define WMM_OUI_TYPE 2 +#define WMM_VERSION 1 +#define WMM_VERSION_LEN 1 + + +#define WMM_OUI_SUBTYPE_PARAMETER 1 +#define WMM_PARAMETER_IE_LEN 24 + + +BWL_PRE_PACKED_STRUCT struct link_id_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + struct ether_addr tdls_init_mac; + struct ether_addr tdls_resp_mac; +} BWL_POST_PACKED_STRUCT; +typedef struct link_id_ie link_id_ie_t; +#define TDLS_LINK_ID_IE_LEN 18 + + +BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { + uint8 id; + uint8 len; + uint32 offset; + uint32 interval; + uint32 awake_win_slots; + uint32 max_wake_win; + uint16 idle_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct wakeup_sch_ie wakeup_sch_ie_t; +#define TDLS_WAKEUP_SCH_IE_LEN 18 + + +BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { + uint8 id; + uint8 len; + uint16 switch_time; + uint16 switch_timeout; +} BWL_POST_PACKED_STRUCT; +typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; +#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 + + +BWL_PRE_PACKED_STRUCT struct pti_control_ie { + uint8 id; + uint8 len; + uint8 tid; + uint16 seq_control; +} BWL_POST_PACKED_STRUCT; +typedef struct pti_control_ie pti_control_ie_t; +#define TDLS_PTI_CONTROL_IE_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { + uint8 id; + uint8 len; + uint8 status; +} BWL_POST_PACKED_STRUCT; +typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; +#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 +#define TDLS_PU_BUFFER_STATUS_AC_BK 1 +#define TDLS_PU_BUFFER_STATUS_AC_BE 2 +#define TDLS_PU_BUFFER_STATUS_AC_VI 4 +#define TDLS_PU_BUFFER_STATUS_AC_VO 8 + + +#define TDLS_SETUP_REQ 0 +#define TDLS_SETUP_RESP 1 +#define TDLS_SETUP_CONFIRM 2 +#define TDLS_TEARDOWN 3 +#define TDLS_PEER_TRAFFIC_IND 4 +#define TDLS_CHANNEL_SWITCH_REQ 5 +#define TDLS_CHANNEL_SWITCH_RESP 6 +#define TDLS_PEER_PSM_REQ 7 +#define TDLS_PEER_PSM_RESP 8 +#define TDLS_PEER_TRAFFIC_RESP 9 +#define TDLS_DISCOVERY_REQ 10 + + +#define TDLS_DISCOVERY_RESP 14 + + +#define GAS_REQUEST_ACTION_FRAME 10 +#define GAS_RESPONSE_ACTION_FRAME 11 +#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 +#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 + + +#define IW_ANT_MASK 0x0f +#define IW_INTERNET_MASK 0x10 +#define IW_ASRA_MASK 0x20 +#define IW_ESR_MASK 0x40 +#define IW_UESA_MASK 0x80 + + +#define IW_ANT_PRIVATE_NETWORK 0 +#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 +#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 +#define IW_ANT_FREE_PUBLIC_NETWORK 3 +#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 +#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 +#define IW_ANT_TEST_NETWORK 14 +#define IW_ANT_WILDCARD_NETWORK 15 + + +#define ADVP_ANQP_PROTOCOL_ID 0 + + +#define ADVP_QRL_MASK 0x7f +#define ADVP_PAME_BI_MASK 0x80 + + +#define ADVP_QRL_REQUEST 0x00 +#define ADVP_QRL_RESPONSE 0x7f +#define ADVP_PAME_BI_DEPENDENT 0x00 +#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK + + +#define ANQP_ID_QUERY_LIST 256 +#define ANQP_ID_CAPABILITY_LIST 257 +#define ANQP_ID_VENUE_NAME_INFO 258 +#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 +#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 +#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 +#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 +#define ANQP_ID_NAI_REALM_LIST 263 +#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 +#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 +#define ANQP_ID_AP_CIVIC_LOCATION 266 +#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 +#define ANQP_ID_DOMAIN_NAME_LIST 268 +#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 +#define ANQP_ID_EMERGENCY_NAI 271 +#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 + + +#define ANQP_OUI_SUBTYPE 9 + + +#define VENUE_LANGUAGE_CODE_SIZE 3 +#define VENUE_NAME_SIZE 255 + + +#define VENUE_UNSPECIFIED 0 +#define VENUE_ASSEMBLY 1 +#define VENUE_BUSINESS 2 +#define VENUE_EDUCATIONAL 3 +#define VENUE_FACTORY 4 +#define VENUE_INSTITUTIONAL 5 +#define VENUE_MERCANTILE 6 +#define VENUE_RESIDENTIAL 7 +#define VENUE_STORAGE 8 +#define VENUE_UTILITY 9 +#define VENUE_VEHICULAR 10 +#define VENUE_OUTDOOR 11 + + +#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 +#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 +#define NATI_HTTP_HTTPS_REDIRECTION 2 +#define NATI_DNS_REDIRECTION 3 + + +#define IPA_IPV6_SHIFT 0 +#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) +#define IPA_IPV6_NOT_AVAILABLE 0x00 +#define IPA_IPV6_AVAILABLE 0x01 +#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 + + +#define IPA_IPV4_SHIFT 2 +#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) +#define IPA_IPV4_NOT_AVAILABLE 0x00 +#define IPA_IPV4_PUBLIC 0x01 +#define IPA_IPV4_PORT_RESTRICT 0x02 +#define IPA_IPV4_SINGLE_NAT 0x03 +#define IPA_IPV4_DOUBLE_NAT 0x04 +#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 +#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 +#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 + + +#define REALM_ENCODING_RFC4282 0 +#define REALM_ENCODING_UTF8 1 + + +#define REALM_EAP_TLS 13 +#define REALM_EAP_SIM 18 +#define REALM_EAP_TTLS 21 +#define REALM_EAP_AKA 23 +#define REALM_EAP_PSK 47 +#define REALM_EAP_AKAP 50 +#define REALM_EAP_EXPANDED 254 + + +#define REALM_EXPANDED_EAP 1 +#define REALM_NON_EAP_INNER_AUTHENTICATION 2 +#define REALM_INNER_AUTHENTICATION_EAP 3 +#define REALM_EXPANDED_INNER_EAP 4 +#define REALM_CREDENTIAL 5 +#define REALM_TUNNELED_EAP_CREDENTIAL 6 +#define REALM_VENDOR_SPECIFIC_EAP 221 + + +#define REALM_PAP 1 +#define REALM_CHAP 2 +#define REALM_MSCHAP 3 +#define REALM_MSCHAPV2 4 + + +#define REALM_SIM 1 +#define REALM_USIM 2 +#define REALM_NFC 3 +#define REALM_HARDWARE_TOKEN 4 +#define REALM_SOFTOKEN 5 +#define REALM_CERTIFICATE 6 +#define REALM_USERNAME_PASSWORD 7 +#define REALM_SERVER_SIDE 8 + + +#define G3PP_GUD_VERSION 0 +#define G3PP_PLMN_LIST_IE 0 + + +BWL_PRE_PACKED_STRUCT struct hs20_ie { + uint8 oui[3]; + uint8 type; + uint8 config; +} BWL_POST_PACKED_STRUCT; +typedef struct hs20_ie hs20_ie_t; +#define HS20_IE_LEN 5 + + +typedef enum { + DOT11_2GHZ_20MHZ_CLASS_12 = 81, + DOT11_5GHZ_20MHZ_CLASS_1 = 115, + DOT11_5GHZ_20MHZ_CLASS_2_DFS = 118, + DOT11_5GHZ_20MHZ_CLASS_3 = 124, + DOT11_5GHZ_20MHZ_CLASS_4_DFS = 121, + DOT11_5GHZ_20MHZ_CLASS_5 = 125, + DOT11_5GHZ_40MHZ_CLASS_22 = 116, + DOT11_5GHZ_40MHZ_CLASS_23_DFS = 119, + DOT11_5GHZ_40MHZ_CLASS_24_DFS = 122, + DOT11_5GHZ_40MHZ_CLASS_25 = 126, + DOT11_5GHZ_40MHZ_CLASS_27 = 117, + DOT11_5GHZ_40MHZ_CLASS_28_DFS = 120, + DOT11_5GHZ_40MHZ_CLASS_29_DFS = 123, + DOT11_5GHZ_40MHZ_CLASS_30 = 127, + DOT11_2GHZ_40MHZ_CLASS_32 = 83, + DOT11_2GHZ_40MHZ_CLASS_33 = 84, +} dot11_op_class_t; + + +#include <packed_section_end.h> + +#endif
diff --git a/src/common/include/proto/802.11_bta.h b/src/common/include/proto/802.11_bta.h new file mode 100644 index 0000000..1a53542 --- /dev/null +++ b/src/common/include/proto/802.11_bta.h
@@ -0,0 +1,27 @@ +/* + * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: 802.11_bta.h 382882 2013-02-04 23:24:31Z $ +*/ + +#ifndef _802_11_BTA_H_ +#define _802_11_BTA_H_ + +#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" + +/* BT-AMP 802.11 PAL Protocols */ +#define BTA_PROT_L2CAP 1 +#define BTA_PROT_ACTIVITY_REPORT 2 +#define BTA_PROT_SECURITY 3 +#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 +#define BTA_PROT_LINK_SUPERVISION_REPLY 5 + +/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ +#define BTA_TYPE_ID_MAC_ADDRESS 1 +#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 +#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 +#define BTA_TYPE_ID_CAPABILITIES 4 +#define BTA_TYPE_ID_VERSION 5 +#endif /* _802_11_bta_h_ */
diff --git a/src/common/include/proto/802.11_ccx.h b/src/common/include/proto/802.11_ccx.h new file mode 100644 index 0000000..1036b65 --- /dev/null +++ b/src/common/include/proto/802.11_ccx.h
@@ -0,0 +1,703 @@ +/* + * $Copyright Open Broadcom Corporation$ + * + * Fundamental types and constants relating to 802.11 ccx + * + * $Id: 802.11_ccx.h 382882 2013-02-04 23:24:31Z $ + */ + +#ifndef _802_11_CCX_H_ +#define _802_11_CCX_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +#ifndef _NET_ETHERNET_H_ +#include <proto/ethernet.h> +#endif + + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + + +#define DOT11_LEAP_AUTH 0x80 /* LEAP authentication frame payload constants */ + +/* Management Frame Information Element IDs */ +#define DOT11_MNG_AIRONET_ID 133 /* AIRONET id */ +#define DOT11_MNG_CELL_PWR_ID 150 /* cell power id */ +#define DOT11_MNG_CCKM_REASSOC_ID 156 /* CCKM reassoc. id */ +#define DOT11_MNG_SSIDL_ID 221 /* SSIDL id */ + +#define CISCO_BASE 8 /* base of Cisco cipher and AKM vals */ + +/* AIRONET IE field offsets */ +#define AIRONET_IE_REFRESH_RATE 3 /* refresh rate */ +#define AIRONET_IE_CWMIN 4 /* cwmin */ +#define AIRONET_IE_CWMAX 6 /* cwmax */ +#define AIRONET_IE_CKIP 8 /* CKIP */ +#define AIRONET_IE_NAME 10 /* offset to AP/Machine name field */ +#define AIRONET_IE_DEVICE_ID 0x66 /* Dev ID */ + +#define AIRONET_IE_MAX_NAME_LEN 16 /* device name length, include NULL */ + +BWL_PRE_PACKED_STRUCT struct aironet_assoc_ie { + uint8 id; /* IE ID */ + uint8 len; /* IE length */ + uint8 load; + uint8 hops; + uint8 device; + uint8 refresh_rate; + uint16 cwmin; + uint16 cwmax; + uint8 flags; + uint8 distance; + char name[AIRONET_IE_MAX_NAME_LEN]; /* AP or Client's machine name */ + uint16 num_assoc; /* number of clients associated */ + uint16 radiotype; +} BWL_POST_PACKED_STRUCT; +typedef struct aironet_assoc_ie aironet_assoc_ie_t; + +/* CKIP Negotiation bit fields */ +#define CKIP_MIC 0x08 /* MIC */ +#define CKIP_KP 0x10 /* KP */ +#define CKIP_LLC_SNAP_LEN 8 /* SKIP LLC SNAP header length */ + +#define CCX_DDP_LLC_SNAP_LEN 8 /* CCX DDP/LLC/SNAP length */ +#define CCX_DDP_MSG_LEN 40 /* CCX DDP MSG length */ +#define CCX_DDP_ROGUE_NAME_LEN 16 /* CCX DDP rogue name length */ +BWL_PRE_PACKED_STRUCT struct ccx_ddp_pkt_s { + struct ether_header eth; + struct dot11_llc_snap_header snap; + uint16 msg_len; + uint8 msg_type; + uint8 fcn_code; + struct ether_addr dest_mac; + struct ether_addr src_mac; + uint16 fail_reason; + struct ether_addr rogue_mac; + uint8 rogue_name[CCX_DDP_ROGUE_NAME_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_ddp_pkt_s ccx_ddp_pkt_t; +#define CCX_DDP_PKT_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN + CCX_DDP_MSG_LEN) + +#define CCX_ROGUE_INVALID_AUTH 1 /* invalid auth. */ +#define CCX_ROGUE_LEAP_TIMEOUT 2 /* LEAP timeout */ +#define CCX_ROGUE_CHAN_FROM_AP 3 /* chan. from AP */ +#define CCX_ROGUE_CHAN_TO_AP 4 /* chan. to AP */ + +/* Cisco/Aironet IAPP packet defs */ + +#define CISCO_AIRONET_OUI "\x00\x40\x96" /* Cisco AIRONET OUI */ +#define CISCO_AIRONET_SNAP "\xAA\xAA\x03\x00\x40\x96\x00\x00" /* Cisco AIRONET SNAP */ + +#define CCX_IAPP_ID_MASK 0xf000 /* IAPP id mask */ +#define CCX_IAPP_LEN_MASK 0x0fff /* IAPP len mask */ +#define CCX_IAPP_ID_SHIFT 12 /* IAPP id shift */ + +#define CCX_IAPP_ID_CONTROL 0x0000 /* IAPP id control */ +#define CCX_IAPP_TYPE_RM 0x32 /* IAPP radio measurement request type */ +#define CCX_IAPP_TYPE_ROAM 0x33 /* IAPP roam request type */ +#define CCX_IAPP_TYPE_LINK_TEST 0x41 /* IAPP link test request type */ +#define CCX_IAPP_SUBTYPE_REQ 0x01 /* IAPP subtype request */ +#define CCX_IAPP_SUBTYPE_ROAM_REP 0x81 /* IAPP subtype report */ +#define CCX_IAPP_SUBTYPE_ROAM_REQ 0x82 /* IAPP subtype directed roam request */ +#define CCXv2_IAPP_TYPE_ROAM 0x30 /* CCXv2 IAPP roam request type */ +#define CCXv2_IAPP_SUBTYPE_ROAM_REQ 0x00 /* CCXv2 IAPP roam subtype request */ +#define CCX_IAPP_TYPE_DIAG_GROUP 0x60 /* IAPP type for diag. group(s64, s65 and s66) */ + +/* Cisco/Aironet IAPP header */ +BWL_PRE_PACKED_STRUCT struct ccx_iapp_hdr { + uint16 id_len; /* IAPP ID & Length */ + uint8 type; /* IAPP Type */ + uint8 subtype; /* IAPP Subtype */ + struct ether_addr da; + struct ether_addr sa; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_iapp_hdr ccx_iapp_hdr_t; +#define CCX_IAPP_HDR_LEN 16 /* IAPP header length */ + +/* CCXv2 Transmit Power Control IE */ +BWL_PRE_PACKED_STRUCT struct ccx_cell_pwr { + uint8 id; /* 150, DOT11_MNG_CELL_PWR_ID */ + uint8 len; + uint8 oui[3]; /* 00:40:96, CISCO_AIRONET_OUI */ + uint8 ver; /* 0 */ + uint8 power; /* signed int dBm */ + uint8 reserved; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_cell_pwr ccx_cell_pwr_t; + +#define CCX_RM_STATE_NORMAL 1 /* Radio Management Capability IE state */ +#define CCX_RM_STATE_MBSSID_MASK 0x0700 /* MBSSID Mask field */ +#define CCX_RM_STATE_MBSSID_SHIFT 8 /* MBSSID Mask field */ + +/* CCXv2 Radio Management Capability IE */ +BWL_PRE_PACKED_STRUCT struct ccx_radio_mgmt { + uint8 id; /* 221, DOT11_MNG_PROPR_ID */ + uint8 len; + uint8 oui[3]; /* 00:40:96, CISCO_AIRONET_OUI */ + uint8 ver; /* 1 */ + uint16 state; /* Radio Mgmt state, 1->Normal. MBSSID mask starts at bit 8 */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_radio_mgmt ccx_radio_mgmt_t; + +#define CCX_QOS_IE_TYPE 4 /* CCX QoS IE type */ +#define CCX_QOS_IE_LEN 0x16 /* CCX QoS IE length */ +#define CCX_VERSION_IE_TYPE 3 /* CCX version IE type */ +#define CCX_VERSION_IE_LEN 5 /* CCX version IE length */ +#define CCX_RM_CAP_IE_TYPE 1 /* CCX RM cap IE type */ + +/* CCXv2 QOS Parameter set IE */ +BWL_PRE_PACKED_STRUCT struct ccx_qos_params { + uint8 id; /* 221, DOT11_MNG_PROPR_ID */ + uint8 len; + uint8 oui[3]; /* 00:40:96, CISCO_AIRONET_OUI */ + uint8 type; /* 4 */ + uint8 unused; + uint8 count; /* incremented when element changes */ + uint8 aifsn_0; /* AIFSN class 0 */ + uint8 ecw_0; /* ECWmin/ECWmax class 0 */ + uint16 txop_0; /* TXOP Limit class 0 */ + uint8 aifsn_1; /* AIFSN class 1 */ + uint8 ecw_1; /* ECWmin/ECWmax class 1 */ + uint16 txop_1; /* TXOP Limit class 1 */ + uint8 aifsn_2; /* AIFSN class 2 */ + uint8 ecw_2; /* ECWmin/ECWmax class 2 */ + uint16 txop_2; /* TXOP Limit class 2 */ + uint8 aifsn_3; /* AIFSN class 3 */ + uint8 ecw_3; /* ECWmin/ECWmax class 3 */ + uint16 txop_3; /* TXOP Limit class 3 */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_qos_params ccx_qos_params_t; + +/* CCXv2 Version IE */ +BWL_PRE_PACKED_STRUCT struct ccx_version_ie { + uint8 id; /* 221, DOT11_MNG_PROPR_ID */ + uint8 len; + uint8 oui[DOT11_OUI_LEN]; /* 00:40:96, CISCO_AIRONET_OUI */ + uint8 type; /* 3 */ + uint8 version; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_version_ie ccx_version_ie_t; + +/* CCX Adjacent AP Report IE in roam IAPP packet */ +BWL_PRE_PACKED_STRUCT struct ccx_roam_ap_ie_s { + uint16 tag; /* 0x9b - Adjacent AP report */ + uint16 len; + uint8 oui[DOT11_OUI_LEN]; /* Aironet OUI 0x00 0x40 0x96 0x00 */ + uint8 ver; + struct ether_addr mac; /* MAC address of AP */ + uint16 channel; + uint16 ssid_len; + uint8 ssid[32]; + uint16 disassoc_time; /* Seconds that the client has been disassociated */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_roam_ap_ie_s ccx_roam_ap_ie_t; +#define CCX_ROAM_AP_IE_LEN 52 /* CCX roam AP IE length */ + +/* CCX IAPP packet sent to AP on association with info on previous AP */ +BWL_PRE_PACKED_STRUCT struct ccx_roam_iapp_pkt_s { + struct ether_header eth; + struct dot11_llc_snap_header snap; + uint16 msg_len; + uint8 msg_type; + uint8 fcn_code; + struct ether_addr dest_mac; + struct ether_addr src_mac; + ccx_roam_ap_ie_t ap_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_roam_iapp_pkt_s ccx_roam_iapp_pkt_t; + +/* CCX roam IAPP message length */ +#define CCX_ROAM_IAPP_MSG_SIZE (sizeof(ccx_roam_iapp_pkt_t) - sizeof(struct ether_header)) +#define CCX_ROAM_ADJ_AP_TAG 0x9b /* CCX adjacent AP tag */ + +/* CCXv4 S51 */ +/* CCX roam reason IE in roam IAPP packet */ +BWL_PRE_PACKED_STRUCT struct ccx_roam_reason_ie { + uint16 tag; /* 0x9c - roam reason tag */ + uint16 len; + uint8 oui[DOT11_OUI_LEN]; /* Aironet OUI 0x00 0x40 0x96 0x00 */ + uint8 ver; + uint8 reason; /* roam reason */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_roam_reason_ie ccx_roam_reason_ie_t; +#define CCX_ROAM_REASON_IE_LEN 8 /* CCX roam reason IE length */ + +/* CCX roam neighbor report IE in roam IAPP packet */ +BWL_PRE_PACKED_STRUCT struct ccx_neighbor_rept_ie { + uint8 id; /* CCX_ROAM_NEIGHBOR_REPT_ID */ + uint8 len; /* length beyond len */ + struct ether_addr mac; /* MAC address of neighbor AP */ + uint8 channel; /* current channel of neighbor AP */ + uint8 band; /* band of current channel of neighbor AP */ + uint8 phy_type; /* PHY type of current channel of neighbor AP */ + /* variable subelements follows */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_neighbor_rept_ie ccx_neighbor_rept_ie_t; +#define CCX_NEIGHBOR_REPT_IE_LEN 11 /* CCX neighbor report IE length */ +#define CCX_NEIGHBOR_REPT_IE_LEN_W_H 9 /* CCX_NEIGHBOR_REPT_IE_LEN - header (2) */ +/* RF parameter subelement for neighbor ie */ +BWL_PRE_PACKED_STRUCT struct ccx_radio_param_subie { + uint8 sub_id; /* subelement id */ + uint8 len; /* length beyond len */ + int8 min_rssi; /* min. recv pwr in dBm required to associate with the AP */ + int8 ap_tx_pwr; /* tx pwr in dBm of neighbor AP */ + int8 sta_tx_pwr; /* tx pwr in dBm of sta advertised by neighbor AP */ + int8 roam_delta; /* roam delta */ + int8 roam_trigger; /* roam trigger */ + uint8 roam_time; /* transition time(in 0.1s) permmited in roam */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_radio_param_subie ccx_radio_param_subie_t; +#define CCX_RADIO_PARAM_SUBIE_LEN 8 /* CCX RF parameter sub IE length */ + +/* TSF info. subelement for neighbor ie */ +BWL_PRE_PACKED_STRUCT struct ccx_tsf_info_subie { + uint8 sub_id; /* subelement id */ + uint8 len; /* length beyond len */ + BWL_PRE_PACKED_STRUCT struct { + uint16 offset; /* TSF time offset in TUs between serving AP and this AP */ + uint16 bcn_interval; /* beacon interval of AP */ + } BWL_POST_PACKED_STRUCT TSF; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_tsf_info_subie ccx_tsf_info_subie_t; +#define CCX_TSF_INFO_SUBIE_LEN 6 /* CCX TSF info. sub IE length */ + +/* subelement id */ +#define CCX_ROAM_SUB_RF_PARAMS 1 /* CCX neighbor element RF subelement id */ +#define CCX_ROAM_SUB_TSF_INFO 2 /* CCX neighbor element TSF subelement id */ + +/* roam reason */ +#define CCX_ROAM_UNSPECIFIED 0 /* unspecified */ +#define CCX_ROAM_NORMAL 1 /* poor link(excessive retries, RSSI too low...) */ +#define CCX_ROAM_LOAD_BALANCING 2 /* normal roam, load balancing */ +#define CCX_ROAM_AP_INCAPACITY 3 /* AP has insufficient capacity(TSPEC rejected) */ +#define CCX_ROAM_DIRECTED_ROAM 4 /* Infrastructure directed roam */ +#define CCX_ROAM_FIRST_ASSOC 5 /* first association to WLAN */ +#define CCX_ROAM_IN_NET 6 /* roaming in from cellular or other WAN */ +#define CCX_ROAM_OUT_NET 7 /* roaming out to cellular or other WAN */ +#define CCX_ROAM_BETTER_AP 8 /* normal roaming, better AP found */ +#define CCX_ROAM_LINK_DOWN 9 /* deauthnticated or disassociated from the previous AP */ + +/* band */ +#define CCX_CHAN_BAND_2G 0 /* 2.4 GHz band */ +#define CCX_CHAN_BAND_5G 1 /* 5 GHz band */ + +#define CCX_ROAM_NEIGHBOR_REPT_ID 0x28 /* CCX roam neighbor report id */ + +#define CCX_ROAM_REASON_TAG 0x9c /* roam reason tag */ + +#if defined(BCMSUP_PSK) || !defined(BCMINTSUP) +#define CCKM_KRK_LEN 16 /* CCKM KRK length */ +#define CCKM_BTK_LEN 32 /* CCKM BTK length */ + +#define CCKM_OUI_TYPE 0 /* CCKM OUI type */ +#define CCKM_RSC_LEN 8 /* CCKM RSC length */ +#define CCKM_MIC_LEN 8 /* CCKM MIC length */ + +BWL_PRE_PACKED_STRUCT struct cckm_reassoc_req_ie_s { + uint8 id; /* DOT11_MNG_CCKM_REASSOC_ID */ + uint8 len; /* length beyond len */ + uint8 oui[DOT11_OUI_LEN]; /* expect AIRONET_OUI */ + uint8 oui_type; /* expect CCKM_OUI_TYPE */ + uint8 timestamp[DOT11_MNG_TIMESTAMP_LEN]; /* TSF timer value (LE) */ + uint32 rn; /* reassociation request number (LE) */ + uint8 mic[CCKM_MIC_LEN]; /* MIC computed using KRK */ +} BWL_POST_PACKED_STRUCT; +typedef struct cckm_reassoc_req_ie_s cckm_reassoc_req_ie_t; +#define CCKM_REASSOC_REQ_IE_LEN 26 /* CCKM reassoc. request IE length */ + +BWL_PRE_PACKED_STRUCT struct cckm_reassoc_resp_ie_s { + uint8 id; /* DOT11_MNG_CCKM_REASSOC_ID */ + uint8 len; /* length beyond len */ + uint8 oui[DOT11_OUI_LEN]; /* expect AIRONET_OUI */ + uint8 oui_type; /* expect CCKM_OUI_TYPE */ + uint32 rn; /* rekey value */ + uint8 ucast_idx; /* ucast key index; expect 0 */ + uint8 mcast_idx; /* mcast key index */ + uint8 rsc[CCKM_RSC_LEN]; /* mcast RSC */ + uint16 gtklen; /* mcast key len */ + uint8 mic[CCKM_MIC_LEN]; /* msg integrity code */ + uint8 egtk[1]; /* encrypted group key */ +} BWL_POST_PACKED_STRUCT; +typedef struct cckm_reassoc_resp_ie_s cckm_reassoc_resp_ie_t; +#define CCKM_REASSOC_RESP_IE_LEN 31 /* CCKM reassoc. response IE length */ + +#endif /* BCMSUP_PSK || !BCMINTSUP */ + +/* CCX Radio Managment definitions, CCX spec section S36 */ + +#define CCX_RM_IE_HDR_LEN 4 /* length of Radio Mgmt IE ID plus Len */ + +/* Radio Measurement IE IDs */ +#define CCX_RM_ID_REQUEST 38 /* CCX radio measurement request id */ +#define CCX_RM_ID_REPORT 39 /* CCX radio measurement respond id */ + +/* Radio Measurement Request Type field */ +#define CCX_RM_TYPE_LOAD 1 /* CCX radio measurement load request */ +#define CCX_RM_TYPE_NOISE 2 /* CCX radio measurement noise request */ +#ifndef CCX_SDK /* CCX SDK defined the same RM types with the same names */ +#define CCX_RM_TYPE_BEACON 3 /* CCX radio measurement beacon request */ +#define CCX_RM_TYPE_FRAME 4 /* CCX radio measurement frame request */ +#endif /* CCX_SDK */ +#define CCXv4_RM_TYPE_PATHLOSS 6 /* CCX radio measurement PathLoss request for CCXv4 */ +#define CCX_RM_TYPE_PATHLOSS 9 /* CCX radio measurement PathLoss request */ +#define CCX_RM_TYPE_STATISTICS 10 /* CCX radio measurement Statistics request */ + +/* Radio Measurement Request Mode field */ +#define CCX_RM_MODE_PARALLEL (1<<0) /* CCX radio measurement parallel request */ +#define CCX_RM_MODE_ENABLE (1<<2) /* CCX radio measurement autonomous request */ +#define CCX_RM_MODE_REPORT (1<<3) /* CCX radio measurement report */ +/* Radio Measurement Report Modes */ +#define CCX_RM_MODE_INCAPABLE (1<<1) /* CCX radio measurement incapable */ +#define CCX_RM_MODE_REFUSED (1<<2) /* CCX radio measurement refused */ + +/* Radio Measurement Beacon scan types */ +#define CCX_RM_BEACON_PASSIVE_SCAN 0 /* CCX radio measurement beacon passive scan */ +#define CCX_RM_BEACON_ACTIVE_SCAN 1 /* CCX radio measurement beacon active scan */ +#define CCX_RM_BEACON_TABLE 2 /* CCX radio measurement beacon table */ + +/* Radio Measurement Beacon PHY Types */ +#define CCX_RM_PHY_FH 1 /* CCX radio measurement FH */ +#define CCX_RM_PHY_DSS 2 /* CCX radio measurement DSS */ +#define CCX_RM_PHY_OFDM 4 /* CCX radio measurement OFDM */ +#define CCX_RM_PHY_HRDSS 5 /* CCX radio measurement HRDSS */ +#define CCX_RM_PHY_ERP 6 /* CCX radio measurement ERP */ + +/* CCXv2 Radio Measurment Request frame + * Encapsulated in Cisco Aironet IAPP frame + */ +BWL_PRE_PACKED_STRUCT struct ccx_rm_req { + uint16 token; /* Dialog Token */ + uint8 delay; /* Request Activation Delay (TBTTs) */ + uint8 offset; /* Request Activation Offset (TUs) */ + uint8 data[1]; /* Request information elts */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_req ccx_rm_req_t; +#define CCX_RM_REQ_LEN 4 /* CCX radio measurement request header length */ + +/* CCXv2 Radio Measurment Report frame header + * Encapsulated in Cisco Aironet IAPP frame + */ +BWL_PRE_PACKED_STRUCT struct ccx_rm_rep { + uint16 token; /* Dialog Token */ + uint8 data[1]; /* Report information elts */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_rep ccx_rm_rep_t; +#define CCX_RM_REP_LEN 2 /* CCX radio measurement reponse header length */ +/* Max length of CCXv2 Radio Measurment Report data section based on + * the maximum size of the LLC_SNAP encapsulating frame. + */ +#define CCX_RM_REP_DATA_MAX_LEN \ + (ETHER_MAX_DATA - (DOT11_LLC_SNAP_HDR_LEN + CCX_IAPP_HDR_LEN + \ + CCX_RM_REP_LEN)) /* CCX radio measurement max report data length */ + +/* CCXv2 Radio Measurment Request IE + * Encapsulated in a CCXv2 Radio Measurment Request frame + */ +BWL_PRE_PACKED_STRUCT struct ccx_rm_req_ie { + uint16 id; + uint16 len; + uint16 token; /* Dialog Token */ + uint8 mode; + uint8 type; + /* end of fixed portion */ + /* variable data, depends on mode and type */ + uint8 channel; /* channel for the measurment */ + uint8 param; /* measurement parameter */ + uint16 duration; /* measurement duration (TUs) */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_req_ie ccx_rm_req_ie_t; +#define CCX_RM_REQ_IE_FIXED_LEN 8 /* CCX radio measurement request IE fixed length */ + +/* CCXv2 Radio Measurment Report IE + * Encapsulated in a CCXv2 Radio Measurment Report frame + */ +BWL_PRE_PACKED_STRUCT struct ccx_rm_rep_ie { + uint16 id; + uint16 len; + uint16 token; + uint8 mode; + uint8 type; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_rep_ie ccx_rm_rep_ie_t; +#define CCX_RM_REP_IE_FIXED_LEN 8 /* CCX radio measurement report IE fixed length */ + +BWL_PRE_PACKED_STRUCT struct ccx_rm_beacon_rep { + uint8 channel; + uint8 spare; + uint16 duration; + uint8 phy_type; + int8 rssi; + struct ether_addr bssid; + uint32 parent_tsf; + uint32 target_tsf_low; + uint32 target_tsf_hi; + uint16 beacon_interval; + uint16 capability; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_beacon_rep ccx_rm_beacon_rep_t; +#define CCX_RM_BEACON_REP_FIXED_LEN 28 /* CCX rm beacon report fixed length */ + +BWL_PRE_PACKED_STRUCT struct ccx_rm_frm_rep_elt { + struct ether_addr ta; /* transmitter address */ + struct ether_addr bssid; /* bssid transmitter belongs to */ + uint8 rssi; /* average RSSI */ + uint8 frames; /* total number of frames */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_frm_rep_elt ccx_rm_frm_rep_elt_t; +#define CCX_RM_FRAME_REP_ENTRY_LEN 14 /* CCX rm frame report entry length */ + +BWL_PRE_PACKED_STRUCT struct ccx_rm_frame_rep { + uint8 channel; + uint8 spare; + uint16 duration; + ccx_rm_frm_rep_elt_t elt[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_frame_rep ccx_rm_frame_rep_t; +#define CCX_RM_FRAME_REP_FIXED_LEN 4 /* CCX rm frame report fixed length */ + +BWL_PRE_PACKED_STRUCT struct ccx_rm_load_rep { + uint8 channel; + uint8 spare; + uint16 duration; + uint8 fraction; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_load_rep ccx_rm_load_rep_t; +#define CCX_RM_LOAD_REP_LEN 5 /* CCX radio measurement load report length */ + +BWL_PRE_PACKED_STRUCT struct ccx_rm_noise_rep { + uint8 channel; + uint8 spare; + uint16 duration; + uint8 rpi[8]; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_noise_rep ccx_rm_noise_rep_t; +#define CCX_RM_NOISE_REP_LEN 12 /* CCX radio measurement noise report length */ + +/* SSIDL Elements. CCXv4 S53 */ +#define SSIDL_OUI "\x00\x50\xf2" /* SSIDL OUI */ +#define SSIDL_OUI_LEN 3 /* SSIDL OUI length */ +#define SSIDL_TYPE 5 /* SSIDL type */ + +/* extended capability bits */ +#define PRI_EXT_CAP_8021X 1 /* primary ssid supports 802.1x */ +#define PRI_EXT_CAP_WPS 2 /* primary ssid supports WPS */ + +/* hidden ssid capability field */ +#define SEC_CAP_MC_CIPHER_MASK 0x0000000f /* mcast cipher mask */ +#define SEC_CAP_UC_CIPHER_MASK 0x000efff0 /* ucast cipher mask */ +#define SEC_CAP_AKM_MASK 0x7e000000 /* AKM mask */ +#define SEC_CAP_UC_CIPHER_SHIFT 4 /* ucast cipher shift */ +#define SEC_CAP_AKM_SHIFT 25 /* AKM shift */ + +/* SEC_CAP_MC_CIPHER value */ +enum { + MC_CIPHER_NONE, + MC_CIPHER_WEP40, + MC_CIPHER_WEP104, + MC_CIPHER_TKIP, + MC_CIPHER_CCMP, + MC_CIPHER_CKIP_CMIC, + MC_CIPHER_CKIP, + MC_CIPHER_CMIC +}; + +/* SEC_CAP_UC_CIPHER value */ +#define UC_CIPHER_NONE (1 << 0) +#define UC_CIPHER_WEP40 (1 << 1) +#define UC_CIPHER_WEP104 (1 << 2) +#define UC_CIPHER_TKIP (1 << 3) +#define UC_CIPHER_CCMP (1 << 4) +#define UC_CIPHER_CKIP_CMIC (1 << 5) +#define UC_CIPHER_CKIP (1 << 6) +#define UC_CIPHER_CMIC (1 << 7) +#define UC_CIPHER_WPA2_WEP40 (1 << 8) +#define UC_CIPHER_WPA2_WEP104 (1 << 9) +#define UC_CIPHER_WPA2_TKIP (1 << 10) +#define UC_CIPHER_WPA2_CCMP (1 << 11) +#define UC_CIPHER_WPA2_CKIP_CMIC (1 << 12) +#define UC_CIPHER_WPA2_CKIP (1 << 13) +#define UC_CIPHER_WPA2_CMIC (1 << 14) + +/* SEC_CAP_AKM value */ +#define AKM_WPA1_1X (1 << 0) +#define AKM_WPA1_PSK (1 << 1) +#define AKM_WPA2_1X (1 << 2) +#define AKM_WPA2_PSK (1 << 3) +#define AKM_WPA1_CCKM (1 << 4) +#define AKM_WPA2_CCKM (1 << 5) + +BWL_PRE_PACKED_STRUCT struct ccx_hidden_ssid { + uint8 ext_cap; /* hidden ssid extended capability */ + uint32 capability; /* hidden ssid capability */ + uint8 ssid_len; /* ssid name length */ + uint8 ssid[1]; /* ssid. variable length */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_hidden_ssid ccx_hidden_ssid_t; + +/* CCXv4 SSIDL IE */ +BWL_PRE_PACKED_STRUCT struct ccx_ssidl_ie { + uint8 id; /* 221, DOT11_MNG_SSIDL_ID */ + uint8 length; + uint8 oui[3]; /* 00:50:f2 */ + uint8 type; /* 5 */ + uint8 pri_ext_cap; /* primary ssid extended capability */ + /* following fields are optional */ + uint8 ssid_count; /* number of hidden ssids followed */ + ccx_hidden_ssid_t hidden_ssid[1]; /* hidden ssid start */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_ssidl_ie ccx_ssidl_ie_t; + +/* link test. CCXv4 S62 */ +BWL_PRE_PACKED_STRUCT struct ccx_link_test_s { + uint16 frm_num; /* frame number */ + uint32 time; /* time from sender */ + uint8 rsq; /* raw signal quality of request */ + uint8 rss; /* raw signal strength of request */ + uint8 txretried; /* retries in sending previous response */ + uint8 rssi; /* signal strength in dBm of request */ + uint8 sqp; /* signal quality as percent of request */ + uint8 ssp; /* signal strength as percent of request */ + uint8 data[1]; /* start data set by sender */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_link_test_s ccx_link_test_t; +#define CCX_LINK_TEST_REQ_LEN 12 /* line test request length */ + +/* Supported Features Advertisement(SFA) IE. CCXv5 S63 */ +BWL_PRE_PACKED_STRUCT struct ccx_sfa_ie { + uint8 id; /* 221, DOT11_MNG_PROPR_ID */ + uint8 length; /* 5 */ + uint8 oui[3]; /* 00:40:96 */ + uint8 type; /* 14 */ + uint8 capability; /* capability to support CCXv5 features */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_sfa_ie ccx_sfa_ie_t; +#define CCX_SFA_IE_TYPE 0x14 /* SFA IE type */ +/* feature bit in capability field */ +#define CAP_MFP 0x01 /* S67. MFP */ +#define CAP_DIAG_CHANL 0x02 /* S64. Diagnostic channel */ +#define CAP_LOC_SERVICE 0x04 /* S69. Location services */ +#define CAP_EXP_BNDWITH 0x08 /* S70. Expedited Bandwidth Requests */ + +/* MHDR IE. CCXv5 S67 */ +BWL_PRE_PACKED_STRUCT struct ccx_mhdr_ie { + uint8 id; /* 221, DOT11_MNG_PROPR_ID */ + uint8 length; /* 12 */ + uint8 oui[3]; /* 00:40:96 */ + uint8 type; /* 16 */ + uint8 fc[2]; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_mhdr_ie ccx_mhdr_ie_t; +#define CCX_HMDR_IE_TYPE 16 + +#define CKIP_MIC_SIZE 4 /* size of CKIP MIC */ +#define CKIP_SEQ_SIZE 4 /* size of CKIP SEQ */ +#define CKIP_KEY_SIZE 16 /* size of CKIP key */ + +/* 802.11e MSDU Lifetime IE */ +BWL_PRE_PACKED_STRUCT typedef struct { + uint8 oui[DOT11_OUI_LEN]; /* 3 bytes OUI */ + uint8 oui_type; /* OUI Type */ + uint8 tid; /* traffic stream ID */ + uint16 msdu_lifetime; /* time in TU, specify per AC */ +} BWL_POST_PACKED_STRUCT ccx_msdu_lifetime_t; + +/* CCX traffic stream rateset IE */ +BWL_PRE_PACKED_STRUCT typedef struct { + uint8 oui[DOT11_OUI_LEN]; /* 3 bytes OUI */ + uint8 oui_type; /* OUI Type */ + uint8 tid; /* traffic stream ID */ + uint8 rateset[1]; /* nominal rate to use (multiple of 500k) */ +} BWL_POST_PACKED_STRUCT ccx_stream_rs_t; +#define CAC_STREAM_RS_HDR_LEN (DOT11_OUI_LEN + 2) /* len from oui to tid */ + +/* CCX traffic stream metrics IE */ +BWL_PRE_PACKED_STRUCT typedef struct { + uint8 oui[DOT11_OUI_LEN]; /* 3 bytes OUI */ + uint8 oui_type; /* OUI Type */ + uint8 tid; /* traffic stream ID */ + uint8 state; /* metrics enable or disable */ + uint16 measure_interval; /* interval time in TU */ +} BWL_POST_PACKED_STRUCT ccx_ts_metrics_t; + +#define CCX_CAC_TS_METRICS_TYPE 7 /* Traffic Stream Metrics type */ +#define CCX_CAC_TS_RATESET_TYPE 8 /* Traffic Stream Rateset type */ +#define CCX_CAC_MSDU_LIFETIME_TYPE 9 /* MSUD Lifetime type */ + +/* CCX Traffic Stream Metrics IE in IAPP packet */ +BWL_PRE_PACKED_STRUCT typedef struct { + uint16 dialog_token; /* dialog token should set to 0 */ + uint16 id; /* ID should be 0x27 */ + uint16 len; /* len start from token to end of struct */ + uint16 token; /* token should set to 0 */ + uint8 mode; /* mode should set to 0 */ + uint8 type; /* Traffic Stream Metrics type set to 6 */ + uint16 avg_delay; /* average delay in msec */ + uint16 cnt_delay10; /* bucket for <= 10 msec delay */ + uint16 cnt_delay20; /* bucket for > 10 && <= 20 msec delay */ + uint16 cnt_delay40; /* bucket for >20 && <= 40 msec delay */ + uint16 cnt_delay; /* bucket for > 40 msec delay */ + uint32 media_delay; /* average media delay in TU */ + uint16 pkt_loss; /* packet loss per AC */ + uint16 pkt_cnt; /* packet count per AC */ + uint8 roam_cnt; /* roam count */ + uint16 roam_delay; /* roam delay measure in TU */ + /* following fields are added in CCXv5 */ + uint16 used_time; /* defined in section 3.5.1 in the WMM */ + uint8 tid; /* traffic stream ID */ +} BWL_POST_PACKED_STRUCT ccx_tsm_param_t; + +/* ccx_tsm_param_t defines */ +#define CCX_TSM_LEN_DELTA 3 /* length delta between V4 and later versions */ +#define CCX_TSM_LEN (sizeof(ccx_tsm_param_t)) /* length */ +#define CCX_TSM_V4_LEN (CCX_TSM_LEN - CCX_TSM_LEN_DELTA) +#define CCX_TSM_IE_LEN 28 /* length (from token to end of struct) */ +#define CCX_TSM_IE_V4_LEN (CCX_TSM_IE_LEN - CCX_TSM_LEN_DELTA) +#define CCX_TSM_ID 0x27 /* ID */ +#define CCX_TSM_TOKEN 0 /* Token */ +#define CCX_TSM_MODE 0 /* Mode */ +#define CCX_TSM_TYPE 8 /* Type */ +#define CCX_TSM_V4_TYPE 6 /* Type for V4 */ + +/* CCX IAPP packet sent to AP on ts metrics interval */ +#define CCX_TSM_IAPP_PKT_LEN (DOT11_LLC_SNAP_HDR_LEN + CCX_TSM_IAPP_LEN) +#define CCX_TSM_IAPP_PKT_V4_LEN (DOT11_LLC_SNAP_HDR_LEN + CCX_TSM_IAPP_V4_LEN) +#define CCX_TSM_IAPP_LEN (CCX_IAPP_HDR_LEN + CCX_TSM_LEN) +#define CCX_TSM_IAPP_V4_LEN (CCX_IAPP_HDR_LEN + CCX_TSM_V4_LEN) +#define CCX_TSM_IAPP_SUBTYPE 0x81 /* CCX IAPP Subtype for Traffic Stream Metrics */ + +/* CCXv4 S60 PathLoss Measurement req */ +BWL_PRE_PACKED_STRUCT struct ccx_rm_pathlossreq { + uint16 nbursts; /* Number of Bursts */ + uint16 burstinterval; /* Burst Interval in seconds */ + uint8 burstlen; /* Burst len */ + uint16 duration; /* Measurement Duration in TUs 1024 us */ + uint8 txpower; /* Desired txpower -128 to +127dBm */ + struct ether_addr addr; /* multicast Address for the report */ + uint8 nchannels; /* number of Channels */ + uint8 channel[1]; /* Channel list */ +} BWL_POST_PACKED_STRUCT; +typedef struct ccx_rm_pathlossreq ccx_rm_pathlossreq_t; +#define CCX_RM_PATHLOSSREQ_FIXEDLEN 15 + +/* CCXv4 S60 PathLoss Measurement Frame */ +BWL_PRE_PACKED_STRUCT struct ccx_rm_pathlossmeas_frame { + uint16 seq; + int8 txpower; + uint8 txchannel; +} BWL_POST_PACKED_STRUCT; +#define CCX_RM_PATHLOSS_SEQ_MASK 0x0FFF +#define CCX_RM_IAPP_SUBTYPE 0x82 /* CCX IAPP Subtype for Pathloss Measurement */ + + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +#endif /* _802_11_CCX_H_ */
diff --git a/src/common/include/proto/802.11e.h b/src/common/include/proto/802.11e.h new file mode 100644 index 0000000..914d278 --- /dev/null +++ b/src/common/include/proto/802.11e.h
@@ -0,0 +1,120 @@ +/* + * 802.11e protocol header file + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: 802.11e.h 382883 2013-02-04 23:26:09Z $ + */ + +#ifndef _802_11e_H_ +#define _802_11e_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + + +/* WME Traffic Specification (TSPEC) element */ +#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ +#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ + +#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ +#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ +#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ +#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ + +BWL_PRE_PACKED_STRUCT struct tsinfo { + uint8 octets[3]; +} BWL_POST_PACKED_STRUCT; + +typedef struct tsinfo tsinfo_t; + +/* 802.11e TSPEC IE */ +typedef BWL_PRE_PACKED_STRUCT struct tspec { + uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ + uint8 type; /* WME_TYPE */ + uint8 subtype; /* WME_SUBTYPE_TSPEC */ + uint8 version; /* WME_VERSION */ + tsinfo_t tsinfo; /* TS Info bit field */ + uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ + uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ + uint32 min_srv_interval; /* Minimum Service Interval (us) */ + uint32 max_srv_interval; /* Maximum Service Interval (us) */ + uint32 inactivity_interval; /* Inactivity Interval (us) */ + uint32 suspension_interval; /* Suspension Interval (us) */ + uint32 srv_start_time; /* Service Start Time (us) */ + uint32 min_data_rate; /* Minimum Data Rate (bps) */ + uint32 mean_data_rate; /* Mean Data Rate (bps) */ + uint32 peak_data_rate; /* Peak Data Rate (bps) */ + uint32 max_burst_size; /* Maximum Burst Size (bytes) */ + uint32 delay_bound; /* Delay Bound (us) */ + uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ + uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ + uint16 medium_time; /* Medium Time (32 us/s periods) */ +} BWL_POST_PACKED_STRUCT tspec_t; + +#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ + +/* ts_info */ +/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ +#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ +#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ +#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ +#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ +#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ +#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ +#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ +#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ +#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ +#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ +#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ +#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ +/* TS info. user priority mask */ +#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) + +/* Macro to get/set bit(s) field in TSINFO */ +#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) +#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ + TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) +#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) +#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ + TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) + +#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ + ((id) << TS_INFO_TID_SHIFT)) +#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ + ((prio) << TS_INFO_USER_PRIO_SHIFT)) + +/* 802.11e QBSS Load IE */ +#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ +#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ + +#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */ + /* DEFVAL dot11ADDTSResponseTimeout = 1s */ + +/* 802.11e ADDTS status code */ +#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ +#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ +#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ +#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ +#ifdef BCMCCX +#define CCX_STATUS_ASSOC_DENIED_UNKNOWN 0xc8 /* unspecified QoS related failure */ +#define CCX_STATUS_ASSOC_DENIED_AP_POLICY 0xc9 /* TSPEC refused due to AP policy */ +#define CCX_STATUS_ASSOC_DENIED_NO_BW 0xca /* Assoc denied due to AP insufficient BW */ +#define CCX_STATUS_ASSOC_DENIED_BAD_PARAM 0xcb /* one or more TSPEC with invalid parameter */ +#endif /* BCMCCX */ + +/* 802.11e DELTS status code */ +#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ +#define DOT11E_STATUS_END_TS 37 /* END TS */ +#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ +#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ + + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +#endif /* _802_11e_CAC_H_ */
diff --git a/src/common/include/proto/802.1d.h b/src/common/include/proto/802.1d.h new file mode 100644 index 0000000..f2c6e2d --- /dev/null +++ b/src/common/include/proto/802.1d.h
@@ -0,0 +1,30 @@ +/* + * $Copyright Open Broadcom Corporation$ + * + * Fundamental types and constants relating to 802.1D + * + * $Id: 802.1d.h 382882 2013-02-04 23:24:31Z $ + */ + +#ifndef _802_1_D_ +#define _802_1_D_ + + +#define PRIO_8021D_NONE 2 +#define PRIO_8021D_BK 1 +#define PRIO_8021D_BE 0 +#define PRIO_8021D_EE 3 +#define PRIO_8021D_CL 4 +#define PRIO_8021D_VI 5 +#define PRIO_8021D_VO 6 +#define PRIO_8021D_NC 7 +#define MAXPRIO 7 +#define NUMPRIO (MAXPRIO + 1) + +#define ALLPRIO -1 + + +#define PRIO2PREC(prio) \ + (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) + +#endif
diff --git a/src/common/include/proto/802.3.h b/src/common/include/proto/802.3.h new file mode 100644 index 0000000..9901a23 --- /dev/null +++ b/src/common/include/proto/802.3.h
@@ -0,0 +1,34 @@ +/* + * $Copyright Open Broadcom Corporation$ + * + * Fundamental constants relating to 802.3 + * + * $Id: 802.3.h 417943 2013-08-13 07:54:04Z $ + */ + +#ifndef _802_3_h_ +#define _802_3_h_ + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + +#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */ +#define DOT3_OUI_LEN 3 /* 802.3 oui length */ + +BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ + uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ + uint16 length; /* frame length incl header */ + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 type; /* ethertype */ +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +#endif /* #ifndef _802_3_h_ */
diff --git a/src/common/include/proto/bcmeth.h b/src/common/include/proto/bcmeth.h new file mode 100644 index 0000000..f030584 --- /dev/null +++ b/src/common/include/proto/bcmeth.h
@@ -0,0 +1,64 @@ +/* + * Broadcom Ethernettype protocol definitions + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmeth.h 382882 2013-02-04 23:24:31Z $ + */ + + + +#ifndef _BCMETH_H_ +#define _BCMETH_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + + +#include <packed_section_start.h> + + + + + + + +#define BCMILCP_SUBTYPE_RATE 1 +#define BCMILCP_SUBTYPE_LINK 2 +#define BCMILCP_SUBTYPE_CSA 3 +#define BCMILCP_SUBTYPE_LARQ 4 +#define BCMILCP_SUBTYPE_VENDOR 5 +#define BCMILCP_SUBTYPE_FLH 17 + +#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 +#define BCMILCP_SUBTYPE_CERT 32770 +#define BCMILCP_SUBTYPE_SES 32771 + + +#define BCMILCP_BCM_SUBTYPE_RESERVED 0 +#define BCMILCP_BCM_SUBTYPE_EVENT 1 +#define BCMILCP_BCM_SUBTYPE_SES 2 + + +#define BCMILCP_BCM_SUBTYPE_DPT 4 + +#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 +#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 + + +typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr +{ + uint16 subtype; + uint16 length; + uint8 version; + uint8 oui[3]; + + uint16 usr_subtype; +} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; + + + +#include <packed_section_end.h> + +#endif
diff --git a/src/common/include/proto/bcmevent.h b/src/common/include/proto/bcmevent.h new file mode 100644 index 0000000..b129808 --- /dev/null +++ b/src/common/include/proto/bcmevent.h
@@ -0,0 +1,436 @@ +/* + * Broadcom Event protocol definitions + * + * $Copyright Open Broadcom Corporation$ + * + * Dependencies: proto/bcmeth.h + * + * $Id: bcmevent.h 642996 2016-06-11 01:13:46Z $ + * + */ + + + +#ifndef _BCMEVENT_H_ +#define _BCMEVENT_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +#include <proto/bcmeth.h> + + +#include <packed_section_start.h> + +#define BCM_EVENT_MSG_VERSION 2 +#define BCM_MSG_IFNAME_MAX 16 + + +#define WLC_EVENT_MSG_LINK 0x01 +#define WLC_EVENT_MSG_FLUSHTXQ 0x02 +#define WLC_EVENT_MSG_GROUP 0x04 +#define WLC_EVENT_MSG_UNKBSS 0x08 +#define WLC_EVENT_MSG_UNKIF 0x10 + + + + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; + uint32 event_type; + uint32 status; + uint32 reason; + uint32 auth_type; + uint32 datalen; + struct ether_addr addr; + char ifname[BCM_MSG_IFNAME_MAX]; +} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; + + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; + uint32 event_type; + uint32 status; + uint32 reason; + uint32 auth_type; + uint32 datalen; + struct ether_addr addr; + char ifname[BCM_MSG_IFNAME_MAX]; + uint8 ifidx; + uint8 bsscfgidx; +} BWL_POST_PACKED_STRUCT wl_event_msg_t; + + +typedef BWL_PRE_PACKED_STRUCT struct bcm_event { + struct ether_header eth; + bcmeth_hdr_t bcm_hdr; + wl_event_msg_t event; + +} BWL_POST_PACKED_STRUCT bcm_event_t; + +#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) + + +#define WLC_E_SET_SSID 0 +#define WLC_E_JOIN 1 +#define WLC_E_START 2 +#define WLC_E_AUTH 3 +#define WLC_E_AUTH_IND 4 +#define WLC_E_DEAUTH 5 +#define WLC_E_DEAUTH_IND 6 +#define WLC_E_ASSOC 7 +#define WLC_E_ASSOC_IND 8 +#define WLC_E_REASSOC 9 +#define WLC_E_REASSOC_IND 10 +#define WLC_E_DISASSOC 11 +#define WLC_E_DISASSOC_IND 12 +#define WLC_E_QUIET_START 13 +#define WLC_E_QUIET_END 14 +#define WLC_E_BEACON_RX 15 +#define WLC_E_LINK 16 +#define WLC_E_MIC_ERROR 17 +#define WLC_E_NDIS_LINK 18 +#define WLC_E_ROAM 19 +#define WLC_E_TXFAIL 20 +#define WLC_E_PMKID_CACHE 21 +#define WLC_E_RETROGRADE_TSF 22 +#define WLC_E_PRUNE 23 +#define WLC_E_AUTOAUTH 24 +#define WLC_E_EAPOL_MSG 25 +#define WLC_E_SCAN_COMPLETE 26 +#define WLC_E_ADDTS_IND 27 +#define WLC_E_DELTS_IND 28 +#define WLC_E_BCNSENT_IND 29 +#define WLC_E_BCNRX_MSG 30 +#define WLC_E_BCNLOST_MSG 31 +#define WLC_E_ROAM_PREP 32 +#define WLC_E_PFN_NET_FOUND 33 +#define WLC_E_PFN_NET_LOST 34 +#define WLC_E_RESET_COMPLETE 35 +#define WLC_E_JOIN_START 36 +#define WLC_E_ROAM_START 37 +#define WLC_E_ASSOC_START 38 +#define WLC_E_IBSS_ASSOC 39 +#define WLC_E_RADIO 40 +#define WLC_E_PSM_WATCHDOG 41 +#if defined(BCMCCX) && defined(CCX_SDK) +#define WLC_E_CCX_ASSOC_START 42 +#define WLC_E_CCX_ASSOC_ABORT 43 +#endif +#define WLC_E_PROBREQ_MSG 44 +#define WLC_E_SCAN_CONFIRM_IND 45 +#define WLC_E_PSK_SUP 46 +#define WLC_E_COUNTRY_CODE_CHANGED 47 +#define WLC_E_EXCEEDED_MEDIUM_TIME 48 +#define WLC_E_ICV_ERROR 49 +#define WLC_E_UNICAST_DECODE_ERROR 50 +#define WLC_E_MULTICAST_DECODE_ERROR 51 +#define WLC_E_TRACE 52 +#ifdef WLBTAMP +#define WLC_E_BTA_HCI_EVENT 53 +#endif +#define WLC_E_IF 54 +#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 +#define WLC_E_RSSI 56 + +#define WLC_E_PFN_BEST_BATCHING 57 +#define WLC_E_PFN_SCAN_COMPLETE 57 + +#define WLC_E_PFN_BEST_BATCHING 57 +#define WLC_E_EXTLOG_MSG 58 +#define WLC_E_ACTION_FRAME 59 +#define WLC_E_ACTION_FRAME_COMPLETE 60 +#define WLC_E_PRE_ASSOC_IND 61 +#define WLC_E_PRE_REASSOC_IND 62 +#define WLC_E_CHANNEL_ADOPTED 63 +#define WLC_E_AP_STARTED 64 +#define WLC_E_DFS_AP_STOP 65 +#define WLC_E_DFS_AP_RESUME 66 +#define WLC_E_WAI_STA_EVENT 67 +#define WLC_E_WAI_MSG 68 +#define WLC_E_ESCAN_RESULT 69 +#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 +#define WLC_E_PROBRESP_MSG 71 +#define WLC_E_P2P_PROBREQ_MSG 72 +#define WLC_E_DCS_REQUEST 73 +#define WLC_E_FIFO_CREDIT_MAP 74 +#define WLC_E_ACTION_FRAME_RX 75 +#define WLC_E_WAKE_EVENT 76 +#define WLC_E_RM_COMPLETE 77 +#define WLC_E_HTSFSYNC 78 +#define WLC_E_OVERLAY_REQ 79 +#define WLC_E_CSA_COMPLETE_IND 80 +#define WLC_E_EXCESS_PM_WAKE_EVENT 81 +#define WLC_E_PFN_SCAN_NONE 82 + +#define WLC_E_PFN_BSSID_NET_FOUND 82 +#define WLC_E_PFN_SCAN_ALLGONE 83 + +#define WLC_E_PFN_BSSID_NET_LOST 83 +#define WLC_E_GTK_PLUMBED 84 +#define WLC_E_ASSOC_IND_NDIS 85 +#define WLC_E_REASSOC_IND_NDIS 86 +#define WLC_E_ASSOC_REQ_IE 87 +#define WLC_E_ASSOC_RESP_IE 88 +#define WLC_E_ASSOC_RECREATED 89 +#define WLC_E_ACTION_FRAME_RX_NDIS 90 +#define WLC_E_AUTH_REQ 91 +#define WLC_E_TDLS_PEER_EVENT 92 +#define WLC_E_SPEEDY_RECREATE_FAIL 93 +#define WLC_E_NATIVE 94 +#define WLC_E_PKTDELAY_IND 95 +#define WLC_E_PSTA_PRIMARY_INTF_IND 99 +#define WLC_E_EVENT_100 100 +#define WLC_E_BEACON_FRAME_RX 101 +#define WLC_E_SERVICE_FOUND 102 +#define WLC_E_GAS_FRAGMENT_RX 103 +#define WLC_E_GAS_COMPLETE 104 +#define WLC_E_P2PO_ADD_DEVICE 105 +#define WLC_E_P2PO_DEL_DEVICE 106 +#define WLC_E_WNM_STA_SLEEP 107 +#define WLC_E_TXFAIL_THRESH 108 +#define WLC_E_PROXD 109 +#define WLC_E_IBSS_COALESCE 110 +#define WLC_E_AIBSS_TXFAIL 110 +#define WLC_E_CSA_START_IND 121 +#define WLC_E_CSA_DONE_IND 122 +#define WLC_E_CSA_FAILURE_IND 123 +#define WLC_E_CCA_CHAN_QUAL 124 +#define WLC_E_BSSID 125 +#define WLC_E_TX_STAT_ERROR 126 +#define WLC_E_BCMC_CREDIT_SUPPORT 127 +#define WLC_E_PKT_FILTER 164 +#define WLC_E_LAST 165 + +#if (WLC_E_LAST > 165) +#error "WLC_E_LAST: Invalid value for last event; must be <= 155." +#endif + + + +typedef struct { + uint event; + const char *name; +} bcmevent_name_t; + +extern const bcmevent_name_t bcmevent_names[]; +extern const int bcmevent_names_size; + + +#define WLC_E_STATUS_SUCCESS 0 +#define WLC_E_STATUS_FAIL 1 +#define WLC_E_STATUS_TIMEOUT 2 +#define WLC_E_STATUS_NO_NETWORKS 3 +#define WLC_E_STATUS_ABORT 4 +#define WLC_E_STATUS_NO_ACK 5 +#define WLC_E_STATUS_UNSOLICITED 6 +#define WLC_E_STATUS_ATTEMPT 7 +#define WLC_E_STATUS_PARTIAL 8 +#define WLC_E_STATUS_NEWSCAN 9 +#define WLC_E_STATUS_NEWASSOC 10 +#define WLC_E_STATUS_11HQUIET 11 +#define WLC_E_STATUS_SUPPRESS 12 +#define WLC_E_STATUS_NOCHANS 13 +#ifdef BCMCCX +#define WLC_E_STATUS_CCXFASTRM 14 +#endif +#define WLC_E_STATUS_CS_ABORT 15 +#define WLC_E_STATUS_ERROR 16 + + +#define WLC_E_REASON_INITIAL_ASSOC 0 +#define WLC_E_REASON_LOW_RSSI 1 +#define WLC_E_REASON_DEAUTH 2 +#define WLC_E_REASON_DISASSOC 3 +#define WLC_E_REASON_BCNS_LOST 4 + + +#define WLC_E_REASON_FAST_ROAM_FAILED 5 +#define WLC_E_REASON_DIRECTED_ROAM 6 +#define WLC_E_REASON_TSPEC_REJECTED 7 +#define WLC_E_REASON_BETTER_AP 8 +#define WLC_E_REASON_MINTXRATE 9 +#define WLC_E_REASON_TXFAIL 10 +#define WLC_E_REASON_REQUESTED_ROAM 11 + + +#define WLC_E_PRUNE_ENCR_MISMATCH 1 +#define WLC_E_PRUNE_BCAST_BSSID 2 +#define WLC_E_PRUNE_MAC_DENY 3 +#define WLC_E_PRUNE_MAC_NA 4 +#define WLC_E_PRUNE_REG_PASSV 5 +#define WLC_E_PRUNE_SPCT_MGMT 6 +#define WLC_E_PRUNE_RADAR 7 +#define WLC_E_RSN_MISMATCH 8 +#define WLC_E_PRUNE_NO_COMMON_RATES 9 +#define WLC_E_PRUNE_BASIC_RATES 10 +#ifdef BCMCCX +#define WLC_E_PRUNE_CCXFAST_PREVAP 11 +#endif +#define WLC_E_PRUNE_CIPHER_NA 12 +#define WLC_E_PRUNE_KNOWN_STA 13 +#ifdef BCMCCX +#define WLC_E_PRUNE_CCXFAST_DROAM 14 +#endif +#define WLC_E_PRUNE_WDS_PEER 15 +#define WLC_E_PRUNE_QBSS_LOAD 16 +#define WLC_E_PRUNE_HOME_AP 17 +#ifdef BCMCCX +#define WLC_E_PRUNE_AP_BLOCKED 18 +#define WLC_E_PRUNE_NO_DIAG_SUPPORT 19 +#endif + + +#define WLC_E_SUP_OTHER 0 +#define WLC_E_SUP_DECRYPT_KEY_DATA 1 +#define WLC_E_SUP_BAD_UCAST_WEP128 2 +#define WLC_E_SUP_BAD_UCAST_WEP40 3 +#define WLC_E_SUP_UNSUP_KEY_LEN 4 +#define WLC_E_SUP_PW_KEY_CIPHER 5 +#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 +#define WLC_E_SUP_MSG3_IE_MISMATCH 7 +#define WLC_E_SUP_NO_INSTALL_FLAG 8 +#define WLC_E_SUP_MSG3_NO_GTK 9 +#define WLC_E_SUP_GRP_KEY_CIPHER 10 +#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 +#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 +#define WLC_E_SUP_SEND_FAIL 13 +#define WLC_E_SUP_DEAUTH 14 +#define WLC_E_SUP_WPA_PSK_TMO 15 + + + +typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { + uint16 version; + uint16 channel; + int32 rssi; + uint32 mactime; + uint32 rate; +} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; + +#define BCM_RX_FRAME_DATA_VERSION 1 + + +typedef struct wl_event_data_if { + uint8 ifidx; + uint8 opcode; + uint8 reserved; + uint8 bssidx; + uint8 role; +} wl_event_data_if_t; + + +#define WLC_E_IF_ADD 1 +#define WLC_E_IF_DEL 2 +#define WLC_E_IF_CHANGE 3 + + +#define WLC_E_IF_ROLE_STA 0 +#define WLC_E_IF_ROLE_AP 1 +#define WLC_E_IF_ROLE_WDS 2 +#define WLC_E_IF_ROLE_P2P_GO 3 +#define WLC_E_IF_ROLE_P2P_CLIENT 4 +#ifdef WLBTAMP +#define WLC_E_IF_ROLE_BTA_CREATOR 5 +#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6 +#endif + + +typedef struct wl_event_data_rssi { + int32 rssi; + int32 snr; + int32 noise; +} wl_event_data_rssi_t; + + +#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 + + +#define WLC_E_LINK_BCN_LOSS 1 +#define WLC_E_LINK_DISASSOC 2 +#define WLC_E_LINK_ASSOC_REC 3 +#define WLC_E_LINK_BSSCFG_DIS 4 + + +#define WLC_E_OVL_DOWNLOAD 0 +#define WLC_E_OVL_UPDATE_IND 1 + + +#define WLC_E_TDLS_PEER_DISCOVERED 0 +#define WLC_E_TDLS_PEER_CONNECTED 1 +#define WLC_E_TDLS_PEER_DISCONNECTED 2 + +#ifdef WLTDLS + +#define TDLS_AF_CATEGORY 12 + + +#define TDLS_VENDOR_SPECIFIC 127 + +#define TDLS_ACTION_SETUP_REQ 0 +#define TDLS_ACTION_SETUP_RESP 1 +#define TDLS_ACTION_SETUP_CONFIRM 2 +#define TDLS_ACTION_TEARDOWN 3 +#define WLAN_TDLS_SET_WFD_IE 11 +#endif + + + +typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { + uint16 channel; + uint8 dialog_token; + uint8 fragment_id; + uint16 status_code; + uint16 data_len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT wl_event_gas_t; + + +typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { + uint16 length; + uint8 protocol; + uint8 transaction_id; + uint8 status_code; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; + + +typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { + uint16 channel; + uint8 count; + wl_sd_tlv_t tlv[1]; +} BWL_POST_PACKED_STRUCT wl_event_sd_t; + + +#define WLC_E_PKT_FILTER_TIMEOUT 1 + + +#define WLC_E_PROXD_FOUND 1 +#define WLC_E_PROXD_GONE 2 + + + +#define INTFER_EVENT_VERSION 1 +#define INTFER_STREAM_TYPE_NONTCP 1 +#define INTFER_STREAM_TYPE_TCP 2 +#define WLINTFER_STATS_NSMPLS 4 +typedef struct wl_intfer_event { + uint16 version; + uint16 status; + uint8 txfail_histo[WLINTFER_STATS_NSMPLS]; +} wl_intfer_event_t; + + +typedef struct wl_psta_primary_intf_event { + struct ether_addr prim_ea; +} wl_psta_primary_intf_event_t; + + +#include <packed_section_end.h> + +#endif
diff --git a/src/common/include/proto/bcmip.h b/src/common/include/proto/bcmip.h new file mode 100644 index 0000000..acce811 --- /dev/null +++ b/src/common/include/proto/bcmip.h
@@ -0,0 +1,213 @@ +/* + * $Copyright Open Broadcom Corporation$ + * + * Fundamental constants relating to IP Protocol + * + * $Id: bcmip.h 457888 2014-02-25 03:34:39Z $ + */ + +#ifndef _bcmip_h_ +#define _bcmip_h_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + + +#include <packed_section_start.h> + + + +#define IP_VER_OFFSET 0x0 +#define IP_VER_MASK 0xf0 +#define IP_VER_SHIFT 4 +#define IP_VER_4 4 +#define IP_VER_6 6 + +#define IP_VER(ip_body) \ + ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) + +#define IP_PROT_ICMP 0x1 +#define IP_PROT_IGMP 0x2 +#define IP_PROT_TCP 0x6 +#define IP_PROT_UDP 0x11 +#define IP_PROT_ICMP6 0x3a + + +#define IPV4_VER_HL_OFFSET 0 +#define IPV4_TOS_OFFSET 1 +#define IPV4_PKTLEN_OFFSET 2 +#define IPV4_PKTFLAG_OFFSET 6 +#define IPV4_PROT_OFFSET 9 +#define IPV4_CHKSUM_OFFSET 10 +#define IPV4_SRC_IP_OFFSET 12 +#define IPV4_DEST_IP_OFFSET 16 +#define IPV4_OPTIONS_OFFSET 20 +#define IPV4_MIN_HEADER_LEN 20 + + +#define IPV4_VER_MASK 0xf0 +#define IPV4_VER_SHIFT 4 + +#define IPV4_HLEN_MASK 0x0f +#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) + +#define IPV4_ADDR_LEN 4 + +#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ + ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) + +#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ + ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) + +#define IPV4_TOS_DSCP_MASK 0xfc +#define IPV4_TOS_DSCP_SHIFT 2 + +#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) + +#define IPV4_TOS_PREC_MASK 0xe0 +#define IPV4_TOS_PREC_SHIFT 5 + +#define IPV4_TOS_LOWDELAY 0x10 +#define IPV4_TOS_THROUGHPUT 0x8 +#define IPV4_TOS_RELIABILITY 0x4 + +#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) + +#define IPV4_FRAG_RESV 0x8000 +#define IPV4_FRAG_DONT 0x4000 +#define IPV4_FRAG_MORE 0x2000 +#define IPV4_FRAG_OFFSET_MASK 0x1fff + +#define IPV4_ADDR_STR_LEN 16 + + +BWL_PRE_PACKED_STRUCT struct ipv4_addr { + uint8 addr[IPV4_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ipv4_hdr { + uint8 version_ihl; + uint8 tos; + uint16 tot_len; + uint16 id; + uint16 frag; + uint8 ttl; + uint8 prot; + uint16 hdr_chksum; + uint8 src_ip[IPV4_ADDR_LEN]; + uint8 dst_ip[IPV4_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + + +#define IPV6_PAYLOAD_LEN_OFFSET 4 +#define IPV6_NEXT_HDR_OFFSET 6 +#define IPV6_HOP_LIMIT_OFFSET 7 +#define IPV6_SRC_IP_OFFSET 8 +#define IPV6_DEST_IP_OFFSET 24 + + +#define IPV6_TRAFFIC_CLASS(ipv6_body) \ + (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ + ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) + +#define IPV6_FLOW_LABEL(ipv6_body) \ + (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ + (((uint8 *)(ipv6_body))[2] << 8) | \ + (((uint8 *)(ipv6_body))[3])) + +#define IPV6_PAYLOAD_LEN(ipv6_body) \ + ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ + ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) + +#define IPV6_NEXT_HDR(ipv6_body) \ + (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) + +#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) + +#define IPV6_ADDR_LEN 16 + + +#define IP_TOS46(ip_body) \ + (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ + IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) + +#define IP_DSCP46(ip_body) (IP_TOS46(ip_body) >> IPV4_TOS_DSCP_SHIFT); + + +#define IPV6_EXTHDR_HOP 0 +#define IPV6_EXTHDR_ROUTING 43 +#define IPV6_EXTHDR_FRAGMENT 44 +#define IPV6_EXTHDR_AUTH 51 +#define IPV6_EXTHDR_NONE 59 +#define IPV6_EXTHDR_DEST 60 + +#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ + ((prot) == IPV6_EXTHDR_ROUTING) || \ + ((prot) == IPV6_EXTHDR_FRAGMENT) || \ + ((prot) == IPV6_EXTHDR_AUTH) || \ + ((prot) == IPV6_EXTHDR_NONE) || \ + ((prot) == IPV6_EXTHDR_DEST)) + +#define IPV6_MIN_HLEN 40 + +#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) + +BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { + uint8 nexthdr; + uint8 hdrlen; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { + uint8 nexthdr; + uint8 rsvd; + uint16 frag_off; + uint32 ident; +} BWL_POST_PACKED_STRUCT; + +static INLINE int32 +ipv6_exthdr_len(uint8 *h, uint8 *proto) +{ + uint16 len = 0, hlen; + struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; + + while (IPV6_EXTHDR(eh->nexthdr)) { + if (eh->nexthdr == IPV6_EXTHDR_NONE) + return -1; + else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) + hlen = 8; + else if (eh->nexthdr == IPV6_EXTHDR_AUTH) + hlen = (eh->hdrlen + 2) << 2; + else + hlen = IPV6_EXTHDR_LEN(eh); + + len += hlen; + eh = (struct ipv6_exthdr *)(h + len); + } + + *proto = eh->nexthdr; + return len; +} + +#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) + +#define IPV4_MCAST_TO_ETHER_MCAST(ipv4, ether) \ +{ \ + ether[0] = 0x01; \ + ether[1] = 0x00; \ + ether[2] = 0x5E; \ + ether[3] = (ipv4 & 0x7f0000) >> 16; \ + ether[4] = (ipv4 & 0xff00) >> 8; \ + ether[5] = (ipv4 & 0xff); \ +} + + +#include <packed_section_end.h> + +#define IPV4_ADDR_STR "%d.%d.%d.%d" +#define IPV4_ADDR_TO_STR(addr) ((uint32)addr & 0xff000000) >> 24, \ + ((uint32)addr & 0x00ff0000) >> 16, \ + ((uint32)addr & 0x0000ff00) >> 8, \ + ((uint32)addr & 0x000000ff) + +#endif
diff --git a/src/common/include/proto/bcmipv6.h b/src/common/include/proto/bcmipv6.h new file mode 100644 index 0000000..58f9752 --- /dev/null +++ b/src/common/include/proto/bcmipv6.h
@@ -0,0 +1,141 @@ +/* + * $Copyright Open Broadcom Corporation$ + * + * Fundamental constants relating to Neighbor Discovery Protocol + * + * $Id: bcmipv6.h 399482 2013-04-30 09:24:37Z $ + */ + +#ifndef _bcmipv6_h_ +#define _bcmipv6_h_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + +/* Extension headers */ +#define IPV6_EXT_HOP 0 +#define IPV6_EXT_ROUTE 43 +#define IPV6_EXT_FRAG 44 +#define IPV6_EXT_DEST 60 +#define IPV6_EXT_ESEC 50 +#define IPV6_EXT_AUTH 51 + +/* Minimum size (extension header "word" length) */ +#define IPV6_EXT_WORD 8 + +/* Offsets for most extension headers */ +#define IPV6_EXT_NEXTHDR 0 +#define IPV6_EXT_HDRLEN 1 + +/* Constants specific to fragmentation header */ +#define IPV6_FRAG_MORE_MASK 0x0001 +#define IPV6_FRAG_MORE_SHIFT 0 +#define IPV6_FRAG_OFFS_MASK 0xfff8 +#define IPV6_FRAG_OFFS_SHIFT 3 + +/* For icmpv6 */ +#define ICMPV6_HEADER_TYPE 0x3A +#define ICMPV6_PKT_TYPE_NS 135 +#define ICMPV6_PKT_TYPE_NA 136 + +#define ICMPV6_ND_OPT_TYPE_TARGET_MAC 2 +#define ICMPV6_ND_OPT_TYPE_SRC_MAC 1 + +#define ICMPV6_ND_OPT_LEN_LINKADDR 1 + +#define ICMPV6_ND_OPT_LEN_LINKADDR 1 + +#define IPV6_VERSION 6 +#define IPV6_HOP_LIMIT 255 + +#define IPV6_ADDR_NULL(a) ((a[0] | a[1] | a[2] | a[3] | a[4] | \ + a[5] | a[6] | a[7] | a[8] | a[9] | \ + a[10] | a[11] | a[12] | a[13] | \ + a[14] | a[15]) == 0) + +#define IPV6_ADDR_LOCAL(a) (((a[0] == 0xfe) && (a[1] & 0x80))? TRUE: FALSE) + +/* IPV6 address */ +BWL_PRE_PACKED_STRUCT struct ipv6_addr { + uint8 addr[16]; +} BWL_POST_PACKED_STRUCT; + + +/* ICMPV6 Header */ +BWL_PRE_PACKED_STRUCT struct icmp6_hdr { + uint8 icmp6_type; + uint8 icmp6_code; + uint16 icmp6_cksum; + BWL_PRE_PACKED_STRUCT union { + uint32 reserved; + BWL_PRE_PACKED_STRUCT struct nd_advt { + uint32 reserved1:5, + override:1, + solicited:1, + router:1, + reserved2:24; + } BWL_POST_PACKED_STRUCT nd_advt; + } BWL_POST_PACKED_STRUCT opt; +} BWL_POST_PACKED_STRUCT; + +/* Ipv6 Header Format */ +BWL_PRE_PACKED_STRUCT struct ipv6_hdr { + uint8 priority:4, + version:4; + uint8 flow_lbl[3]; + uint16 payload_len; + uint8 nexthdr; + uint8 hop_limit; + struct ipv6_addr saddr; + struct ipv6_addr daddr; +} BWL_POST_PACKED_STRUCT; + +/* Neighbor Advertisement/Solicitation Packet Structure */ +BWL_PRE_PACKED_STRUCT struct nd_msg { + struct icmp6_hdr icmph; + struct ipv6_addr target; +} BWL_POST_PACKED_STRUCT; + + +/* Neighibor Solicitation/Advertisement Optional Structure */ +BWL_PRE_PACKED_STRUCT struct nd_msg_opt { + uint8 type; + uint8 len; + uint8 mac_addr[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; + +/* Ipv6 Fragmentation Header */ +BWL_PRE_PACKED_STRUCT struct ipv6_frag { + uint8 nexthdr; + uint8 reserved; + uint16 frag_offset; + uint32 ident; +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +static const struct ipv6_addr all_node_ipv6_maddr = { + { 0xff, 0x2, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1 + }}; + +#define IPV6_ISMULTI(a) (a[0] == 0xff) + +#define IPV6_MCAST_TO_ETHER_MCAST(ipv6, ether) \ +{ \ + ether[0] = 0x33; \ + ether[1] = 0x33; \ + ether[2] = ipv6[12]; \ + ether[3] = ipv6[13]; \ + ether[4] = ipv6[14]; \ + ether[5] = ipv6[15]; \ +} + +#endif /* !defined(_bcmipv6_h_) */
diff --git a/src/common/include/proto/bcmtcp.h b/src/common/include/proto/bcmtcp.h new file mode 100644 index 0000000..f9af5e3 --- /dev/null +++ b/src/common/include/proto/bcmtcp.h
@@ -0,0 +1,72 @@ +/* + * Fundamental constants relating to TCP Protocol + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmtcp.h 457888 2014-02-25 03:34:39Z $ + */ + +#ifndef _bcmtcp_h_ +#define _bcmtcp_h_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + + +#include <packed_section_start.h> + + +#define TCP_SRC_PORT_OFFSET 0 +#define TCP_DEST_PORT_OFFSET 2 +#define TCP_SEQ_NUM_OFFSET 4 +#define TCP_ACK_NUM_OFFSET 8 +#define TCP_HLEN_OFFSET 12 +#define TCP_FLAGS_OFFSET 13 +#define TCP_CHKSUM_OFFSET 16 + +#define TCP_PORT_LEN 2 + + +#define TCP_FLAG_URG 0x20 +#define TCP_FLAG_ACK 0x10 +#define TCP_FLAG_PSH 0x08 +#define TCP_FLAG_RST 0x04 +#define TCP_FLAG_SYN 0x02 +#define TCP_FLAG_FIN 0x01 + +#define TCP_HLEN_MASK 0xf000 +#define TCP_HLEN_SHIFT 12 + + +BWL_PRE_PACKED_STRUCT struct bcmtcp_hdr +{ + uint16 src_port; + uint16 dst_port; + uint32 seq_num; + uint32 ack_num; + uint16 hdrlen_rsvd_flags; + uint16 tcpwin; + uint16 chksum; + uint16 urg_ptr; +} BWL_POST_PACKED_STRUCT; + +#define TCP_MIN_HEADER_LEN 20 + +#define TCP_HDRLEN_MASK 0xf0 +#define TCP_HDRLEN_SHIFT 4 +#define TCP_HDRLEN(hdrlen) (((hdrlen) & TCP_HDRLEN_MASK) >> TCP_HDRLEN_SHIFT) + +#define TCP_FLAGS_MASK 0x1f +#define TCP_FLAGS(hdrlen) ((hdrlen) & TCP_FLAGS_MASK) + + +#include <packed_section_end.h> + + +#define IS_TCPSEQ_GE(a, b) ((a - b) < NBITVAL(31)) +#define IS_TCPSEQ_LE(a, b) ((b - a) < NBITVAL(31)) +#define IS_TCPSEQ_GT(a, b) !IS_TCPSEQ_LE(a, b) +#define IS_TCPSEQ_LT(a, b) !IS_TCPSEQ_GE(a, b) + +#endif
diff --git a/src/common/include/proto/bt_amp_hci.h b/src/common/include/proto/bt_amp_hci.h new file mode 100644 index 0000000..bc91f84 --- /dev/null +++ b/src/common/include/proto/bt_amp_hci.h
@@ -0,0 +1,423 @@ +/* + * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bt_amp_hci.h 382882 2013-02-04 23:24:31Z $ +*/ + +#ifndef _bt_amp_hci_h +#define _bt_amp_hci_h + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + + +/* AMP HCI CMD packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { + uint16 opcode; + uint8 plen; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; + +#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) +#define HCI_CMD_DATA_SIZE 255 + +/* AMP HCI CMD opcode layout */ +#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) +#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) +#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) + +/* AMP HCI command opcodes */ +#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) +#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) +#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) +#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) +#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) +#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) +#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) +#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) +#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) +#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) +#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) +#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) +#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) +#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) +#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) +#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) +#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) +#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) +#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) +#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) +#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) +#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) +#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) +#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) +#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) +#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) +#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) +#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) +#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) +#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) +#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) +#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) +#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) + +/* AMP HCI command parameters */ +typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { + uint8 plh; + uint8 offset[2]; /* length so far */ + uint8 max_remote[2]; +} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { + uint8 plh; + uint8 offset[2]; + uint8 len[2]; + uint8 frag[1]; +} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { + uint8 plh; + uint8 key_length; + uint8 key_type; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { + uint8 plh; + uint8 reason; +} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { + uint8 plh; + uint8 txflow[16]; + uint8 rxflow[16]; +} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { + uint8 id; + uint8 service_type; + uint8 max_sdu[2]; + uint8 sdu_ia_time[4]; + uint8 access_latency[4]; + uint8 flush_timeout[4]; +} BWL_POST_PACKED_STRUCT ext_flow_spec_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { + uint8 llh[2]; + uint8 txflow[16]; + uint8 rxflow[16]; +} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct plh_pad { + uint8 plh; + uint8 pad; +} BWL_POST_PACKED_STRUCT plh_pad_t; + +typedef BWL_PRE_PACKED_STRUCT union hci_handle { + uint16 bredr; + plh_pad_t amp; +} BWL_POST_PACKED_STRUCT hci_handle_t; + +typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { + hci_handle_t handle; + uint8 timeout[2]; +} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { + uint8 llh[2]; + uint8 befto[4]; +} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { + uint8 plh; + uint8 srm; +} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { + uint8 ld_aware; + uint8 ld[2]; + uint8 ld_opts; + uint8 l_opts; +} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { + uint8 llh[2]; + uint8 packet_type; +} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; + +/* Generic AMP extended flow spec service types */ +#define EFS_SVCTYPE_NO_TRAFFIC 0 +#define EFS_SVCTYPE_BEST_EFFORT 1 +#define EFS_SVCTYPE_GUARANTEED 2 + +/* AMP HCI event packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { + uint8 ecode; + uint8 plen; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT amp_hci_event_t; + +#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) + +/* AMP HCI event codes */ +#define HCI_Command_Complete 0x0E +#define HCI_Command_Status 0x0F +#define HCI_Flush_Occurred 0x11 +#define HCI_Enhanced_Flush_Complete 0x39 +#define HCI_Physical_Link_Complete 0x40 +#define HCI_Channel_Select 0x41 +#define HCI_Disconnect_Physical_Link_Complete 0x42 +#define HCI_Logical_Link_Complete 0x45 +#define HCI_Disconnect_Logical_Link_Complete 0x46 +#define HCI_Flow_Spec_Modify_Complete 0x47 +#define HCI_Number_of_Completed_Data_Blocks 0x48 +#define HCI_Short_Range_Mode_Change_Complete 0x4C +#define HCI_Status_Change_Event 0x4D +#define HCI_Vendor_Specific 0xFF + +/* AMP HCI event mask bit positions */ +#define HCI_Physical_Link_Complete_Event_Mask 0x0001 +#define HCI_Channel_Select_Event_Mask 0x0002 +#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 +#define HCI_Logical_Link_Complete_Event_Mask 0x0020 +#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 +#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 +#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 +#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 +#define HCI_Status_Change_Event_Mask 0x2000 +#define HCI_All_Event_Mask 0x31e7 +/* AMP HCI event parameters */ +typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { + uint8 status; + uint8 cmdpkts; + uint16 opcode; +} BWL_POST_PACKED_STRUCT cmd_status_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { + uint8 cmdpkts; + uint16 opcode; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { + uint16 handle; +} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { + uint8 status; + uint8 plh; +} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { + uint8 status; + uint8 plh; + uint16 len; + uint8 frag[1]; +} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { + uint8 status; + uint8 AMP_status; + uint32 bandwidth; + uint32 gbandwidth; + uint32 latency; + uint32 PDU_size; + uint8 ctrl_type; + uint16 PAL_cap; + uint16 AMP_ASSOC_len; + uint32 max_flush_timeout; + uint32 be_flush_timeout; +} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { + uint8 status; + uint16 llh; + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { + uint8 status; + uint16 llh; + uint8 reason; +} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { + uint8 status; + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { + uint8 status; + uint16 llh; +} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { + uint8 status; + uint8 plh; +} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { + uint8 status; + uint8 plh; + uint8 reason; +} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { + uint8 status; + hci_handle_t handle; + uint16 timeout; +} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { + uint8 status; + uint16 timeout; +} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { + uint8 status; + uint16 ACL_pkt_len; + uint16 data_block_len; + uint16 data_block_num; +} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct data_blocks { + uint16 handle; + uint16 pkts; + uint16 blocks; +} BWL_POST_PACKED_STRUCT data_blocks_t; + +typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { + uint16 num_blocks; + uint8 num_handles; + data_blocks_t completed[1]; +} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { + uint8 status; + uint32 befto; +} BWL_POST_PACKED_STRUCT befto_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { + uint8 status; + uint8 plh; + uint8 srm; +} BWL_POST_PACKED_STRUCT srm_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { + uint8 status; + uint8 llh[2]; + uint16 counter; +} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { + uint8 status; + uint8 llh[2]; +} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { + uint8 status; + hci_handle_t handle; + uint8 link_quality; +} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { + uint8 status; + uint8 ld_aware; + uint8 ld[2]; + uint8 ld_opts; + uint8 l_opts; +} BWL_POST_PACKED_STRUCT ld_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { + uint16 handle; +} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { + uint8 len; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { + uint8 status; + uint8 hci_version; + uint16 hci_revision; + uint8 pal_version; + uint16 mfg_name; + uint16 pal_subversion; +} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; + +#define MAX_SUPPORTED_CMD_BYTE 64 +typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { + uint8 status; + uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; +} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { + uint8 status; + uint8 amp_status; +} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; + +/* AMP HCI error codes */ +#define HCI_SUCCESS 0x00 +#define HCI_ERR_ILLEGAL_COMMAND 0x01 +#define HCI_ERR_NO_CONNECTION 0x02 +#define HCI_ERR_MEMORY_FULL 0x07 +#define HCI_ERR_CONNECTION_TIMEOUT 0x08 +#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 +#define HCI_ERR_CONNECTION_EXISTS 0x0B +#define HCI_ERR_CONNECTION_DISALLOWED 0x0C +#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 +#define HCI_ERR_UNSUPPORTED_VALUE 0x11 +#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 +#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 +#define HCI_ERR_UNSPECIFIED 0x1F +#define HCI_ERR_UNIT_KEY_USED 0x26 +#define HCI_ERR_QOS_REJECTED 0x2D +#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 +#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 +#define HCI_ERR_CHANNEL_MOVE 0xFF + +/* AMP HCI ACL Data packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { + uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ + uint16 dlen; /* data total length */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; + +#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) + +#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) +#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) + +#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) +#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) + +/* AMP Activity Report packet formats */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { + uint8 ScheduleKnown; + uint8 NumReports; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; + +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { + uint32 StartTime; + uint32 Duration; + uint32 Periodicity; +} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; + +#define HCI_AR_SCHEDULE_KNOWN 0x01 + + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +#endif /* _bt_amp_hci_h_ */
diff --git a/src/common/include/proto/eapol.h b/src/common/include/proto/eapol.h new file mode 100644 index 0000000..3f283a6 --- /dev/null +++ b/src/common/include/proto/eapol.h
@@ -0,0 +1,193 @@ +/* + * 802.1x EAPOL definitions + * + * See + * IEEE Std 802.1X-2001 + * IEEE 802.1X RADIUS Usage Guidelines + * + * Copyright Open Broadcom Corporation + * + * $Id: eapol.h 452678 2014-01-31 19:16:29Z $ + */ + +#ifndef _eapol_h_ +#define _eapol_h_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + +#include <bcmcrypto/aeskeywrap.h> + +/* EAPOL for 802.3/Ethernet */ +typedef BWL_PRE_PACKED_STRUCT struct { + struct ether_header eth; /* 802.3/Ethernet header */ + unsigned char version; /* EAPOL protocol version */ + unsigned char type; /* EAPOL type */ + unsigned short length; /* Length of body */ + unsigned char body[1]; /* Body (optional) */ +} BWL_POST_PACKED_STRUCT eapol_header_t; + +#define EAPOL_HEADER_LEN 18 + +typedef struct { + unsigned char version; /* EAPOL protocol version */ + unsigned char type; /* EAPOL type */ + unsigned short length; /* Length of body */ +} eapol_hdr_t; + +#define EAPOL_HDR_LEN 4 + +/* EAPOL version */ +#define WPA2_EAPOL_VERSION 2 +#define WPA_EAPOL_VERSION 1 +#define LEAP_EAPOL_VERSION 1 +#define SES_EAPOL_VERSION 1 + +/* EAPOL types */ +#define EAP_PACKET 0 +#define EAPOL_START 1 +#define EAPOL_LOGOFF 2 +#define EAPOL_KEY 3 +#define EAPOL_ASF 4 + +/* EAPOL-Key types */ +#define EAPOL_RC4_KEY 1 +#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ +#define EAPOL_WPA_KEY 254 /* WPA */ + +/* RC4 EAPOL-Key header field sizes */ +#define EAPOL_KEY_REPLAY_LEN 8 +#define EAPOL_KEY_IV_LEN 16 +#define EAPOL_KEY_SIG_LEN 16 + +/* RC4 EAPOL-Key */ +typedef BWL_PRE_PACKED_STRUCT struct { + unsigned char type; /* Key Descriptor Type */ + unsigned short length; /* Key Length (unaligned) */ + unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ + unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ + unsigned char index; /* Key Flags & Index */ + unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ + unsigned char key[1]; /* Key (optional) */ +} BWL_POST_PACKED_STRUCT eapol_key_header_t; + +#define EAPOL_KEY_HEADER_LEN 44 + +/* RC4 EAPOL-Key flags */ +#define EAPOL_KEY_FLAGS_MASK 0x80 +#define EAPOL_KEY_BROADCAST 0 +#define EAPOL_KEY_UNICAST 0x80 + +/* RC4 EAPOL-Key index */ +#define EAPOL_KEY_INDEX_MASK 0x7f + +/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ +#define EAPOL_WPA_KEY_REPLAY_LEN 8 +#define EAPOL_WPA_KEY_NONCE_LEN 32 +#define EAPOL_WPA_KEY_IV_LEN 16 +#define EAPOL_WPA_KEY_RSC_LEN 8 +#define EAPOL_WPA_KEY_ID_LEN 8 +#define EAPOL_WPA_KEY_MIC_LEN 16 +#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) +#define EAPOL_WPA_MAX_KEY_SIZE 32 + +/* WPA EAPOL-Key */ +typedef BWL_PRE_PACKED_STRUCT struct { + unsigned char type; /* Key Descriptor Type */ + unsigned short key_info; /* Key Information (unaligned) */ + unsigned short key_len; /* Key Length (unaligned) */ + unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ + unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ + unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ + unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ + unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ + unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ + unsigned short data_len; /* Key Data Length */ + unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ +} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; + +#define EAPOL_WPA_KEY_LEN 95 + +/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ +#define WPA_KEY_DESC_V1 0x01 +#define WPA_KEY_DESC_V2 0x02 +#define WPA_KEY_DESC_V3 0x03 +#define WPA_KEY_PAIRWISE 0x08 +#define WPA_KEY_INSTALL 0x40 +#define WPA_KEY_ACK 0x80 +#define WPA_KEY_MIC 0x100 +#define WPA_KEY_SECURE 0x200 +#define WPA_KEY_ERROR 0x400 +#define WPA_KEY_REQ 0x800 + +#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 + +/* WPA-only KEY KEY_INFO bits */ +#define WPA_KEY_INDEX_0 0x00 +#define WPA_KEY_INDEX_1 0x10 +#define WPA_KEY_INDEX_2 0x20 +#define WPA_KEY_INDEX_3 0x30 +#define WPA_KEY_INDEX_MASK 0x30 +#define WPA_KEY_INDEX_SHIFT 0x04 + +/* 802.11i/WPA2-only KEY KEY_INFO bits */ +#define WPA_KEY_ENCRYPTED_DATA 0x1000 + +/* Key Data encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 type; + uint8 length; + uint8 oui[3]; + uint8 subtype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; + +#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 + +#define WPA2_KEY_DATA_SUBTYPE_GTK 1 +#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 +#define WPA2_KEY_DATA_SUBTYPE_MAC 3 +#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 +#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 + +/* GTK encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 flags; + uint8 reserved; + uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; + +#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 + +#define WPA2_GTK_INDEX_MASK 0x03 +#define WPA2_GTK_INDEX_SHIFT 0x00 + +#define WPA2_GTK_TRANSMIT 0x04 + +/* IGTK encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 key_id; + uint8 ipn[6]; + uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; + +#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 + +/* STAKey encapsulation */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 reserved[2]; + uint8 mac[ETHER_ADDR_LEN]; + uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; +} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; + +#define WPA2_KEY_DATA_PAD 0xdd + + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +#endif /* _eapol_h_ */
diff --git a/src/common/include/proto/ethernet.h b/src/common/include/proto/ethernet.h new file mode 100644 index 0000000..ba06a33 --- /dev/null +++ b/src/common/include/proto/ethernet.h
@@ -0,0 +1,174 @@ +/* + * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: ethernet.h 403353 2013-05-20 14:05:33Z $ + */ + +#ifndef _NET_ETHERNET_H_ +#define _NET_ETHERNET_H_ + +#ifndef _TYPEDEFS_H_ +#include "typedefs.h" +#endif + + +#include <packed_section_start.h> + + + +#define ETHER_ADDR_LEN 6 + + +#define ETHER_TYPE_LEN 2 + + +#define ETHER_CRC_LEN 4 + + +#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) + + +#define ETHER_MIN_LEN 64 + + +#define ETHER_MIN_DATA 46 + + +#define ETHER_MAX_LEN 1518 + + +#define ETHER_MAX_DATA 1500 + + +#define ETHER_TYPE_MIN 0x0600 +#define ETHER_TYPE_IP 0x0800 +#define ETHER_TYPE_ARP 0x0806 +#define ETHER_TYPE_8021Q 0x8100 +#define ETHER_TYPE_IPV6 0x86dd +#define ETHER_TYPE_BRCM 0x886c +#define ETHER_TYPE_802_1X 0x888e +#ifdef PLC +#define ETHER_TYPE_88E1 0x88e1 +#define ETHER_TYPE_8912 0x8912 +#define ETHER_TYPE_GIGLED 0xffff +#endif +#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 +#define ETHER_TYPE_WAI 0x88b4 +#define ETHER_TYPE_89_0D 0x890d + +#define ETHER_TYPE_PPP_SES 0x8864 + +#define ETHER_TYPE_IAPP_L2_UPDATE 0x6 + + +#define ETHER_BRCM_SUBTYPE_LEN 4 + + +#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) +#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) +#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) + + +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ + ((uint8 *)ea)[0] = 0x01; \ + ((uint8 *)ea)[1] = 0x00; \ + ((uint8 *)ea)[2] = 0x5e; \ + ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ + ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ + ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ +} + +#ifndef __INCif_etherh + +BWL_PRE_PACKED_STRUCT struct ether_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 ether_type; +} BWL_POST_PACKED_STRUCT; + + +BWL_PRE_PACKED_STRUCT struct ether_addr { + uint8 octet[ETHER_ADDR_LEN]; +} BWL_POST_PACKED_STRUCT; +#endif + + +#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) +#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) +#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) +#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) + + +#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) + + +#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) + + + +#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \ + (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \ + (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2])) + +#define ether_cmp(a, b) eacmp(a, b) + + +#define eacopy(s, d) \ +do { \ + ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \ + ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \ + ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ +} while (0) + +#define ether_copy(s, d) eacopy(s, d) + + +#define ether_rcopy(s, d) \ +do { \ + ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \ + ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \ + ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \ +} while (0) + + + +static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; +static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; +static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; + +#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \ + ((const uint8 *)(ea))[1] & \ + ((const uint8 *)(ea))[2] & \ + ((const uint8 *)(ea))[3] & \ + ((const uint8 *)(ea))[4] & \ + ((const uint8 *)(ea))[5]) == 0xff) +#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \ + ((const uint8 *)(ea))[1] | \ + ((const uint8 *)(ea))[2] | \ + ((const uint8 *)(ea))[3] | \ + ((const uint8 *)(ea))[4] | \ + ((const uint8 *)(ea))[5]) == 0) + +#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \ + ((const uint16 *)(da))[1] | \ + ((const uint16 *)(da))[2]) == 0) +#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa) + +#define ETHER_MOVE_HDR(d, s) \ +do { \ + struct ether_header t; \ + t = *(struct ether_header *)(s); \ + *(struct ether_header *)(d) = t; \ +} while (0) + +#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) + + +#include <packed_section_end.h> + +#endif
diff --git a/src/common/include/proto/p2p.h b/src/common/include/proto/p2p.h new file mode 100644 index 0000000..f4077ac --- /dev/null +++ b/src/common/include/proto/p2p.h
@@ -0,0 +1,574 @@ +/* + * $Copyright Open Broadcom Corporation$ + * + * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) + * + * $Id: p2p.h 444066 2013-12-18 12:49:24Z $ + */ + +#ifndef _P2P_H_ +#define _P2P_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif +#include <wlioctl.h> +#include <proto/802.11.h> + + +#include <packed_section_start.h> + + + +#define P2P_OUI WFA_OUI +#define P2P_VER WFA_OUI_TYPE_P2P + +#define P2P_IE_ID 0xdd + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { + uint8 id; + uint8 len; + uint8 OUI[3]; + uint8 oui_type; + uint8 subelts[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ie wifi_p2p_ie_t; + +#define P2P_IE_FIXED_LEN 6 + +#define P2P_ATTR_ID_OFF 0 +#define P2P_ATTR_LEN_OFF 1 +#define P2P_ATTR_DATA_OFF 3 + +#define P2P_ATTR_ID_LEN 1 +#define P2P_ATTR_LEN_LEN 2 +#define P2P_ATTR_HDR_LEN 3 + + +#define P2P_SEID_STATUS 0 +#define P2P_SEID_MINOR_RC 1 +#define P2P_SEID_P2P_INFO 2 +#define P2P_SEID_DEV_ID 3 +#define P2P_SEID_INTENT 4 +#define P2P_SEID_CFG_TIMEOUT 5 +#define P2P_SEID_CHANNEL 6 +#define P2P_SEID_GRP_BSSID 7 +#define P2P_SEID_XT_TIMING 8 +#define P2P_SEID_INTINTADDR 9 +#define P2P_SEID_P2P_MGBTY 10 +#define P2P_SEID_CHAN_LIST 11 +#define P2P_SEID_ABSENCE 12 +#define P2P_SEID_DEV_INFO 13 +#define P2P_SEID_GROUP_INFO 14 +#define P2P_SEID_GROUP_ID 15 +#define P2P_SEID_P2P_IF 16 +#define P2P_SEID_OP_CHANNEL 17 +#define P2P_SEID_INVITE_FLAGS 18 +#define P2P_SEID_VNDR 221 + +#define P2P_SE_VS_ID_SERVICES 0x1b + + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { + uint8 eltId; + uint8 len[2]; + uint8 dev; + uint8 group; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; + + +#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 +#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 +#define P2P_CAPSE_DEV_CONCURRENT 0x4 +#define P2P_CAPSE_DEV_INFRA_MAN 0x8 +#define P2P_CAPSE_DEV_LIMIT 0x10 +#define P2P_CAPSE_INVITE_PROC 0x20 + + +#define P2P_CAPSE_GRP_OWNER 0x1 +#define P2P_CAPSE_PERSIST_GRP 0x2 +#define P2P_CAPSE_GRP_LIMIT 0x4 +#define P2P_CAPSE_GRP_INTRA_BSS 0x8 +#define P2P_CAPSE_GRP_X_CONNECT 0x10 +#define P2P_CAPSE_GRP_PERSISTENT 0x20 +#define P2P_CAPSE_GRP_FORMATION 0x40 + + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { + uint8 eltId; + uint8 len[2]; + uint8 intent; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { + uint8 eltId; + uint8 len[2]; + uint8 go_tmo; + uint8 client_tmo; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { + uint8 eltId; + uint8 len[2]; + uint8 country[3]; + uint8 op_class; + uint8 channel; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { + uint8 eltId; + uint8 len[2]; + uint8 mac[6]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { + uint8 eltId; + uint8 len[2]; + uint8 mac[6]; + uint8 ssid[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { + uint8 eltId; + uint8 len[2]; + uint8 mac[6]; + uint8 ifaddrs; + uint8 ifaddr[1][6]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { + uint8 eltId; + uint8 len[2]; + uint8 status; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; + + +#define P2P_STATSE_SUCCESS 0 + +#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 + +#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL + +#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 + +#define P2P_STATSE_FAIL_LIMIT_REACHED 3 + +#define P2P_STATSE_FAIL_INVALID_PARAMS 4 + +#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 + +#define P2P_STATSE_FAIL_PROTO_ERROR 6 + +#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 + +#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 + +#define P2P_STATSE_FAIL_INTENT 9 + +#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 + +#define P2P_STATSE_FAIL_USER_REJECT 11 + + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { + uint8 eltId; + uint8 len[2]; + uint8 avail[2]; + uint8 interval[2]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; + +#define P2P_EXT_MIN 10 + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { + uint8 eltId; + uint8 len[2]; + uint8 mac[6]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { + uint8 eltId; + uint8 len[2]; + uint8 band; + uint8 channel; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; + + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { + uint8 band; + uint8 num_channels; + uint8 channels[WL_NUMCHANNELS]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; +#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { + uint8 eltId; + uint8 len[2]; + uint8 country[3]; + uint8 num_entries; + wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { + uint16 cat_id; + uint8 OUI[3]; + uint8 oui_type; + uint16 sub_cat_id; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; + + +#define P2P_DISE_SUBCATEGORY_MINVAL 1 +#define P2P_DISE_CATEGORY_COMPUTER 1 +#define P2P_DISE_SUBCATEGORY_COMPUTER_MAXVAL 8 +#define P2P_DISE_CATEGORY_INPUT_DEVICE 2 +#define P2P_DISE_SUBCATEGORY_INPUT_DEVICE_MAXVAL 9 +#define P2P_DISE_CATEGORY_PRINTER 3 +#define P2P_DISE_SUBCATEGORY_PRINTER_MAXVAL 5 +#define P2P_DISE_CATEGORY_CAMERA 4 +#define P2P_DISE_SUBCATEGORY_CAMERA_MAXVAL 4 +#define P2P_DISE_CATEGORY_STORAGE 5 +#define P2P_DISE_SUBCATEGORY_STORAGE_MAXVAL 1 +#define P2P_DISE_CATEGORY_NETWORK_INFRA 6 +#define P2P_DISE_SUBCATEGORY_NETWORK_INFRA_MAXVAL 4 +#define P2P_DISE_CATEGORY_DISPLAY 7 +#define P2P_DISE_SUBCATEGORY_DISPLAY_MAXVAL 4 +#define P2P_DISE_CATEGORY_MULTIMEDIA 8 +#define P2P_DISE_SUBCATEGORY_MULTIMEDIA_MAXVAL 6 +#define P2P_DISE_CATEGORY_GAMING 9 +#define P2P_DISE_SUBCATEGORY_GAMING_MAXVAL 5 +#define P2P_DISE_CATEGORY_TELEPHONE 10 +#define P2P_DISE_SUBCATEGORY_TELEPHONE_MAXVAL 5 +#define P2P_DISE_CATEGORY_AUDIO 11 +#define P2P_DISE_SUBCATEGORY_AUDIO_MAXVAL 6 + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { + uint8 eltId; + uint8 len[2]; + uint8 mac[6]; + uint16 wps_cfg_meths; + uint8 pri_devtype[8]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; + +#define P2P_DEV_TYPE_LEN 8 + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { + uint8 len; + uint8 devaddr[ETHER_ADDR_LEN]; + uint8 ifaddr[ETHER_ADDR_LEN]; + uint8 devcap; + uint8 cfg_meths[2]; + uint8 pridt[P2P_DEV_TYPE_LEN]; + uint8 secdts; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { + uint8 eltId; + uint8 len[2]; + struct ether_addr addr; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { + uint8 eltId; + uint8 len[2]; + uint8 mg_bitmap; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; + +#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { + uint8 eltId; + uint8 len[2]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { + uint8 eltId; + uint8 len[2]; + uint8 country[3]; + uint8 op_class; + uint8 channel; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { + uint8 eltId; + uint8 len[2]; + uint8 flags; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 dialog_token; + uint8 elts[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; +#define P2P_AF_CATEGORY 0x7f + +#define P2P_AF_FIXED_LEN 7 + + +#define P2P_AF_NOTICE_OF_ABSENCE 0 +#define P2P_AF_PRESENCE_REQ 1 +#define P2P_AF_PRESENCE_RSP 2 +#define P2P_AF_GO_DISC_REQ 3 + + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { + uint8 category; + uint8 action; + uint8 oui[3]; + uint8 oui_type; + uint8 subtype; + uint8 dialog_token; + uint8 elts[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; +#define P2P_PUB_AF_FIXED_LEN 8 +#define P2P_PUB_AF_CATEGORY 0x04 +#define P2P_PUB_AF_ACTION 0x09 + + +#define P2P_PAF_GON_REQ 0 +#define P2P_PAF_GON_RSP 1 +#define P2P_PAF_GON_CONF 2 +#define P2P_PAF_INVITE_REQ 3 +#define P2P_PAF_INVITE_RSP 4 +#define P2P_PAF_DEVDIS_REQ 5 +#define P2P_PAF_DEVDIS_RSP 6 +#define P2P_PAF_PROVDIS_REQ 7 +#define P2P_PAF_PROVDIS_RSP 8 +#define P2P_PAF_SUBTYPE_INVALID 255 + + +#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ +#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP +#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF + + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { + uint8 cnt_type; + uint32 duration; + uint32 interval; + uint32 start; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { + uint8 eltId; + uint8 len[2]; + uint8 index; + uint8 ops_ctw_parms; + wifi_p2p_noa_desc_t desc[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; + +#define P2P_NOA_SE_FIXED_LEN 5 + +#define P2P_NOA_SE_MAX_DESC 2 + + +#define P2P_NOA_DESC_CNT_RESERVED 0 +#define P2P_NOA_DESC_CNT_REPEAT 255 +#define P2P_NOA_DESC_TYPE_PREFERRED 1 +#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 + + +#define P2P_NOA_CTW_MASK 0x7f +#define P2P_NOA_OPS_MASK 0x80 +#define P2P_NOA_OPS_SHIFT 7 + +#define P2P_CTW_MIN 10 + + +#define P2PSD_ACTION_CATEGORY 0x04 + +#define P2PSD_ACTION_ID_GAS_IREQ 0x0a + +#define P2PSD_ACTION_ID_GAS_IRESP 0x0b + +#define P2PSD_ACTION_ID_GAS_CREQ 0x0c + +#define P2PSD_ACTION_ID_GAS_CRESP 0x0d + +#define P2PSD_AD_EID 0x6c + +#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 + +#define P2PSD_ADP_PROTO_ID 0x00 + +#define P2PSD_GAS_OUI P2P_OUI + +#define P2PSD_GAS_OUI_SUBTYPE P2P_VER + +#define P2PSD_GAS_NQP_INFOID 0xDDDD + +#define P2PSD_GAS_COMEBACKDEALY 0x00 + + + +typedef enum p2psd_svc_protype { + SVC_RPOTYPE_ALL = 0, + SVC_RPOTYPE_BONJOUR = 1, + SVC_RPOTYPE_UPNP = 2, + SVC_RPOTYPE_WSD = 3, + SVC_RPOTYPE_VENDOR = 255 +} p2psd_svc_protype_t; + + +typedef enum { + P2PSD_RESP_STATUS_SUCCESS = 0, + P2PSD_RESP_STATUS_PROTYPE_NA = 1, + P2PSD_RESP_STATUS_DATA_NA = 2, + P2PSD_RESP_STATUS_BAD_REQUEST = 3 +} p2psd_resp_status_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { + uint8 llm_pamebi; + uint8 adp_id; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { + uint8 id; + uint8 len; + wifi_p2psd_adp_tpl_t adp_tpl; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { + uint8 oui_subtype; + uint16 svc_updi; + uint8 svc_tlvs[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { + uint16 len; + uint8 svc_prot; + uint8 svc_tscid; + uint8 query_data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { + uint16 info_id; + uint16 len; + uint8 oui[3]; + uint8 qreq_vsc[1]; + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { + wifi_p2psd_adp_ie_t adp_ie; + uint16 qreq_len; + uint8 qreq_frm[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { + uint16 len; + uint8 svc_prot; + uint8 svc_tscid; + uint8 status; + uint8 query_data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { + uint16 info_id; + uint16 len; + uint8 oui[3]; + uint8 qresp_vsc[1]; + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { + uint16 status; + uint16 cb_delay; + wifi_p2psd_adp_ie_t adp_ie; + uint16 qresp_len; + uint8 qresp_frm[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { + uint16 status; + uint8 fragment_id; + uint16 cb_delay; + wifi_p2psd_adp_ie_t adp_ie; + uint16 qresp_len; + uint8 qresp_frm[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; + + +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { + uint8 category; + uint8 action; + uint8 dialog_token; + uint8 query_data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; + + +#include <packed_section_end.h> + +#endif
diff --git a/src/common/include/proto/sdspi.h b/src/common/include/proto/sdspi.h new file mode 100644 index 0000000..647a217 --- /dev/null +++ b/src/common/include/proto/sdspi.h
@@ -0,0 +1,57 @@ +/* + * SD-SPI Protocol Standard + * + * $ Copyright Open Broadcom Corporation $ + * + * $Id: sdspi.h 382882 2013-02-04 23:24:31Z $ + */ +#ifndef _SD_SPI_H +#define _SD_SPI_H + +#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ +#define SPI_START_S 31 +#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ +#define SPI_DIR_S 30 +#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ +#define SPI_CMD_INDEX_S 24 +#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ +#define SPI_RW_S 23 +#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ +#define SPI_FUNC_S 20 +#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ +#define SPI_RAW_S 19 +#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ +#define SPI_STUFF_S 18 +#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ +#define SPI_BLKMODE_S 19 +#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ +#define SPI_OPCODE_S 18 +#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ +#define SPI_ADDR_S 1 +#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ +#define SPI_STUFF0_S 0 + +#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ +#define SPI_RSP_START_S 7 +#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ +#define SPI_RSP_PARAM_ERR_S 6 +#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ +#define SPI_RSP_RFU5_S 5 +#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ +#define SPI_RSP_FUNC_ERR_S 4 +#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ +#define SPI_RSP_CRC_ERR_S 3 +#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ +#define SPI_RSP_ILL_CMD_S 2 +#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ +#define SPI_RSP_RFU1_S 1 +#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ +#define SPI_RSP_IDLE_S 0 + +/* SD-SPI Protocol Definitions */ +#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ +#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ +#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ +#define SDSPI_START_BIT_MASK 0x80 + +#endif /* _SD_SPI_H */
diff --git a/src/common/include/proto/vlan.h b/src/common/include/proto/vlan.h new file mode 100644 index 0000000..bf48965 --- /dev/null +++ b/src/common/include/proto/vlan.h
@@ -0,0 +1,75 @@ +/* + * 802.1Q VLAN protocol definitions + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: vlan.h 382883 2013-02-04 23:26:09Z $ + */ + +#ifndef _vlan_h_ +#define _vlan_h_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif + + +#include <packed_section_start.h> + +#ifndef VLAN_VID_MASK +#define VLAN_VID_MASK 0xfff +#endif + +#define VLAN_CFI_SHIFT 12 +#define VLAN_PRI_SHIFT 13 + +#define VLAN_PRI_MASK 7 + +#define VLAN_TPID_OFFSET 12 +#define VLAN_TCI_OFFSET 14 + +#define VLAN_TAG_LEN 4 +#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) + +#define VLAN_TPID 0x8100 + +struct vlan_header { + uint16 vlan_type; + uint16 vlan_tag; +}; + +struct ethervlan_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 vlan_type; + uint16 vlan_tag; + uint16 ether_type; +}; + +struct dot3_mac_llc_snapvlan_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 length; + uint8 dsap; + uint8 ssap; + uint8 ctl; + uint8 oui[3]; + uint16 vlan_type; + uint16 vlan_tag; + uint16 ether_type; +}; + +#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) + + + +#include <packed_section_end.h> + +#define ETHERVLAN_MOVE_HDR(d, s) \ +do { \ + struct ethervlan_header t; \ + t = *(struct ethervlan_header *)(s); \ + *(struct ethervlan_header *)(d) = t; \ +} while (0) + +#endif
diff --git a/src/common/include/proto/wpa.h b/src/common/include/proto/wpa.h new file mode 100644 index 0000000..519df36 --- /dev/null +++ b/src/common/include/proto/wpa.h
@@ -0,0 +1,194 @@ +/* + * Fundamental types and constants relating to WPA + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: wpa.h 384536 2013-02-12 04:13:09Z $ + */ + +#ifndef _proto_wpa_h_ +#define _proto_wpa_h_ + +#include <typedefs.h> +#include <proto/ethernet.h> + + + +#include <packed_section_start.h> + + + + +#define DOT11_RC_INVALID_WPA_IE 13 +#define DOT11_RC_MIC_FAILURE 14 +#define DOT11_RC_4WH_TIMEOUT 15 +#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 +#define DOT11_RC_WPA_IE_MISMATCH 17 +#define DOT11_RC_INVALID_MC_CIPHER 18 +#define DOT11_RC_INVALID_UC_CIPHER 19 +#define DOT11_RC_INVALID_AKMP 20 +#define DOT11_RC_BAD_WPA_VERSION 21 +#define DOT11_RC_INVALID_WPA_CAP 22 +#define DOT11_RC_8021X_AUTH_FAIL 23 + +#define WPA2_PMKID_LEN 16 + + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint8 tag; + uint8 length; + uint8 oui[3]; + uint8 oui_type; + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT version; +} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; +#define WPA_IE_OUITYPE_LEN 4 +#define WPA_IE_FIXED_LEN 8 +#define WPA_IE_TAG_FIXED_LEN 6 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 tag; + uint8 length; + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT version; +} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; +#define WPA_RSN_IE_FIXED_LEN 4 +#define WPA_RSN_IE_TAG_FIXED_LEN 2 +typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; + + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint8 oui[3]; + uint8 type; +} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; +#define WPA_SUITE_LEN 4 + + +typedef BWL_PRE_PACKED_STRUCT struct +{ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT count; + wpa_suite_t list[1]; +} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; +#define WPA_IE_SUITE_COUNT_LEN 2 +typedef BWL_PRE_PACKED_STRUCT struct +{ + BWL_PRE_PACKED_STRUCT struct { + uint8 low; + uint8 high; + } BWL_POST_PACKED_STRUCT count; + wpa_pmkid_t list[1]; +} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; + + +#define WPA_CIPHER_NONE 0 +#define WPA_CIPHER_WEP_40 1 +#define WPA_CIPHER_TKIP 2 +#define WPA_CIPHER_AES_OCB 3 +#define WPA_CIPHER_AES_CCM 4 +#define WPA_CIPHER_WEP_104 5 +#define WPA_CIPHER_BIP 6 +#define WPA_CIPHER_TPK 7 +#ifdef BCMCCX +#define WPA_CIPHER_CKIP 8 +#define WPA_CIPHER_CKIP_MMH 9 +#define WPA_CIPHER_WEP_MMH 10 + +#define IS_CCX_CIPHER(cipher) ((cipher) == WPA_CIPHER_CKIP || \ + (cipher) == WPA_CIPHER_CKIP_MMH || \ + (cipher) == WPA_CIPHER_WEP_MMH) +#endif + +#ifdef BCMWAPI_WAI +#define WAPI_CIPHER_NONE WPA_CIPHER_NONE +#define WAPI_CIPHER_SMS4 11 + +#define WAPI_CSE_WPI_SMS4 1 +#endif + +#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ + (cipher) == WPA_CIPHER_WEP_40 || \ + (cipher) == WPA_CIPHER_WEP_104 || \ + (cipher) == WPA_CIPHER_TKIP || \ + (cipher) == WPA_CIPHER_AES_OCB || \ + (cipher) == WPA_CIPHER_AES_CCM || \ + (cipher) == WPA_CIPHER_TPK) + +#ifdef BCMWAPI_WAI +#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ + (cipher) == WAPI_CSE_WPI_SMS4) + + +#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ + WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) + +#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ + WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) +#endif + + +#define WPA_TKIP_CM_DETECT 60 +#define WPA_TKIP_CM_BLOCK 60 + + +#define RSN_CAP_LEN 2 + + +#define RSN_CAP_PREAUTH 0x0001 +#define RSN_CAP_NOPAIRWISE 0x0002 +#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C +#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 +#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 +#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 +#define RSN_CAP_1_REPLAY_CNTR 0 +#define RSN_CAP_2_REPLAY_CNTRS 1 +#define RSN_CAP_4_REPLAY_CNTRS 2 +#define RSN_CAP_16_REPLAY_CNTRS 3 +#define RSN_CAP_MFPR 0x0040 +#define RSN_CAP_MFPC 0x0080 +#define RSN_CAP_SPPC 0x0400 +#define RSN_CAP_SPPR 0x0800 + + +#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS +#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS +#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT +#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK + + +#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) + + +#define WPA_CAP_LEN RSN_CAP_LEN +#define WPA_PMKID_CNT_LEN 2 + +#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH + +#define WPA2_PMKID_COUNT_LEN 2 + +#ifdef BCMWAPI_WAI +#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH + + +#define WAPI_WAI_REQUEST 0x00F1 +#define WAPI_UNICAST_REKEY 0x00F2 +#define WAPI_STA_AGING 0x00F3 +#define WAPI_MUTIL_REKEY 0x00F4 +#define WAPI_STA_STATS 0x00F5 + +#define WAPI_USK_REKEY_COUNT 0x4000000 +#define WAPI_MSK_REKEY_COUNT 0x4000000 +#endif + + +#include <packed_section_end.h> + +#endif
diff --git a/src/common/include/proto/wps.h b/src/common/include/proto/wps.h new file mode 100644 index 0000000..43c4996 --- /dev/null +++ b/src/common/include/proto/wps.h
@@ -0,0 +1,361 @@ +/* + * WPS IE definitions + * + * $Copyright Open Broadcom Corporation$ + * + * $Id$ + */ + +#ifndef _WPS_ +#define _WPS_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Data Element Definitions */ +#define WPS_ID_AP_CHANNEL 0x1001 +#define WPS_ID_ASSOC_STATE 0x1002 +#define WPS_ID_AUTH_TYPE 0x1003 +#define WPS_ID_AUTH_TYPE_FLAGS 0x1004 +#define WPS_ID_AUTHENTICATOR 0x1005 +#define WPS_ID_CONFIG_METHODS 0x1008 +#define WPS_ID_CONFIG_ERROR 0x1009 +#define WPS_ID_CONF_URL4 0x100A +#define WPS_ID_CONF_URL6 0x100B +#define WPS_ID_CONN_TYPE 0x100C +#define WPS_ID_CONN_TYPE_FLAGS 0x100D +#define WPS_ID_CREDENTIAL 0x100E +#define WPS_ID_DEVICE_NAME 0x1011 +#define WPS_ID_DEVICE_PWD_ID 0x1012 +#define WPS_ID_E_HASH1 0x1014 +#define WPS_ID_E_HASH2 0x1015 +#define WPS_ID_E_SNONCE1 0x1016 +#define WPS_ID_E_SNONCE2 0x1017 +#define WPS_ID_ENCR_SETTINGS 0x1018 +#define WPS_ID_ENCR_TYPE 0x100F +#define WPS_ID_ENCR_TYPE_FLAGS 0x1010 +#define WPS_ID_ENROLLEE_NONCE 0x101A +#define WPS_ID_FEATURE_ID 0x101B +#define WPS_ID_IDENTITY 0x101C +#define WPS_ID_IDENTITY_PROOF 0x101D +#define WPS_ID_KEY_WRAP_AUTH 0x101E +#define WPS_ID_KEY_IDENTIFIER 0x101F +#define WPS_ID_MAC_ADDR 0x1020 +#define WPS_ID_MANUFACTURER 0x1021 +#define WPS_ID_MSG_TYPE 0x1022 +#define WPS_ID_MODEL_NAME 0x1023 +#define WPS_ID_MODEL_NUMBER 0x1024 +#define WPS_ID_NW_INDEX 0x1026 +#define WPS_ID_NW_KEY 0x1027 +#define WPS_ID_NW_KEY_INDEX 0x1028 +#define WPS_ID_NEW_DEVICE_NAME 0x1029 +#define WPS_ID_NEW_PWD 0x102A +#define WPS_ID_OOB_DEV_PWD 0x102C +#define WPS_ID_OS_VERSION 0x102D +#define WPS_ID_POWER_LEVEL 0x102F +#define WPS_ID_PSK_CURRENT 0x1030 +#define WPS_ID_PSK_MAX 0x1031 +#define WPS_ID_PUBLIC_KEY 0x1032 +#define WPS_ID_RADIO_ENABLED 0x1033 +#define WPS_ID_REBOOT 0x1034 +#define WPS_ID_REGISTRAR_CURRENT 0x1035 +#define WPS_ID_REGISTRAR_ESTBLSHD 0x1036 +#define WPS_ID_REGISTRAR_LIST 0x1037 +#define WPS_ID_REGISTRAR_MAX 0x1038 +#define WPS_ID_REGISTRAR_NONCE 0x1039 +#define WPS_ID_REQ_TYPE 0x103A +#define WPS_ID_RESP_TYPE 0x103B +#define WPS_ID_RF_BAND 0x103C +#define WPS_ID_R_HASH1 0x103D +#define WPS_ID_R_HASH2 0x103E +#define WPS_ID_R_SNONCE1 0x103F +#define WPS_ID_R_SNONCE2 0x1040 +#define WPS_ID_SEL_REGISTRAR 0x1041 +#define WPS_ID_SERIAL_NUM 0x1042 +#define WPS_ID_SC_STATE 0x1044 +#define WPS_ID_SSID 0x1045 +#define WPS_ID_TOT_NETWORKS 0x1046 +#define WPS_ID_UUID_E 0x1047 +#define WPS_ID_UUID_R 0x1048 +#define WPS_ID_VENDOR_EXT 0x1049 +#define WPS_ID_VERSION 0x104A +#define WPS_ID_X509_CERT_REQ 0x104B +#define WPS_ID_X509_CERT 0x104C +#define WPS_ID_EAP_IDENTITY 0x104D +#define WPS_ID_MSG_COUNTER 0x104E +#define WPS_ID_PUBKEY_HASH 0x104F +#define WPS_ID_REKEY_KEY 0x1050 +#define WPS_ID_KEY_LIFETIME 0x1051 +#define WPS_ID_PERM_CFG_METHODS 0x1052 +#define WPS_ID_SEL_REG_CFG_METHODS 0x1053 +#define WPS_ID_PRIM_DEV_TYPE 0x1054 +#define WPS_ID_SEC_DEV_TYPE_LIST 0x1055 +#define WPS_ID_PORTABLE_DEVICE 0x1056 +#define WPS_ID_AP_SETUP_LOCKED 0x1057 +#define WPS_ID_APP_LIST 0x1058 +#define WPS_ID_EAP_TYPE 0x1059 +#define WPS_ID_INIT_VECTOR 0x1060 +#define WPS_ID_KEY_PROVIDED_AUTO 0x1061 +#define WPS_ID_8021X_ENABLED 0x1062 +#define WPS_ID_WEP_TRANSMIT_KEY 0x1064 +#define WPS_ID_REQ_DEV_TYPE 0x106A + +/* WSC 2.0, WFA Vendor Extension Subelements */ +#define WFA_VENDOR_EXT_ID "\x00\x37\x2A" +#define WPS_WFA_SUBID_VERSION2 0x00 +#define WPS_WFA_SUBID_AUTHORIZED_MACS 0x01 +#define WPS_WFA_SUBID_NW_KEY_SHAREABLE 0x02 +#define WPS_WFA_SUBID_REQ_TO_ENROLL 0x03 +#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME 0x04 + + +/* WCN-NET Windows Rally Vertical Pairing Vendor Extensions */ +#define MS_VENDOR_EXT_ID "\x00\x01\x37" +#define WPS_MS_ID_VPI 0x1001 /* Vertical Pairing Identifier TLV */ +#define WPS_MS_ID_TRANSPORT_UUID 0x1002 /* Transport UUID TLV */ + +/* Vertical Pairing Identifier TLV Definitions */ +#define WPS_MS_VPI_TRANSPORT_NONE 0x00 /* None */ +#define WPS_MS_VPI_TRANSPORT_DPWS 0x01 /* Devices Profile for Web Services */ +#define WPS_MS_VPI_TRANSPORT_UPNP 0x02 /* uPnP */ +#define WPS_MS_VPI_TRANSPORT_SDNWS 0x03 /* Secure Devices Profile for Web Services */ +#define WPS_MS_VPI_NO_PROFILE_REQ 0x00 /* Wi-Fi profile not requested. + * Not supported in Windows 7 + */ +#define WPS_MS_VPI_PROFILE_REQ 0x01 /* Wi-Fi profile requested. */ + +/* sizes of the fixed size elements */ +#define WPS_ID_AP_CHANNEL_S 2 +#define WPS_ID_ASSOC_STATE_S 2 +#define WPS_ID_AUTH_TYPE_S 2 +#define WPS_ID_AUTH_TYPE_FLAGS_S 2 +#define WPS_ID_AUTHENTICATOR_S 8 +#define WPS_ID_CONFIG_METHODS_S 2 +#define WPS_ID_CONFIG_ERROR_S 2 +#define WPS_ID_CONN_TYPE_S 1 +#define WPS_ID_CONN_TYPE_FLAGS_S 1 +#define WPS_ID_DEVICE_PWD_ID_S 2 +#define WPS_ID_ENCR_TYPE_S 2 +#define WPS_ID_ENCR_TYPE_FLAGS_S 2 +#define WPS_ID_FEATURE_ID_S 4 +#define WPS_ID_MAC_ADDR_S 6 +#define WPS_ID_MSG_TYPE_S 1 +#define WPS_ID_SC_STATE_S 1 +#define WPS_ID_RF_BAND_S 1 +#define WPS_ID_OS_VERSION_S 4 +#define WPS_ID_VERSION_S 1 +#define WPS_ID_SEL_REGISTRAR_S 1 +#define WPS_ID_SEL_REG_CFG_METHODS_S 2 +#define WPS_ID_REQ_TYPE_S 1 +#define WPS_ID_RESP_TYPE_S 1 +#define WPS_ID_AP_SETUP_LOCKED_S 1 + +/* WSC 2.0, WFA Vendor Extension Subelements */ +#define WPS_WFA_SUBID_VERSION2_S 1 +#define WPS_WFA_SUBID_NW_KEY_SHAREABLE_S 1 +#define WPS_WFA_SUBID_REQ_TO_ENROLL_S 1 +#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME_S 1 + +/* Association states */ +#define WPS_ASSOC_NOT_ASSOCIATED 0 +#define WPS_ASSOC_CONN_SUCCESS 1 +#define WPS_ASSOC_CONFIG_FAIL 2 +#define WPS_ASSOC_ASSOC_FAIL 3 +#define WPS_ASSOC_IP_FAIL 4 + +/* Authentication types */ +#define WPS_AUTHTYPE_OPEN 0x0001 +#define WPS_AUTHTYPE_WPAPSK 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_SHARED 0x0004 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_WPA 0x0008 /* Deprecated in WSC 2.0 */ +#define WPS_AUTHTYPE_WPA2 0x0010 +#define WPS_AUTHTYPE_WPA2PSK 0x0020 + +/* Config methods */ +#define WPS_CONFMET_USBA 0x0001 /* Deprecated in WSC 2.0 */ +#define WPS_CONFMET_ETHERNET 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_CONFMET_LABEL 0x0004 +#define WPS_CONFMET_DISPLAY 0x0008 +#define WPS_CONFMET_EXT_NFC_TOK 0x0010 +#define WPS_CONFMET_INT_NFC_TOK 0x0020 +#define WPS_CONFMET_NFC_INTF 0x0040 +#define WPS_CONFMET_PBC 0x0080 +#define WPS_CONFMET_KEYPAD 0x0100 +/* WSC 2.0 */ +#define WPS_CONFMET_VIRT_PBC 0x0280 +#define WPS_CONFMET_PHY_PBC 0x0480 +#define WPS_CONFMET_VIRT_DISPLAY 0x2008 +#define WPS_CONFMET_PHY_DISPLAY 0x4008 + +/* WPS error messages */ +#define WPS_ERROR_NO_ERROR 0 +#define WPS_ERROR_OOB_INT_READ_ERR 1 +#define WPS_ERROR_DECRYPT_CRC_FAIL 2 +#define WPS_ERROR_CHAN24_NOT_SUPP 3 +#define WPS_ERROR_CHAN50_NOT_SUPP 4 +#define WPS_ERROR_SIGNAL_WEAK 5 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NW_AUTH_FAIL 6 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NW_ASSOC_FAIL 7 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_NO_DHCP_RESP 8 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_FAILED_DHCP_CONF 9 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_IP_ADDR_CONFLICT 10 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_FAIL_CONN_REGISTRAR 11 +#define WPS_ERROR_MULTI_PBC_DETECTED 12 +#define WPS_ERROR_ROGUE_SUSPECTED 13 +#define WPS_ERROR_DEVICE_BUSY 14 +#define WPS_ERROR_SETUP_LOCKED 15 +#define WPS_ERROR_MSG_TIMEOUT 16 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_REG_SESSION_TIMEOUT 17 /* Deprecated in WSC 2.0 */ +#define WPS_ERROR_DEV_PWD_AUTH_FAIL 18 + +/* Connection types */ +#define WPS_CONNTYPE_ESS 0x01 +#define WPS_CONNTYPE_IBSS 0x02 + +/* Device password ID */ +#define WPS_DEVICEPWDID_DEFAULT 0x0000 +#define WPS_DEVICEPWDID_USER_SPEC 0x0001 +#define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002 +#define WPS_DEVICEPWDID_REKEY 0x0003 +#define WPS_DEVICEPWDID_PUSH_BTN 0x0004 +#define WPS_DEVICEPWDID_REG_SPEC 0x0005 + +/* Encryption type */ +#define WPS_ENCRTYPE_NONE 0x0001 +#define WPS_ENCRTYPE_WEP 0x0002 /* Deprecated in WSC 2.0 */ +#define WPS_ENCRTYPE_TKIP 0x0004 /* Deprecated in version 2.0. TKIP can only + * be advertised on the AP when Mixed Mode + * is enabled (Encryption Type is 0x000c). + */ +#define WPS_ENCRTYPE_AES 0x0008 + + +/* WPS Message Types */ +#define WPS_ID_BEACON 0x01 +#define WPS_ID_PROBE_REQ 0x02 +#define WPS_ID_PROBE_RESP 0x03 +#define WPS_ID_MESSAGE_M1 0x04 +#define WPS_ID_MESSAGE_M2 0x05 +#define WPS_ID_MESSAGE_M2D 0x06 +#define WPS_ID_MESSAGE_M3 0x07 +#define WPS_ID_MESSAGE_M4 0x08 +#define WPS_ID_MESSAGE_M5 0x09 +#define WPS_ID_MESSAGE_M6 0x0A +#define WPS_ID_MESSAGE_M7 0x0B +#define WPS_ID_MESSAGE_M8 0x0C +#define WPS_ID_MESSAGE_ACK 0x0D +#define WPS_ID_MESSAGE_NACK 0x0E +#define WPS_ID_MESSAGE_DONE 0x0F + +/* WSP private ID for local use */ +#define WPS_PRIVATE_ID_IDENTITY (WPS_ID_MESSAGE_DONE + 1) +#define WPS_PRIVATE_ID_WPS_START (WPS_ID_MESSAGE_DONE + 2) +#define WPS_PRIVATE_ID_FAILURE (WPS_ID_MESSAGE_DONE + 3) +#define WPS_PRIVATE_ID_FRAG (WPS_ID_MESSAGE_DONE + 4) +#define WPS_PRIVATE_ID_FRAG_ACK (WPS_ID_MESSAGE_DONE + 5) +#define WPS_PRIVATE_ID_EAPOL_START (WPS_ID_MESSAGE_DONE + 6) + + +/* Device Type categories for primary and secondary device types */ +#define WPS_DEVICE_TYPE_CAT_COMPUTER 1 +#define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2 +#define WPS_DEVICE_TYPE_CAT_PRINTER 3 +#define WPS_DEVICE_TYPE_CAT_CAMERA 4 +#define WPS_DEVICE_TYPE_CAT_STORAGE 5 +#define WPS_DEVICE_TYPE_CAT_NW_INFRA 6 +#define WPS_DEVICE_TYPE_CAT_DISPLAYS 7 +#define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8 +#define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9 +#define WPS_DEVICE_TYPE_CAT_TELEPHONE 10 +#define WPS_DEVICE_TYPE_CAT_AUDIO_DEVICES 11 /* WSC 2.0 */ + +/* Device Type sub categories for primary and secondary device types */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3 +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_UM_PC 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NOTEBOOK 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_DESKTOP 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MID 7 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NETBOOK 8 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_Keyboard 1 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_MOUSE 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_JOYSTICK 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_TRACKBALL 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_GAM_CTRL 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_REMOTE 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_TOUCHSCREEN 7 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_BIO_READER 8 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_INP_BAR_READER 9 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1 +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_FAX 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_COPIER 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_ALLINONE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1 +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_VIDEO_CAM 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_WEB_CAM 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_CAM_SECU_CAM 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3 +#define WPS_DEVICE_TYPE_SUB_CAT_NW_GATEWAY 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_NW_BRIDGE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3 +#define WPS_DEVICE_TYPE_SUB_CAT_DISP_MONITOR 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3 +#define WPS_DEVICE_TYPE_SUB_CAT_MM_STB 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_MS_ME 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVP 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3 +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_GC 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PGD 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1 +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PSM 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PDM 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SSM 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SDM 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_TUNER 1 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_SPEAKERS 2 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_PMP 3 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HEADSET 4 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HPHONE 5 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_MPHONE 6 /* WSC 2.0 */ +#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HTS 7 /* WSC 2.0 */ + + +/* Device request/response type */ +#define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00 +#define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01 +#define WPS_MSGTYPE_REGISTRAR 0x02 +#define WPS_MSGTYPE_AP_WLAN_MGR 0x03 + +/* RF Band */ +#define WPS_RFBAND_24GHZ 0x01 +#define WPS_RFBAND_50GHZ 0x02 + +/* Simple Config state */ +#define WPS_SCSTATE_UNCONFIGURED 0x01 +#define WPS_SCSTATE_CONFIGURED 0x02 +#define WPS_SCSTATE_OFF 11 + +/* WPS Vendor extension key */ +#define WPS_OUI_HEADER_LEN 2 +#define WPS_OUI_HEADER_SIZE 4 +#define WPS_OUI_FIXED_HEADER_OFF 16 +#define WPS_WFA_SUBID_V2_OFF 3 +#define WPS_WFA_V2_OFF 5 + +#ifdef __cplusplus +} +#endif + +#endif /* _WPS_ */
diff --git a/src/dhd/exe/GNUmakefile b/src/dhd/exe/GNUmakefile new file mode 100644 index 0000000..409c225 --- /dev/null +++ b/src/dhd/exe/GNUmakefile
@@ -0,0 +1,128 @@ +# +# GNUmakefile for dhd/exe +# +# Copyright (c) 2000, Broadcom Corp. +# $Id: GNUmakefile,v 1.27 2010-09-13 14:20:34 $ + +WLAN_ComponentsInUse := bcmwifi +include ../../makefiles/WLAN_Common.mk +SRCBASE := $(WLAN_SrcBaseR) + +UNAME = $(shell uname) + +#----------------------------------------------------------------- +# Windows build +# 1) windows, don't include Makerules due to all: conflict + +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) + +include ../../GNUmakefile.inc + +else # UNAME + +# 2) not windows, need to include first to pick up TARGETENV dependent vars +include $(SRCBASE)/Makerules + +CFLAGS += $(EXTRA_PLATFORM_CFLAGS) + +# use nl80211 for driver access (ioctl replacement) +ifdef NL80211 +CFLAGS += -DNL80211 +endif + +#ifdef BCMWPA2 +CFLAGS += -DBCMWPA2 +#endif +# Always include pktgen commands in the application +CFLAGS += -DSDTEST +#ifndef OEM_ANDROID +CFLAGS += -DBCMSPI +#endif + +#ifdef WLCNT +CFLAGS += -DWLCNT +#endif + + +CFLAGS += -DWLBTAMP +CFLAGS += -DWLPFN -DLINUX -g -I$(SRCBASE)/wl/exe + +vpath %.c $(SRCBASE)/shared $(SRCBASE)/wl/exe $(WLAN_StdSrcDirsR) $(WLAN_ComponentSrcDirsR) + +#----------------------------------------------------------------- +# Linux build +# +# This should be one of values recognized in src/Makerules + +# Change to the new dhd driver trunk build structure as discussed +# by the build team +ifeq ($(BUILD_TAG),TRUNK) + +# $(TARGETARCH) is set based on TARGETENV in src/Makerules.* files +DHD_OBJS := $(TARGETARCH)/dhdu.o $(TARGETARCH)/dhdu_linux.o $(TARGETARCH)/bcmutils.o $(TARGETARCH)/bcmwifi_channels.o $(TARGETARCH)/wlu_client_shared.o $(TARGETARCH)/wlu_pipe_linux.o $(TARGETARCH)/wlu_pipe.o $(TARGETARCH)/miniopt.o $(TARGETARCH)/bcm_app_utils.o $(TARGETARCH)/ucode_download.o $(TARGETARCH)/wlu_common.o +DHD_EXE := $(TARGETARCH)/dhd + +include netlink.inc + +all: $(DHD_EXE) + +clean: + rm -fr $(DHD_EXE) $(DHD_OBJS) $(TARGETARCH) + +$(DHD_EXE): $(DHD_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +$(TARGETARCH)/%.o: %.c + @mkdir -p $(TARGETARCH) + $(CC) -c $(CFLAGS) -DRWL_SOCKET -DRWL_WIFI -DRWL_DONGLE -o $@ $^ + +else # BUILD_TAG + +# Preserve the old build structure for other components that still haven't not +# changed to the new build structure, once everyone moved to the new structure +# , we can remove the whole else BUILD_TAG code + +ifneq ($(findstring $(TARGETENV), "linux linuxmips linuxmips_be linuxarm linuxarm_le android android_ndk_r6b"),) +# $(TARGETARCH) is set based on TARGETENV in src/Makerules.* files +DHD_OBJS := dhdu.o dhdu_linux.o bcmutils.o bcmwifi_channels.o wlu_client_shared.o wlu_pipe_linux.o wlu_pipe.o miniopt.o bcm_app_utils.o ucode_download.o wlu_common.o +DHD_EXE := dhd +DHD_OBJS := $(DHD_OBJS:%.o=%.o) + +include netlink.inc + +ifeq ($(findstring $(TARGETARCH), "x86 x86_mmx"),) + DHD_EXE := $(DHD_EXE)$(TARGETARCH) + DHD_OBJS := $(DHD_OBJS:%.o=$(TARGETARCH)/%.o) +endif + +all: $(DHD_EXE) + +clean: + rm -fr $(DHD_EXE) $(DHD_OBJS) $(TARGETARCH) + +$(DHD_EXE): $(DHD_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +# net_priv target is for building the dhd with NET_ADMIN privilege (i.e. to avoid running as root) +# note: The 'setcap' command is availble from the libcap2-bin package +# note: linux kernel < 2.6.33 doesn't support Security File Capabilities by default +net_priv: $(DHD_EXE) + sudo setcap CAP_NET_ADMIN=eip $^ + +%.o: %.c + $(CC) -c $(CFLAGS) -DRWL_SOCKET -DRWL_WIFI -DRWL_DONGLE -o $@ $^ + + +ifeq ($(findstring $(TARGETARCH), "x86 x86_mmx"),) +$(TARGETARCH)/%.o: %.c + @mkdir -p $(TARGETARCH) + $(CC) -c $(CFLAGS) -DRWL_SOCKET -DRWL_WIFI -DRWL_DONGLE -o $@ $^ +endif + +endif # TARGETENV linux + +endif # BUILD_TAG + +.PHONY: all clean net_priv + +endif # UNAME
diff --git a/src/dhd/exe/dhdu.c b/src/dhd/exe/dhdu.c new file mode 100644 index 0000000..9343b38 --- /dev/null +++ b/src/dhd/exe/dhdu.c
@@ -0,0 +1,3480 @@ +/* + * Common code for DHD command-line utility + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: dhdu.c 479444 2014-05-21 04:19:36Z $ + */ + +/* For backwards compatibility, the absence of the define 'BWL_NO_FILESYSTEM_SUPPORT' + * implies that a filesystem is supported. + */ +#if !defined(BWL_NO_FILESYSTEM_SUPPORT) +#define BWL_FILESYSTEM_SUPPORT +#endif + +#ifndef PROP_TXSTATUS +#define PROP_TXSTATUS +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include <typedefs.h> +#include <epivers.h> +#include <proto/ethernet.h> +#include <dhdioctl.h> +#include <sdiovar.h> +#include <bcmutils.h> +#include <bcmendian.h> +#include "dhdu.h" +#include "miniopt.h" +#include <usbrdl.h> +#include <proto/bcmip.h> +#include <hndrte_debug.h> +#include <hndrte_armtrap.h> +#include <hndrte_cons.h> +#define IPV4_ADDR_LEN 4 +#ifdef WLBTAMP +#include <proto/bt_amp_hci.h> +#endif + +#include <errno.h> + +#include <trxhdr.h> +#include "ucode_download.h" + +#define stricmp strcasecmp +#define strnicmp strncasecmp + + +static cmd_func_t dhd_var_void; +static cmd_func_t dhd_varint, dhd_varstr; +static cmd_func_t dhd_var_getandprintstr, dhd_var_getint, dhd_var_get; +static cmd_func_t dhd_var_setint; + +static cmd_func_t dhd_version, dhd_list, dhd_msglevel; + +#ifdef SDTEST +static cmd_func_t dhd_pktgen; +#endif +static cmd_func_t dhd_sprom; +static cmd_func_t dhd_sdreg; +static cmd_func_t dhd_reg2args; +static cmd_func_t dhd_pcie_dmaxfer; +static cmd_func_t dhd_sd_msglevel, dhd_sd_blocksize, dhd_sd_mode, dhd_sd_reg; +static cmd_func_t dhd_dma_mode; +static cmd_func_t dhd_membytes, dhd_download, dhd_dldn, + dhd_upload, dhd_coredump, dhd_consoledump, dhd_vars, dhd_idleclock, dhd_idletime; +static cmd_func_t dhd_logstamp; +#ifdef BCMSPI +static cmd_func_t dhd_spierrstats; +#endif /* BCMSPI */ + +static cmd_func_t dhd_hostreorder_flows; + +#ifdef QMONITOR +static int dhd_qtime_thres(void *dhd, cmd_t *cmd, char **argv); +static int dhd_qtime_percent(void *dhd, cmd_t *cmd, char **argv); +#endif + +#ifdef PROP_TXSTATUS +static cmd_func_t dhd_proptxstatusenable; +static cmd_func_t dhd_proptxstatusmode; +static cmd_func_t dhd_proptxopt; +#endif +static int dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr); +static int dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len); + +static uint dhd_iovar_mkbuf(char *name, char *data, uint datalen, + char *buf, uint buflen, int *perr); +static int dhd_iovar_getint(void *dhd, char *name, int *var); +static int dhd_iovar_setint(void *dhd, char *name, int var); + +#if defined(BWL_FILESYSTEM_SUPPORT) +static int file_size(char *fname); +static int read_vars(char *fname, char *buf, int buf_maxlen); +#endif + +#ifdef WLBTAMP +static cmd_func_t wl_HCI_cmd; +static cmd_func_t wl_HCI_ACL_data; +#endif + +/* dword align allocation */ +static union { + char bufdata[DHD_IOCTL_MAXLEN]; + uint32 alignme; +} bufstruct_dhd; +static char *buf = (char*) &bufstruct_dhd.bufdata; + +/* integer output format, default to signed integer */ +static uint8 int_fmt; + +#define DEBUG_INFO_PTRS_END 0xffffffff +const uint32 debug_info_ptrs[] = {0xf8, 0x878, DEBUG_INFO_PTRS_END}; + +typedef struct { + uint value; + char *string; +} dbg_msg_t; + +static int dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg); + +/* Actual command table */ +cmd_t dhd_cmds[] = { + { "cmds", dhd_list, -1, -1, + "generate a short list of available commands"}, + { "version", dhd_version, DHD_GET_VAR, -1, + "get version information" }, + { "msglevel", dhd_msglevel, DHD_GET_VAR, DHD_SET_VAR, + "get/set message bits" }, + { "bcmerrorstr", dhd_var_getandprintstr, DHD_GET_VAR, -1, + "errorstring"}, + { "wdtick", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "watchdog tick time (ms units)"}, + { "msi_sim", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "simulate MSI interrupts for the PCIE full dongle operation"}, + { "pcie_lpbk", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "send a loopback message on the bus"}, + { "pcie_dmaxfer", dhd_pcie_dmaxfer, -1, DHD_SET_VAR, + "send a dma transfer message on the bus"}, + { "pcie_tx_lpbk", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "enable/disable loopback of tx packets on the bus"}, + { "pcie_suspend", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "suspend/resume pcie bus"}, + { "pciereg", dhd_reg2args, DHD_GET_VAR, DHD_SET_VAR, + "get/set a pciereg from the device"}, + { "pciecorereg", dhd_reg2args, DHD_GET_VAR, DHD_SET_VAR, + "get/set a pciecorereg from the device"}, + { "pciecfgreg", dhd_reg2args, DHD_GET_VAR, DHD_SET_VAR, + "get/set a pciecfgreg from the device"}, + { "sleep_allowed", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "boolean to indicate whether the device is allowed to go to deep sleep"}, + { "cc_nvmshadow", dhd_varstr, DHD_GET_VAR, -1, + "dump OTP/SPROM shadow in chip common enum space"}, + { "intr", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "use interrupts on the bus"}, + { "pollrate", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "number of ticks between bus polls (0 means no polling)"}, + { "idletime", dhd_idletime, DHD_GET_VAR, DHD_SET_VAR, + "number of ticks for activity timeout (-1: immediate, 0: never)"}, + { "idleclock", dhd_idleclock, DHD_GET_VAR, DHD_SET_VAR, + "idleclock active | stopped | <N>\n" + "\tactive (0) - do not request any change to the SD clock\n" + "\tstopped (-1) - request SD clock be stopped on activity timeout\n" + "\t<N> (other) - an sd_divisor value to request on activity timeout\n"}, + { "sd1idle", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "change mode to SD1 when turning off clock at idle"}, + { "forceeven", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "force SD tx/rx buffers to be even"}, + { "readahead", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "enable readahead feature (look for next frame len in headers)"}, + { "sdrxchain", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "enable packet chains to SDIO stack for glom receive"}, + { "alignctl", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "align control frames"}, + { "sdalign", dhd_varint, DHD_GET_VAR, -1, + "display the (compiled in) alignment target for sd requests"}, + { "txbound", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "get/set maximum number of tx frames per scheduling"}, + { "rxbound", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "get/set maximum number of rx frames per scheduling"}, + { "txminmax", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "get/set maximum number of tx frames per scheduling while rx frames outstanding"}, + { "dconpoll", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set dongle console polling interval (ms)"}, + { "dump", dhd_varstr, DHD_GET_VAR, -1, + "dump information"}, + { "cons", dhd_varstr, -1, DHD_SET_VAR, + "send string to device console (sd only)"}, + { "clearcounts", dhd_var_void, -1, DHD_SET_VAR, + "reset the bus stats shown in the dhd dump"}, + { "logdump", dhd_varstr, DHD_GET_VAR, -1, + "dump the timestamp logging buffer"}, + { "logcal", dhd_varint, -1, DHD_SET_VAR, + "logcal <n> -- log around an osl_delay of <n> usecs"}, + { "logstamp", dhd_logstamp, -1, DHD_SET_VAR, + "logstamp [<n1>] [<n2>] -- add a message to the log"}, + { "ramstart", dhd_varint, DHD_GET_VAR, -1, + "display start address of onchip SOCRAM"}, + { "ramsize", dhd_varint, DHD_GET_VAR, -1, + "display size of onchip SOCRAM"}, + { "membytes", dhd_membytes, DHD_GET_VAR, DHD_SET_VAR, + "membytes [-h | -r | -i] <address> <length> [<data>]\n" + "\tread or write data in the dongle ram\n" + "\t-h <data> is a sequence of hex digits rather than a char string\n" + "\t-r output binary to stdout rather hex\n"}, + { "download", dhd_download, -1, DHD_SET_VAR, + "download [-a <address>] [--noreset] [--norun] [--verify] <binfile> [<varsfile>]\n" + "\tdownload file to specified dongle ram address and start CPU\n" + "\toptional vars file will replace vars parsed from the CIS\n" + "\t--noreset do not reset SOCRAM core before download\n" + "\t--norun do not start dongle CPU after download\n" + "\t--verify do readback verify \n" + "\tdefault <address> is 0\n"}, + { "dldn", dhd_dldn, -1, DHD_SET_VAR, + "download <binfile>\n" + "\tdownload file to specified dongle ram address 0\n"}, + { "vars", dhd_vars, DHD_GET_VAR, DHD_SET_VAR, + "vars [<file>]\n" + "\toverride SPROM vars with <file> (before download)\n"}, + { "coredump", dhd_coredump, -1, -1, + "coredump <file>\n" + "\tdump dongle RAM content into a file in dumpfile format\n" + "\tfor use with ELF core generator"}, + { "consoledump", dhd_consoledump, -1, -1, + "consoledump\n" + "\tdump dongle debug console buffer"}, + { "upload", dhd_upload, -1, -1, + "upload [-a <address> ] <file> [<size>]\n" + "\tupload dongle RAM content into a file\n" + "\tdefault <address> is 0, default <size> is RAM size"}, + { "srdump", dhd_sprom, DHD_GET_VAR, -1, + "display SPROM content" }, + { "srwrite", dhd_sprom, -1, DHD_SET_VAR, + "write data or file content to SPROM\n" + "\tsrwrite <word-offset> <word-value> ...\n" + "\tsrwrite [-c] <srom-file-path>\n" + "\t -c means write regardless of crc"}, + { "sleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "enter/exit simulated host sleep (bus powerdown w/OOB wakeup)"}, + { "kso", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "keep sdio on"}, + { "devcap", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "brcm device capabilities"}, + { "devsleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "Sleep CMD14"}, +#ifdef SDTEST + { "extloop", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "external loopback: convert all tx data to echo test frames"}, + { "pktgen", dhd_pktgen, DHD_GET_VAR, DHD_SET_VAR, + "configure/report pktgen status (SDIO)\n" + "\t-f N frequency: send/recv a burst every N ticks\n" + "\t-c N count: send/recv N packets each burst\n" + "\t-t N total: stop after a total of N packets\n" + "\t-p N print: display counts on console every N bursts\n" + "\t-m N min: set minimum length of packet data\n" + "\t-M N Max: set maximum length of packet data\n" + "\t-l N len: set fixed length of packet data\n" + "\t-s N stop after N tx failures\n" + "\t-d dir test direction/type:\n" + "\t send -- send packets discarded by dongle\n" + "\t echo -- send packets to be echoed by dongle\n" + "\t burst -- request bursts (of size <-c>) from dongle\n" + "\t one every <-f> ticks, until <-t> total requests\n" + "\t recv -- request dongle enter continuous send mode,\n" + "\t read up to <-c> pkts every <-f> ticks until <-t>\n" + "\t total reads\n"}, +#endif /* SDTEST */ + { "dngl_isolation", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set dongle isolation, so the dev could be disabled with out effecting the dongle state"}, + { "ltrsleep_on_unload", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set sending ltr sleep message on unload config"}, + { "sdreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR, + "g/set sdpcmdev core register (f1) across SDIO (CMD53)"}, + { "sbreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR, + "g/set any backplane core register (f1) across SDIO (CMD53)"}, + { "sd_cis", dhd_var_getandprintstr, DHD_GET_VAR, -1, + "dump sdio CIS"}, + { "sd_devreg", dhd_sd_reg, DHD_GET_VAR, DHD_SET_VAR, + "g/set device register across SDIO bus (CMD52)"}, + { "sd_hostreg", dhd_sd_reg, DHD_GET_VAR, DHD_SET_VAR, + "g/set local controller register"}, + { "sd_blocksize", dhd_sd_blocksize, DHD_GET_VAR, DHD_SET_VAR, + "g/set block size for a function"}, + { "sd_blockmode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set blockmode"}, + { "sd_ints", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set client ints"}, + { "sd_dma", dhd_dma_mode, DHD_GET_VAR, DHD_SET_VAR, + "g/set dma usage: [PIO | SDMA | ADMA1 | ADMA2]"}, + { "sd_yieldcpu", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "allow blocking (yield of CPU) on data xfer"}, + { "sd_minyield", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "minimum xfer size to allow CPU yield"}, + { "sd_forcerb", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "force readback when changing local interrupt settings"}, + { "sd_numints", dhd_varint, DHD_GET_VAR, -1, + "number of device interrupts"}, + { "sd_numlocalints", dhd_varint, DHD_GET_VAR, -1, + "number of non-device interrupts"}, + { "sd_divisor", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "set the divisor for SDIO clock generation"}, + { "sd_power", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "set the SD Card slot power"}, + { "sd_power_save", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "set the SDIO3.0 power save value"}, + { "sd_clock", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "turn on/off the SD Clock"}, + { "sd_crc", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "turn on/off CRC checking in SPI mode"}, + { "sd_mode", dhd_sd_mode, DHD_GET_VAR, DHD_SET_VAR, + "g/set SDIO bus mode (spi, sd1, sd4)"}, + { "sd_highspeed", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "set the high-speed clocking mode"}, + { "sd_msglevel", dhd_sd_msglevel, DHD_GET_VAR, DHD_SET_VAR, + "g/set debug message level"}, + { "sd_hciregs", dhd_varstr, DHD_GET_VAR, -1, + "display host-controller interrupt registers"}, + { "sdiod_drive", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "SDIO Device drive strength in milliamps. (0=tri-state, 1-12mA)"}, +#ifdef BCMSPI + { "spi_errstats", dhd_spierrstats, DHD_GET_VAR, DHD_SET_VAR, + "SPI device status error statistics."}, + { "spi_respdelay", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set response delay flag."}, +#endif /* BCMSPI */ + { "devreset", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "Move device into or out of reset state (1/reset, or 0/operational)"}, + { "ioctl_timeout", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "IOCTL response timeout (milliseconds)."}, +#ifdef WLBTAMP + { "HCI_cmd", wl_HCI_cmd, -1, DHD_SET_VAR, + "carries HCI commands to the driver\n" + "\tusage: dhd HCI_cmd <command> <args>\n" }, + { "HCI_ACL_data", wl_HCI_ACL_data, -1, DHD_SET_VAR, + "carries HCI ACL data packet to the driver\n" + "\tusage: dhd HCI_ACL_data <logical link handle> <data>\n" }, +#endif +#ifdef QMONITOR + { "qtime_percent", dhd_qtime_percent, DHD_GET_VAR, -1, + "qtime_percent gives the percentage of time where DHD TX queue\n" + "has a number of packets queued above a threshold set by\n" + "the iovar qtimer_thres"}, + { "qtime_thres", dhd_qtime_thres, DHD_GET_VAR, DHD_SET_VAR, + "qtime_thres sets the thresold of number of packets used\n" + "by the iovar qtime_percent"}, +#endif +#ifdef PROP_TXSTATUS + { "proptx", dhd_proptxstatusenable, DHD_GET_VAR, DHD_SET_VAR, + "enable/disable the proptxtstatus feature\n" + "0 - disabled\n" + "1 - enabled\n"}, + { "ptxmode", dhd_proptxstatusmode, DHD_GET_VAR, DHD_SET_VAR, + "set the proptxtstatus operation mode:\n" + "0 - Unsupported\n" + "1 - Use implied credit from a packet status\n" + "2 - Use explicit credit\n" }, + { "proptx_opt", dhd_proptxopt, DHD_GET_VAR, DHD_SET_VAR, + "enable/disable proptxtstatus optimizations to increase throughput:\n" + "0 - Unsupported\n" + "1 - Enable proptxstatus optimizations to increase throughput\n" }, + { "pmodule_ignore", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "use/bypass the proptxtstatus module\n" + "0 - apply\n" + "1 - bypass\n"}, + { "pcredit_ignore", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "apply/ignore the proptxtstatus credit control\n" + "0 - apply\n" + "1 - ignore\n"}, + { "ptxstatus_ignore", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "process/ignore the proptxtstatus txstaus\n" + "0 - process\n" + "1 - ignore\n"}, + { "rxpkt_chk", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "check/ignore rx packet for multiple AC detection\n" + "0 - ignore\n" + "1 - check\n"}, +#endif /* PROP_TXSTATUS */ + { "sd_uhsimode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set UHSI Mode"}, + { "host_reorder_flows", dhd_hostreorder_flows, DHD_GET_VAR, -1, + "get host reorder flows "}, + { "txglomsize", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "max glom size for sdio tx\n"}, + { "txglommode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "glom mode for sdio tx 0- copy, 1- multidescriptor\n"}, + { "fw_hang_report", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "enable/disable report firmware hangs for firmware reload\n" + "0 - disabled (for testing)\n" + "1 - enabled (default)\n"}, + { "tuning_mode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "get/set tuning mode \n" + "1 - Disabled periodic tuning \n" + "0 - Enable periodic tuning \n"}, + { "tcpack_suppress", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "Turn tcpack_suppress on/off\n" + "0 - off\n" + "1 - on\n"}, + { "txinrx_thres", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "get/set threshold for num of in-queued pkts to tx in rx process\n" + "0 - always send out in rx process\n" + "num - amount of in-queued pkts\n"}, + { NULL, NULL, 0, 0, NULL } +}; + +cmd_t dhd_varcmd = {"var", dhd_varint, -1, -1, "unrecognized name, type -h for help"}; +char *dhdu_av0; + +#if defined(BWL_FILESYSTEM_SUPPORT) +static int +file_size(char *fname) +{ + FILE *fp; + long size = -1; + + /* Can't use stat() because of Win CE */ + + if ((fp = fopen(fname, "rb")) == NULL || + fseek(fp, 0, SEEK_END) < 0 || + (size = ftell(fp)) < 0) + fprintf(stderr, "Could not determine size of %s: %s\n", + fname, strerror(errno)); + + if (fp != NULL) + fclose(fp); + + return (int)size; +} +#endif /* BWL_FILESYSTEM_SUPPORT */ + + +/* parse/validate the command line arguments */ +/* +* pargv is updated upon return if the first argument is an option. + * It remains intact otherwise. + */ +int +dhd_option(char ***pargv, char **pifname, int *phelp) +{ + char *ifname = NULL; + int help = FALSE; + int status = CMD_OPT; + char **argv = *pargv; + + int_fmt = INT_FMT_DEC; + + while (*argv) { + /* select different adapter */ + if (!strcmp(*argv, "-a") || !strcmp(*argv, "-i")) { + char *opt = *argv++; + ifname = *argv; + if (!ifname) { + fprintf(stderr, + "error: expected interface name after option %s\n", opt); + status = CMD_ERR; + break; + } + } + + /* integer output format */ + else if (!strcmp(*argv, "-d")) + int_fmt = INT_FMT_DEC; + else if (!strcmp(*argv, "-u")) + int_fmt = INT_FMT_UINT; + else if (!strcmp(*argv, "-x")) + int_fmt = INT_FMT_HEX; + + /* command usage */ + else if (!strcmp(*argv, "-h")) + help = TRUE; + + /* done with generic options */ + else { + status = CMD_DHD; + break; + } + + /* consume the argument */ + argv ++; + break; + } + + *phelp = help; + *pifname = ifname; + *pargv = argv; + + return status; +} + +void +dhd_cmd_usage(cmd_t *cmd) +{ + if (strlen(cmd->name) >= 8) + fprintf(stderr, "%s\n\t%s\n\n", cmd->name, cmd->help); + else + fprintf(stderr, "%s\t%s\n\n", cmd->name, cmd->help); +} + +/* Dump out short list of commands */ +static int +dhd_list(void *dhd, cmd_t *garb, char **argv) +{ + cmd_t *cmd; + int nrows, i, len; + char *buf; + int letter, col, row, pad; + + UNUSED_PARAMETER(dhd); + UNUSED_PARAMETER(garb); + UNUSED_PARAMETER(argv); + + for (cmd = dhd_cmds, nrows = 0; cmd->name; cmd++) + nrows++; + + nrows /= 4; + nrows++; + + len = nrows * 80 + 2; + buf = malloc(len); + if (buf == NULL) { + fprintf(stderr, "Failed to allocate buffer of %d bytes\n", len); + return BCME_NOMEM; + } + for (i = 0; i < len; i++) + *(buf+i) = 0; + + row = col = 0; + for (letter = 'a'; letter < 'z'; letter++) { + for (cmd = dhd_cmds; cmd->name; cmd++) { + if (cmd->name[0] == letter || cmd->name[0] == letter - 0x20) { + strcat(buf+row*80, cmd->name); + pad = 18 * (col + 1) - strlen(buf+row*80); + if (pad < 1) + pad = 1; + for (; pad; pad--) + strcat(buf+row*80, " "); + row++; + if (row == nrows) { + col++; row = 0; + } + } + } + } + for (row = 0; row < nrows; row++) + printf("%s\n", buf+row*80); + + printf("\n"); + free(buf); + return (0); +} + +void +dhd_cmds_usage(cmd_t *port_cmds) +{ + cmd_t *port_cmd; + cmd_t *cmd; + + /* print usage of port commands */ + for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++) + /* Check for wc_cmd */ + dhd_cmd_usage(port_cmd); + + /* print usage of common commands without port counterparts */ + for (cmd = dhd_cmds; cmd->name; cmd++) { + /* search if port counterpart exists */ + for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++) + if (!strcmp(port_cmd->name, cmd->name)) + break; + if (!port_cmd || !port_cmd->name) + dhd_cmd_usage(cmd); + } +} + +void +dhd_usage(cmd_t *port_cmds) +{ + fprintf(stderr, + "Usage: %s [-a|i <adapter>] [-h] [-d|u|x] <command> [arguments]\n", + dhdu_av0); + + fprintf(stderr, "\n"); + fprintf(stderr, " -h this message\n"); + fprintf(stderr, " -a, -i adapter name or number\n"); + fprintf(stderr, " -d display values as signed integer\n"); + fprintf(stderr, " -u display values as unsigned integer\n"); + fprintf(stderr, " -x display values as hexdecimal\n"); + fprintf(stderr, "\n"); + + dhd_cmds_usage(port_cmds); +} + +int +dhd_check(void *dhd) +{ + int ret; + int val; + + if ((ret = dhd_get(dhd, DHD_GET_MAGIC, &val, sizeof(int))) < 0) + return ret; + if (val != DHD_IOCTL_MAGIC) + return -1; + if ((ret = dhd_get(dhd, DHD_GET_VERSION, &val, sizeof(int))) < 0) + return ret; + if (val > DHD_IOCTL_VERSION) { + fprintf(stderr, "Version mismatch, please upgrade\n"); + return -1; + } + return 0; +} + +void +dhd_printint(int val) +{ + switch (int_fmt) { + case INT_FMT_UINT: + printf("%u\n", val); + break; + case INT_FMT_HEX: + printf("0x%x\n", val); + break; + case INT_FMT_DEC: + default: + printf("%d\n", val); + break; + } +} + +/* pretty hex print a contiguous buffer (tweaked from wlu) */ +void +dhd_hexdump(uchar *buf, uint nbytes, uint saddr) +{ + char line[256]; + char* p; + uint i; + + if (nbytes == 0) { + printf("\n"); + return; + } + + p = line; + for (i = 0; i < nbytes; i++) { + if (i % 16 == 0) { + p += sprintf(p, "%08x: ", saddr + i); /* line prefix */ + } + p += sprintf(p, "%02x ", buf[i]); + if (i % 16 == 15) { + uint j; + p += sprintf(p, " "); + for (j = i-15; j <= i; j++) + p += sprintf(p, "%c", + ((buf[j] >= 0x20 && buf[j] <= 0x7f) ? buf[j] : '.')); + printf("%s\n", line); /* flush line */ + p = line; + } + } + + /* flush last partial line */ + if (p != line) + printf("%s\n", line); +} + + +#ifdef SDTEST +static int +dhd_pktgen(void *dhd, cmd_t *cmd, char **argv) +{ + int ret = 0; + void *ptr = NULL; + dhd_pktgen_t pktgen; + char *str; + + UNUSED_PARAMETER(dhd); + UNUSED_PARAMETER(cmd); + + /* Get current settings */ + if ((ret = dhd_var_getbuf(dhd, "pktgen", NULL, 0, &ptr)) != 0) + return ret; + memcpy(&pktgen, ptr, sizeof(pktgen)); + + if (pktgen.version != DHD_PKTGEN_VERSION) { + fprintf(stderr, "pktgen version mismatch (module %d app %d)\n", + pktgen.version, DHD_PKTGEN_VERSION); + return BCME_ERROR; + } + + /* Presence of args implies a set, else a get */ + if (*++argv) { + miniopt_t opts; + int opt_err; + + /* Initialize option parser */ + miniopt_init(&opts, "pktgen", "", FALSE); + + while ((opt_err = miniopt(&opts, argv)) != -1) { + if (opt_err == 1) { + fprintf(stderr, "pktgen options error\n"); + ret = -1; + goto exit; + } + argv += opts.consumed; + + if (!opts.good_int && opts.opt != 'd') { + fprintf(stderr, "invalid integer %s\n", opts.valstr); + ret = -1; + goto exit; + } + + switch (opts.opt) { + case 'f': + pktgen.freq = opts.uval; + break; + case 'c': + pktgen.count = opts.uval; + break; + case 'p': + pktgen.print = opts.uval; + break; + case 't': + pktgen.total = opts.uval; + break; + case 's': + pktgen.stop = opts.uval; + break; + case 'm': + pktgen.minlen = opts.uval; + break; + case 'M': + pktgen.maxlen = opts.uval; + break; + case 'l': case 'L': + pktgen.minlen = pktgen.maxlen = opts.uval; + break; + case 'd': + if (!strcmp(opts.valstr, "send")) + pktgen.mode = DHD_PKTGEN_SEND; + else if (!strcmp(opts.valstr, "echo")) + pktgen.mode = DHD_PKTGEN_ECHO; + else if (!strcmp(opts.valstr, "burst")) + pktgen.mode = DHD_PKTGEN_RXBURST; + else if (!strcmp(opts.valstr, "recv")) + pktgen.mode = DHD_PKTGEN_RECV; + else { + fprintf(stderr, "unrecognized dir mode %s\n", + opts.valstr); + return BCME_USAGE_ERROR; + } + break; + + default: + fprintf(stderr, "option parsing error (key %s valstr %s)\n", + opts.key, opts.valstr); + ret = BCME_USAGE_ERROR; + goto exit; + } + } + + if (pktgen.maxlen < pktgen.minlen) { + fprintf(stderr, "min/max error (%d/%d)\n", pktgen.minlen, pktgen.maxlen); + ret = -1; + goto exit; + } + + /* Set the new values */ + ret = dhd_var_setbuf(dhd, "pktgen", &pktgen, sizeof(pktgen)); + } else { + printf("Counts: %d send attempts, %d received, %d tx failures\n", + pktgen.numsent, pktgen.numrcvd, pktgen.numfail); + } + + /* Show configuration in either case */ + switch (pktgen.mode) { + case DHD_PKTGEN_ECHO: str = "echo"; break; + case DHD_PKTGEN_SEND: str = "send"; break; + case DHD_PKTGEN_RECV: str = "recv"; break; + case DHD_PKTGEN_RXBURST: str = "burst"; break; + default: str = "UNKNOWN"; break; + } + + printf("Config: mode %s %d pkts (len %d-%d) each %d ticks\n", + str, pktgen.count, pktgen.minlen, pktgen.maxlen, pktgen.freq); + + /* Second config line for optional items */ + str = " "; + if (pktgen.total) { + printf("%slimit %d", str, pktgen.total); + str = ", "; + } + if (pktgen.print) { + printf("%sprint every %d ticks", str, (pktgen.freq * pktgen.print)); + str = ", "; + } + if (pktgen.stop) { + printf("%sstop after %d tx failures", str, pktgen.stop); + str = ", "; + } + if (str[0] == ',') + printf("\n"); + +exit: + return ret; +} +#endif /* SDTEST */ + +static dbg_msg_t dhd_sd_msgs[] = { + {SDH_ERROR_VAL, "error"}, + {SDH_TRACE_VAL, "trace"}, + {SDH_INFO_VAL, "info"}, + {SDH_DATA_VAL, "data"}, + {SDH_CTRL_VAL, "control"}, + {SDH_LOG_VAL, "log"}, + {SDH_DMA_VAL, "dma"}, + {0, NULL} +}; + +static int +dhd_sd_msglevel(void *dhd, cmd_t *cmd, char **argv) +{ + return dhd_do_msglevel(dhd, cmd, argv, dhd_sd_msgs); +} + +static int +dhd_sd_blocksize(void *dhd, cmd_t *cmd, char **argv) +{ + int ret; + int argc; + char *endptr = NULL; + void *ptr = NULL; + int func, size; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (argc < 1 || argc > 2) { + printf("required args: function [size] (size 0 means max)\n"); + return BCME_USAGE_ERROR; + } + + func = strtol(argv[1], &endptr, 0); + if (*endptr != '\0') { + printf("Invalid function: %s\n", argv[1]); + return BCME_USAGE_ERROR; + } + + if (argc > 1) { + size = strtol(argv[2], &endptr, 0); + if (*endptr != '\0') { + printf("Invalid size: %s\n", argv[1]); + return BCME_USAGE_ERROR; + } + } + + if (argc == 1) { + if ((ret = dhd_var_getbuf(dhd, cmd->name, &func, sizeof(func), &ptr)) >= 0) + printf("Function %d block size: %d\n", func, *(int*)ptr); + } else { + printf("Setting function %d block size to %d\n", func, size); + size &= 0x0000ffff; size |= (func << 16); + ret = dhd_var_setbuf(dhd, cmd->name, &size, sizeof(size)); + } + + return (ret); +} + +static int +dhd_sd_mode(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int argc; + int sdmode; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (argv[1]) { + if (!strcmp(argv[1], "spi")) { + strcpy(argv[1], "0"); + } else if (!strcmp(argv[1], "sd1")) { + strcpy(argv[1], "1"); + } else if (!strcmp(argv[1], "sd4")) { + strcpy(argv[1], "2"); + } else { + return BCME_USAGE_ERROR; + } + + ret = dhd_var_setint(wl, cmd, argv); + + } else { + if ((ret = dhd_var_get(wl, cmd, argv))) { + return (ret); + } else { + sdmode = *(int32*)buf; + + printf("SD Mode is: %s\n", + sdmode == 0 ? "SPI" + : sdmode == 1 ? "SD1" + : sdmode == 2 ? "SD4" : "Unknown"); + } + } + + return (ret); +} + +static int +dhd_dma_mode(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int argc; + int dmamode; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (argv[1]) { + if (!stricmp(argv[1], "pio")) { + strcpy(argv[1], "0"); + } else if (!strcmp(argv[1], "0")) { + } else if (!stricmp(argv[1], "dma")) { + strcpy(argv[1], "1"); + } else if (!stricmp(argv[1], "sdma")) { + strcpy(argv[1], "1"); + } else if (!strcmp(argv[1], "1")) { + } else if (!stricmp(argv[1], "adma1")) { + strcpy(argv[1], "2"); + } else if (!stricmp(argv[1], "adma")) { + strcpy(argv[1], "3"); + } else if (!stricmp(argv[1], "adma2")) { + strcpy(argv[1], "3"); + } else { + return BCME_USAGE_ERROR; + } + + ret = dhd_var_setint(wl, cmd, argv); + + } else { + if ((ret = dhd_var_get(wl, cmd, argv))) { + return (ret); + } else { + dmamode = *(int32*)buf; + + printf("DMA Mode is: %s\n", + dmamode == 0 ? "PIO" + : dmamode == 1 ? "SDMA" + : dmamode == 2 ? "ADMA1" + : dmamode == 3 ? "ADMA2" + : "Unknown"); + } + } + + return (ret); +} + + +/* + * dhd_regs2args is a generic function that is used for setting/getting + * DHDIOVAR variables that require address for read, and + * address + data for write. + */ +static int +dhd_reg2args(void *dhd, cmd_t *cmd, char **argv) +{ + char var[256]; + uint32 int_val; + bool get = TRUE; + uint32 len; + void *ptr = NULL; + char *endptr; + int ret = 0; + + if (argv[1]) { + len = sizeof(int_val); + int_val = strtoul(argv[1], &endptr, 0); + memcpy(var, (char *)&int_val, sizeof(int_val)); + } + else + return BCME_USAGE_ERROR; + + if (argv[2]) { + get = FALSE; + int_val = strtoul(argv[2], &endptr, 0); + memcpy(&var[len], (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + } + if (get) { + if ((ret = dhd_var_getbuf(dhd, cmd->name, var, sizeof(var), &ptr)) < 0) + return ret; + + printf("0x%x\n", (*(int *)ptr)); + } + else + ret = dhd_var_setbuf(dhd, cmd->name, &var, sizeof(var)); + return ret; +} + +static int +dhd_pcie_dmaxfer(void *dhd, cmd_t *cmd, char **argv) +{ + char var[256]; + uint32 int_val; + uint32 len; + char *endptr; + int ret = 0; + + bzero(var, sizeof(var)); + if (argv[1]) { + len = sizeof(int_val); + int_val = strtoul(argv[1], &endptr, 0); + memcpy(var, (char *)&int_val, sizeof(int_val)); + } + else + return BCME_USAGE_ERROR; + + if (argv[2]) { + int_val = strtoul(argv[2], &endptr, 0); + memcpy(&var[len], (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + } + + if (argv[3]) { + int_val = strtoul(argv[3], &endptr, 0); + memcpy(&var[len], (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + } + ret = dhd_var_setbuf(dhd, cmd->name, &var, sizeof(var)); + return ret; +} + +static int +dhd_sdreg(void *dhd, cmd_t *cmd, char **argv) +{ + int ret; + sdreg_t sdreg; + uint argc; + char *ptr = NULL; + + UNUSED_PARAMETER(cmd); + + bzero(&sdreg, sizeof(sdreg)); + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + /* required args: offset (will default size) */ + if (argc < 1) { + printf("required args: offset[/size] [value]\n"); + return BCME_USAGE_ERROR; + } + + sdreg.offset = strtoul(argv[1], &ptr, 0); + if (*ptr && *ptr != '/') { + printf("Bad arg: %s\n", argv[1]); + return BCME_USAGE_ERROR; + } + + /* read optional /size */ + if (*ptr == '/') { + sdreg.func = strtol((ptr+1), &ptr, 0); + if (*ptr || ((sdreg.func != 2) && sdreg.func != 4)) { + printf("Bad size option?\n"); + return BCME_USAGE_ERROR; + } + } + else { + sdreg.func = 4; + printf("Defaulting to register size 4\n"); + } + + if (argc > 1) { + sdreg.value = strtoul(argv[2], &ptr, 0); + if (*ptr) { + printf("Bad value: %s\n", argv[2]); + return BCME_USAGE_ERROR; + } + } + + if (argc <= 1) { + ret = dhd_var_getbuf(dhd, argv[0], &sdreg, sizeof(sdreg), (void**)&ptr); + if (ret >= 0) + printf("0x%0*x\n", (2 * sdreg.func), *(int *)ptr); + } else { + ret = dhd_var_setbuf(dhd, argv[0], &sdreg, sizeof(sdreg)); + } + + return (ret); +} + +static int +dhd_membytes(void *dhd, cmd_t *cmd, char **argv) +{ + int ret = -1; + uint argc; + char *ptr; + int params[2]; + uint addr; + uint len; + int align; + + int rawout, hexin; + + miniopt_t opts; + int opt_err; + + /* Parse command-line options */ + miniopt_init(&opts, "membytes", "rh", FALSE); + + rawout = hexin = 0; + + argv++; + while ((opt_err = miniopt(&opts, argv)) != -1) { + if (opt_err == 1) { + fprintf(stderr, "membytes options error\n"); + ret = -1; + goto exit; + } + + if (opts.positional) + break; + + argv += opts.consumed; + + if (opts.opt == 'h') { + hexin = 1; + } else if (opts.opt == 'r') { + rawout = 1; + } else { + fprintf(stderr, "membytes command error\n"); + ret = -1; + goto exit; + } + } + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + + /* required args: address size [<data>]] */ + if (argc < 2) { + fprintf(stderr, "required args: address size [<data>]\n"); + return BCME_USAGE_ERROR; + } + + if (argc < 3 && hexin) { + fprintf(stderr, "missing <data> required by -h\n"); + return BCME_USAGE_ERROR; + } + if ((argc > 2) && (rawout)) { + fprintf(stderr, "can't have <data> arg with -r\n"); + return BCME_USAGE_ERROR; + } + + /* read address */ + addr = strtoul(argv[0], &ptr, 0); + if (*ptr) { + fprintf(stderr, "Bad arg: %s\n", argv[0]); + return BCME_USAGE_ERROR; + } + + /* read size */ + len = strtoul(argv[1], &ptr, 0); + if (*ptr) { + fprintf(stderr, "Bad value: %s\n", argv[1]); + return BCME_USAGE_ERROR; + } + + align = addr & 0x03; + if (align && argc > 2) { + fprintf(stderr, "Can only write starting at long-aligned addresses.\n"); + return BCME_USAGE_ERROR; + } + + /* get can just use utility function, set must copy custom buffer */ + if (argc == 2) { + /* Read */ + uint chunk = DHD_IOCTL_MAXLEN; + for (addr -= align, len += align; len; addr += chunk, len -= chunk, align = 0) { + chunk = MIN(chunk, len); + params[0] = addr; + params[1] = ROUNDUP(chunk, 4); + ret = dhd_var_getbuf(dhd, "membytes", + params, (2 * sizeof(int)), (void**)&ptr); + if (ret < 0) + goto exit; + + if (rawout) { + fwrite(ptr + align, sizeof(char), chunk - align, stdout); + } else { + dhd_hexdump((uchar*)ptr + align, chunk - align, addr + align); + } + } + } else { + /* Write */ + uint patlen = strlen(argv[2]); + uint chunk, maxchunk; + char *sptr; + + if (hexin) { + char *inptr, *outptr; + if (patlen & 1) { + fprintf(stderr, "Hex (-h) must consist of whole bytes\n"); + ret = BCME_USAGE_ERROR; + goto exit; + } + + for (inptr = outptr = argv[2]; patlen; patlen -= 2) { + int n1, n2; + + n1 = (int)((unsigned char)*inptr++); + n2 = (int)((unsigned char)*inptr++); + if (!isxdigit(n1) || !isxdigit(n2)) { + fprintf(stderr, "invalid hex digit %c\n", + (isxdigit(n1) ? n2 : n1)); + ret = BCME_USAGE_ERROR; + goto exit; + } + n1 = isdigit(n1) ? (n1 - '0') + : ((islower(n1) ? (toupper(n1)) : n1) - 'A' + 10); + n2 = isdigit(n2) ? (n2 - '0') + : ((islower(n2) ? (toupper(n2)) : n2) - 'A' + 10); + *outptr++ = (n1 * 16) + n2; + } + + patlen = outptr - argv[2]; + } + + sptr = argv[2]; + maxchunk = DHD_IOCTL_MAXLEN - (strlen(cmd->name) + 1 + (2 * sizeof(int))); + + while (len) { + chunk = (len > maxchunk) ? (maxchunk & ~0x3) : len; + + /* build the iovar command */ + memset(buf, 0, DHD_IOCTL_MAXLEN); + strcpy(buf, cmd->name); + ptr = buf + strlen(buf) + 1; + params[0] = addr; params[1] = chunk; + memcpy(ptr, params, (2 * sizeof(int))); + ptr += (2 * sizeof(int)); + addr += chunk; len -= chunk; + + while (chunk--) { + *ptr++ = *sptr++; + if (sptr >= (argv[2] + patlen)) + sptr = argv[2]; + } + + ret = dhd_set(dhd, DHD_SET_VAR, &buf[0], (ptr - buf)); + if (ret < 0) + goto exit; + } + } + +exit: + return ret; +} + +static int +dhd_idletime(void *dhd, cmd_t *cmd, char **argv) +{ + int32 idletime; + char *endptr = NULL; + int err = 0; + + if (argv[1]) { + if (!strcmp(argv[1], "never")) { + idletime = 0; + } else if (!strcmp(argv[1], "immediate") || !strcmp(argv[1], "immed")) { + idletime = DHD_IDLE_IMMEDIATE; + } else { + idletime = strtol(argv[1], &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "invalid number %s\n", argv[1]); + err = BCME_USAGE_ERROR; + } + } + if ((idletime < 0) && (idletime != DHD_IDLE_IMMEDIATE)) { + fprintf(stderr, "invalid value %s\n", argv[1]); + err = -1; + } + + if (!err) { + strcpy(buf, "idletime"); + endptr = buf + strlen(buf) + 1; + memcpy(endptr, &idletime, sizeof(uint32)); + endptr += sizeof(uint32); + err = dhd_set(dhd, DHD_SET_VAR, &buf[0], (endptr - buf)); + } + } else { + if ((err = dhd_var_get(dhd, cmd, argv))) { + return err; + } else { + idletime = *(int32*)buf; + + if (idletime == 0) { + printf("0 (never)\n"); + } else if (idletime == DHD_IDLE_IMMEDIATE) { + printf("-1 (immediate)\n"); + } else if (idletime > 0) { + printf("%d\n", idletime); + } else printf("%d (invalid)\n", idletime); + } + } + return err; +} + +static int +dhd_idleclock(void *dhd, cmd_t *cmd, char **argv) +{ + int32 idleclock; + char *endptr = NULL; + int err = 0; + + if (argv[1]) { + if (!strcmp(argv[1], "active")) { + idleclock = DHD_IDLE_ACTIVE; + } else if (!strcmp(argv[1], "stopped")) { + idleclock = DHD_IDLE_STOP; + } else { + idleclock = strtol(argv[1], &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "invalid number %s\n", argv[1]); + err = BCME_USAGE_ERROR; + } + } + + if (!err) { + strcpy(buf, "idleclock"); + endptr = buf + strlen(buf) + 1; + memcpy(endptr, &idleclock, sizeof(int32)); + endptr += sizeof(int32); + err = dhd_set(dhd, DHD_SET_VAR, &buf[0], (endptr - buf)); + } + } else { + if ((err = dhd_var_get(dhd, cmd, argv))) { + return err; + } else { + idleclock = *(int32*)buf; + + if (idleclock == DHD_IDLE_ACTIVE) + printf("Idleclock %d (active)\n", idleclock); + else if (idleclock == DHD_IDLE_STOP) + printf("Idleclock %d (stopped)\n", idleclock); + else + printf("Idleclock divisor %d\n", idleclock); + } + } + return err; +} + +/* Word count for a 4kb SPROM */ +#define SPROM_WORDS 256 + +static int +dhd_sprom(void *dhd, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + return (-1); +#else + int ret, i; + uint argc; + char *endptr; + char *bufp, *countptr; + uint16 *wordptr; + uint offset, words, bytes; + bool nocrc = FALSE; + + char *fname; + FILE *fp; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + /* init buffer */ + bufp = buf; + memset(bufp, 0, DHD_IOCTL_MAXLEN); + strcpy(bufp, "sprom"); + bufp += strlen("sprom") + 1; + + if (strcmp(argv[0], "srdump") == 0) { + if (argc) { + fprintf(stderr, "Command srdump doesn't take args\n"); + return BCME_USAGE_ERROR; + } + offset = 0; + words = SPROM_WORDS; + bytes = 2 * words; + + memcpy(bufp, &offset, sizeof(int)); + bufp += sizeof(int); + memcpy(bufp, &bytes, sizeof(int)); + bufp += sizeof(int); + + if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) { + fprintf(stderr, "Internal error: unaligned word buffer\n"); + return BCME_ERROR; + } + } else { + if (strcmp(argv[0], "srwrite") != 0) { + fprintf(stderr, "Unimplemented sprom command: %s\n", argv[0]); + return BCME_USAGE_ERROR; + } + + if (argc == 0) { + return BCME_USAGE_ERROR; + } else if ((argc == 1) || + ((argc == 2) && ((nocrc = !strcmp(argv[1], "-c"))))) { + + fname = nocrc ? argv[2] : argv[1]; + + /* determine and validate file size */ + if ((ret = file_size(fname)) < 0) + return BCME_ERROR; + + bytes = ret; + offset = 0; + words = bytes / 2; + + if (bytes != 2 * SPROM_WORDS) { + fprintf(stderr, "Bad file size\n"); + return BCME_ERROR; + } + + memcpy(bufp, &offset, sizeof(int)); + bufp += sizeof(int); + memcpy(bufp, &bytes, sizeof(int)); + bufp += sizeof(int); + + if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) { + fprintf(stderr, "Internal error: unaligned word buffer\n"); + return BCME_ERROR; + } + + if ((fp = fopen(fname, "rb")) == NULL) { + fprintf(stderr, "Could not open %s: %s\n", + fname, strerror(errno)); + return BCME_ERROR; + } + + if (fread((uint16*)bufp, sizeof(uint16), words, fp) != words) { + fprintf(stderr, "Could not read %d bytes from %s\n", + words * 2, fname); + fclose(fp); + return BCME_ERROR; + } + + fclose(fp); + + if (!nocrc && + hndcrc8((uint8*)bufp, bytes, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE) { + fprintf(stderr, "CRC check failed: 0x%02x, should be 0x%02x.\n", + ((uint8*)bufp)[bytes-1], + ~hndcrc8((uint8*)bufp, bytes - 1, CRC8_INIT_VALUE) & 0xff); + return BCME_ERROR; + } + + ltoh16_buf(bufp, bytes); + } else { + offset = strtoul(*++argv, &endptr, 0) * 2; + if (*endptr != '\0') { + fprintf(stderr, "offset %s is not an integer\n", *argv); + return BCME_USAGE_ERROR; + } + + memcpy(bufp, &offset, sizeof(int)); + bufp += sizeof(int); + countptr = bufp; + bufp += sizeof(int); + + if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) { + fprintf(stderr, "Internal error: unaligned word buffer\n"); + return BCME_ERROR; + } + + for (words = 0, wordptr = (uint16*)bufp; *++argv; words++) { + *wordptr++ = (uint16)strtoul(*argv, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "value %s is not an integer\n", *argv); + return BCME_USAGE_ERROR; + } + if (words > SPROM_WORDS) { + fprintf(stderr, "max of %d words\n", SPROM_WORDS); + return BCME_USAGE_ERROR; + } + } + + bytes = 2 * words; + memcpy(countptr, &bytes, sizeof(int)); + } + } + + if (argc) { + ret = dhd_set(dhd, DHD_SET_VAR, buf, + (strlen("sprom") + 1) + (2 * sizeof(int)) + bytes); + return (ret); + } else { + ret = dhd_get(dhd, DHD_GET_VAR, buf, + (strlen("sprom") + 1) + (2 * sizeof(int)) + bytes); + if (ret < 0) { + return ret; + } + + for (i = 0; i < (int)words; i++) { + if ((i % 8) == 0) + printf("\n srom[%03d]: ", i); + printf("0x%04x ", ((uint16*)buf)[i]); + } + printf("\n"); + } + + return 0; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +/* + * read_vars: reads an environment variables file into a buffer, + * reformatting them and returning the length (-1 on error). + * + * The input text file consists of lines of the form "<var>=<value>\n". + * CRs are ignored, as are blank lines and comments beginning with '#'. + * + * The output buffer consists of blocks of the form "<var>=<value>\0" + * (the newlines have been replaced by NULs) + * + * Todo: allow quoted variable names and quoted values. +*/ + +#if defined(BWL_FILESYSTEM_SUPPORT) +static int +read_vars(char *fname, char *buf, int buf_maxlen) +{ + FILE *fp; + int buf_len, slen; + char line[256], *s, *e; + int line_no = 0; + + if ((fp = fopen(fname, "rb")) == NULL) { + fprintf(stderr, "Cannot open NVRAM file %s: %s\n", + fname, strerror(errno)); + exit(1); + } + + buf_len = 0; + + while (fgets(line, sizeof(line), fp) != NULL) { + bool found_eq = FALSE; + + /* Ensure line length is limited */ + line[sizeof(line) - 1] = 0; + + /* Skip any initial white space */ + for (s = line; *s == ' ' || *s == '\t'; s++) + ; + + /* Determine end of string */ + for (e = s; *e != 0 && *e != '#' && *e != '\r' && *e != '\n'; e++) + if (*e == '=') + found_eq = TRUE; + + /* Strip any white space from end of string */ + while (e > s && (e[-1] == ' ' || e[-1] == '\t')) + e--; + + slen = e - s; + + /* Skip lines that end up blank */ + if (slen == 0) + continue; + + if (!found_eq) { + fprintf(stderr, "Invalid line %d in NVRAM file %s\n", line_no, fname); + fclose(fp); + return -1; + } + + if (buf_len + slen + 1 > buf_maxlen) { + fprintf(stderr, "NVRAM file %s too long\n", fname); + fclose(fp); + return -1; + } + + memcpy(buf + buf_len, s, slen); + buf_len += slen; + buf[buf_len++] = 0; + } + + fclose(fp); + + return buf_len; +} +#endif /* BWL_FILESYSTEM_SUPPORT */ + +static int +dhd_vars(void *dhd, cmd_t *cmd, char **argv) +{ + int ret; + uint argc; + char *bufp; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + switch (argc) { + case 0: /* get */ + { + if ((ret = dhd_var_getbuf(dhd, "vars", NULL, 0, (void**)&bufp))) + break; + while (*bufp) { + printf("%s\n", bufp); + bufp += strlen(bufp) + 1; + } + } + break; + +#if defined(BWL_FILESYSTEM_SUPPORT) + case 1: /* set */ + { + char *vname; + uint nvram_len; + + vname = argv[1]; + + bufp = buf; + strcpy(bufp, "vars"); + bufp += strlen("vars") + 1; + + if ((ret = read_vars(vname, bufp, + DHD_IOCTL_MAXLEN - (strlen("vars") + 3))) < 0) { + ret = -1; + break; + } + + nvram_len = ret; + bufp += nvram_len; + *bufp++ = 0; + + ret = dhd_set(dhd, DHD_SET_VAR, buf, bufp - buf); + } + break; +#endif /* BWL_FILESYSTEM_SUPPORT */ + + default: + ret = -1; + break; + } + + return ret; +} + +#define MEMBLOCK 2048 + +/* Check that strlen("membytes")+1 + 2*sizeof(int32) + MEMBLOCK <= DHD_IOCTL_MAXLEN */ +#if (MEMBLOCK + 17 > DHD_IOCTL_MAXLEN) +#error MEMBLOCK/DHD_IOCTL_MAXLEN sizing +#endif + + +#if defined(BWL_FILESYSTEM_SUPPORT) +static int +dhd_verify_file_bytes(void *dhd, uint8 *memblock, int start, uint len) +{ + int ret = 0; + uint i = 0; + char *ptr; + int params[2]; + uint8 *src, *dst; + + params[0] = start; + params[1] = len; + ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr); + if (ret) { + fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n", + __FUNCTION__, len, start); + return ret; + } + + src = (uint8 *)memblock; + dst = (uint8 *)ptr; + while (i < len) { + if (src[i] != dst[i]) { + fprintf(stderr, " 0x%x: exp[0x%02X] != got[0x%02X]\n", + start+i, src[i], dst[i]); + ret = -1; + } + i++; + } + + return ret; +} + +static int +dhd_load_file_bytes(void *dhd, cmd_t *cmd, FILE *fp, int fsize, int start, uint blk_sz, bool verify) +{ + int tot_len = 0; + uint read_len; + char *bufp; + uint len; + uint8 memblock[MEMBLOCK]; + int ret; + int retry; + + UNUSED_PARAMETER(cmd); + + if (!fsize || !fp) + return -1; + + assert(blk_sz <= MEMBLOCK); + + while (tot_len < fsize) { + read_len = fsize - tot_len; + if (read_len >= blk_sz) { + read_len = blk_sz; + + if (!ISALIGNED(start, MEMBLOCK)) + read_len = ROUNDUP(start, MEMBLOCK) - start; + } + + len = fread(memblock, sizeof(uint8), read_len, fp); + if ((len < read_len) && !feof(fp)) { + fprintf(stderr, "%s: error reading file\n", __FUNCTION__); + return -1; + + } + retry = 0; +failed_retry: + + bufp = buf; + memset(bufp, 0, DHD_IOCTL_MAXLEN); + strcpy(bufp, "membytes"); + bufp += strlen("membytes") + 1; + memcpy(bufp, &start, sizeof(int)); + bufp += sizeof(int); + memcpy(bufp, &len, sizeof(int)); + bufp += sizeof(int); + memcpy(bufp, memblock, len); + + ret = dhd_set(dhd, DHD_SET_VAR, &buf[0], (bufp - buf + len)); + + if (ret) { + fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, ret, len, start); + return ret; + } + + if (verify == TRUE) { + if (dhd_verify_file_bytes(dhd, memblock, start, len) != 0) { + if (retry++ < 5000) + { + fprintf(stderr, "%s: verify failed %d membytes " + "from 0x%08x\n", __FUNCTION__, len, start); + goto failed_retry; + } + } + } + + start += len; + tot_len += len; + } + return 0; +} +#endif /* BWL_FILESYSTEM_SUPPORT */ + +#ifdef QMONITOR +static int +dhd_qtime_thres(void *dhd, cmd_t *cmd, char **argv) +{ + int flag = 0xdead; + + if (argv[1]) { + flag = atoi(argv[1]); + dhd_iovar_setint(dhd, cmd->name, flag); + } + else { + dhd_iovar_getint(dhd, cmd->name, &flag); + printf("qtime_thres: %d\n", flag); + } + return 0; +} + +static int +dhd_qtime_percent(void *dhd, cmd_t *cmd, char **argv) +{ + int flag = 0xdead; + + if (argv[1]) { + flag = atoi(argv[1]); + dhd_iovar_setint(dhd, cmd->name, flag); + } + else { + dhd_iovar_getint(dhd, cmd->name, &flag); + printf("qtime_percent: %d %%\n", flag); + } + return 0; +} +#endif /* QMONITOR */ + + +#ifdef PROP_TXSTATUS +static int +dhd_proptxstatusenable(void *dhd, cmd_t *cmd, char **argv) +{ + int flag = 0xdead; + int ret; + + if (argv[1]) { + flag = atoi(argv[1]); + ret = dhd_iovar_setint(dhd, cmd->name, flag); + } + else { + ret = dhd_iovar_getint(dhd, cmd->name, &flag); + if (ret >= 0) + printf("proptxstatus: %d\n", flag); + } + return ret; +} + +static int +dhd_proptxstatusmode(void *dhd, cmd_t *cmd, char **argv) +{ + int mode = 0xdead; + int ret; + + if (argv[1]) { + mode = atoi(argv[1]); + ret = dhd_iovar_setint(dhd, cmd->name, mode); + } + else { + ret = dhd_iovar_getint(dhd, cmd->name, &mode); + if (ret >= 0) + printf("proptxstatusmode: %d\n", mode); + } + return ret; +} + +static int +dhd_proptxopt(void *dhd, cmd_t *cmd, char **argv) +{ + int flag = 0xdead; + int ret; + + if (argv[1]) { + flag = atoi(argv[1]); + ret = dhd_iovar_setint(dhd, cmd->name, flag); + } + else { + ret = dhd_iovar_getint(dhd, cmd->name, &flag); + if (ret >= 0) + printf("proptx_opt: %d\n", flag); + } + return ret; +} + +#endif /* PROP_TXSTATUS */ + +static int +dhd_get_ramstart(void *dhd, uint32 *ramstart) +{ + int ret; + char *ramstart_args[] = {"ramstart", NULL}; + + /* Read the bus type the DHD driver is associated to */ + if ((ret = dhd_var_get(dhd, NULL, ramstart_args)) != BCME_OK) { + fprintf(stderr, "%s: error obtaining ramstart\n", __FUNCTION__); + + return ret; + } + + *ramstart = *(uint32 *)buf; + + return BCME_OK; +} + +static int +dhd_download(void *dhd, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + return (-1); +#else + bool reset = TRUE; + bool run = TRUE; + bool verify = FALSE; + char *fname = NULL; + char *vname = NULL; + uint32 start; + int ret = 0; + int fsize; + uint32 bustype; + long filepos; + + FILE *fp = NULL; + uint32 ramsize; + char *memszargs[] = { "ramsize", NULL }; + + char *bufp; + + miniopt_t opts; + int opt_err; + uint nvram_len; + struct trx_header trx_hdr; + uint32 trx_hdr_len; + bool trx_file = FALSE; + uint memblock_sz = MEMBLOCK; + bool embedded_ucode = FALSE; + + UNUSED_PARAMETER(cmd); + + if ((ret = dhd_get_ramstart(dhd, &start)) != BCME_OK) + goto exit; + + /* Parse command-line options */ + miniopt_init(&opts, "download", "", TRUE); + + argv++; + while ((opt_err = miniopt(&opts, argv)) != -1) { + if (opt_err == 1) { + fprintf(stderr, "download options error\n"); + ret = -1; + goto exit; + } + argv += opts.consumed; + + if (opts.opt == 'a') { + if (!opts.good_int) { + fprintf(stderr, "invalid address %s\n", opts.valstr); + ret = -1; + goto exit; + } + start = (uint32)opts.uval; + } else if (opts.positional) { + if (fname && vname) { + fprintf(stderr, "extra positional arg, %s\n", + opts.valstr); + ret = -1; + goto exit; + } + if (fname) + vname = opts.valstr; + else + fname = opts.valstr; + } else if (!opts.opt) { + if (!strcmp(opts.key, "noreset")) { + reset = FALSE; + } else if (!strcmp(opts.key, "norun")) { + run = FALSE; + } else if (!strcmp(opts.key, "verify")) { + verify = TRUE; + } else { + fprintf(stderr, "unrecognized option %s\n", opts.valstr); + ret = -1; + goto exit; + } + } else { + fprintf(stderr, "unrecognized option %c\n", opts.opt); + ret = -1; + goto exit; + } + } + + /* validate arguments */ + if (!fname) { + fprintf(stderr, "filename required\n"); + ret = -1; + goto exit; + } + + /* validate file size compared to memory size */ + if ((fsize = file_size(fname)) < 0) { + ret = -1; + goto exit; + } + /* read the file and push blocks down to memory */ + if ((fp = fopen(fname, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open %s: %s\n", + __FUNCTION__, fname, strerror(errno)); + ret = -1; + goto exit; + } + /* Verify the file is a regular bin file or trx file */ + { + uint32 tmp_len; + trx_hdr_len = sizeof(struct trx_header); + tmp_len = fread(&trx_hdr, sizeof(uint8), trx_hdr_len, fp); + if (tmp_len == trx_hdr_len) { + if (trx_hdr.magic == TRX_MAGIC) { + trx_file = TRUE; + if (trx_hdr.flag_version & TRX_EMBED_UCODE) + embedded_ucode = TRUE; + } + else + fseek(fp, 0, SEEK_SET); + } + else + fseek(fp, 0, SEEK_SET); + } + + /* Check on which bus the dhd driver is sitting. Downloading methodology differs from + * USB to SDIO. + */ + { + char* bustype_args[] = {"bustype", NULL}; + + /* Read the bus type the DHD driver is associated to */ + if ((ret = dhd_var_get(dhd, NULL, bustype_args))) { + fprintf(stderr, "%s: error obtaining bustype\n", __FUNCTION__); + goto exit; + } + + bustype = *(uint32*)buf; + } + + if (trx_file) + fsize = (int)(trx_hdr.offsets[0]); + if (bustype == BUS_TYPE_PCIE) { + if ((ret = dhd_var_get(dhd, NULL, memszargs))) { + fprintf(stderr, "%s: error obtaining memsize\n", __FUNCTION__); + goto exit; + } + ramsize = *(uint32*)buf; + } + + if (bustype == BUS_TYPE_SDIO) { + if ((ret = dhd_var_get(dhd, NULL, memszargs))) { + fprintf(stderr, "%s: error obtaining ramsize\n", __FUNCTION__); + goto exit; + } + ramsize = *(uint32*)buf; + } + + + BCM_REFERENCE(ramsize); + + /* do the download reset if not suppressed */ + if (reset) { + if ((ret = dhd_iovar_setint(dhd, "dwnldstate", TRUE))) { + fprintf(stderr, "%s: failed to put dongle in download mode\n", + __FUNCTION__); + goto exit; + } + } + + if (BUS_TYPE_USB == bustype) { + /* store the cur pos pointing to base image which should be written */ + filepos = ftell(fp); + if (filepos == -1) { + fprintf(stderr, "%s: ftell failed.\n", __FUNCTION__); + } + + /* In case of USB, we need to write header information also to dongle. */ + fseek(fp, 0, SEEK_SET); + + /* The file size is "base_image + TRX_Header_size" */ + fsize = (int)(trx_hdr.offsets[0] + sizeof(struct trx_header)); + + memblock_sz = RDL_CHUNK; + } + + + /* Load the ram image */ + if ((ret = dhd_load_file_bytes(dhd, cmd, fp, fsize, start, memblock_sz, verify))) { + fprintf(stderr, "%s: error loading the ramimage at addr 0x%x\n", + __FUNCTION__, start); + goto exit; + } + + if (trx_file) { + + filepos = ftell(fp); + if (filepos == -1) { + fprintf(stderr, "%s: ftell failed.\n", __FUNCTION__); + } + + if (BUS_TYPE_SDIO == bustype) { + + } + } + + fclose(fp); + fp = NULL; + + /* download the vars file if specified */ + if (vname) { + bufp = buf; + strcpy(bufp, "vars"); + bufp += strlen("vars") + 1; + + if ((ret = read_vars(vname, bufp, + DHD_IOCTL_MAXLEN - (strlen("vars") + 3))) < 0) { + ret = -1; + goto exit; + } + + nvram_len = ret; + bufp += nvram_len; + *bufp++ = 0; + + ret = dhd_set(dhd, DHD_SET_VAR, buf, (bufp - buf)); + if (ret) { + fprintf(stderr, "%s: error %d on delivering vars\n", + __FUNCTION__, ret); + goto exit; + } + } + + /* start running the downloaded code if not suppressed */ + if (run) { + if ((ret = dhd_iovar_setint(dhd, "dwnldstate", FALSE))) { + + fprintf(stderr, "%s: failed to take dongle out of download mode\n", + __FUNCTION__); + /* USB Error return values */ + if (BUS_TYPE_USB == bustype) { + if (ret == -1) + fprintf(stderr, "%s: CPU is not in RUNNABLE State\n", + __FUNCTION__); + else + fprintf(stderr, "%s: Error in setting CPU to RUN mode.\n", + __FUNCTION__); + } + goto exit; + } + } + if (embedded_ucode) { + } + +exit: + if (fp) + fclose(fp); + + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +static int +dhd_dldn(void *dhd, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + return (-1); +#else + char *fname = NULL; + uint32 start; + int ret = 0; + int fsize; + int fd = 0; + + FILE *fp = NULL; + uint32 ramsize; + + uint len; + uint8 memblock[MEMBLOCK]; + + miniopt_t opts; + int opt_err; + + UNUSED_PARAMETER(cmd); + + /* Parse command-line options */ + miniopt_init(&opts, "download", "", TRUE); + argv++; + + while ((opt_err = miniopt(&opts, argv)) != -1) { + if (opt_err == 1) { + fprintf(stderr, "download options error\n"); + ret = -1; + goto exit; + } + argv += opts.consumed; + + if (opts.positional) { + if (fname) { + fprintf(stderr, "extra positional arg, %s\n", + opts.valstr); + ret = -1; + goto exit; + } + if (!fname) + fname = opts.valstr; + } else { + fprintf(stderr, "unrecognized option %c\n", opts.opt); + ret = -1; + goto exit; + } + } + + fd = dhd_set(dhd, DHD_DLDN_ST, NULL, 0); + if (fd < 0) { + ret = -1; + goto exit; + } + + /* validate arguments */ + if (!fname) { + fprintf(stderr, "filename required\n"); + ret = -1; + goto exit; + } + + /* validate file size compared to memory size */ + if ((fsize = file_size(fname)) < 0) { + ret = -1; + goto exit; + } + + ramsize = 393216; + + if (ramsize && ((uint32)fsize > ramsize)) { + fprintf(stderr, "%s: file %s too large (%d > %d)\n", + __FUNCTION__, fname, fsize, ramsize); + ret = -1; + goto exit; + } + + /* read the file and push blocks down to memory */ + if ((fp = fopen(fname, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open %s: %s\n", + __FUNCTION__, fname, strerror(errno)); + ret = -1; + goto exit; + } + + if ((ret = dhd_get_ramstart(dhd, &start)) != BCME_OK) + goto exit; + + while ((len = fread(memblock, sizeof(uint8), MEMBLOCK, fp))) { + if (len < MEMBLOCK && !feof(fp)) { + fprintf(stderr, "%s: error reading file %s\n", __FUNCTION__, fname); + ret = -1; + goto exit; + } + + ret = dhd_set(dhd, DHD_DLDN_WRITE, memblock, len); + if (ret) { + fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, ret, len, start); + goto exit; + } + + start += len; + } + + if (!feof(fp)) { + fprintf(stderr, "%s: error reading file %s\n", __FUNCTION__, fname); + ret = -1; + goto exit; + } + fclose(fp); + fp = NULL; + +exit: + if (fp) + fclose(fp); + + if (fd) + ret = dhd_set(dhd, DHD_DLDN_END, NULL, 0); + + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +static int +dhd_upload(void *dhd, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + return (-1); +#else + char *fname = NULL; + uint32 start; + uint32 size = 0; + int ret = 0; + + FILE *fp; + uint32 ramsize; + char *memszargs[] = { "ramsize", NULL }; + + uint len; + + miniopt_t opts; + int opt_err; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + if ((ret = dhd_get_ramstart(dhd, &start)) != BCME_OK) + goto exit; + + /* Parse command-line options */ + miniopt_init(&opts, "upload", "", TRUE); + + argv++; + while ((opt_err = miniopt(&opts, argv)) != -1) { + if (opt_err == 1) { + fprintf(stderr, "upload options error\n"); + ret = -1; + goto exit; + } + argv += opts.consumed; + + if (opts.opt == 'a') { + if (!opts.good_int) { + fprintf(stderr, "invalid address %s\n", opts.valstr); + ret = -1; + goto exit; + } + start = (uint32)opts.uval; + } else if (opts.positional) { + if (!fname) { + fname = opts.valstr; + } else if (opts.good_int) { + size = (uint32)opts.uval; + } else { + fprintf(stderr, "upload options error\n"); + ret = -1; + goto exit; + } + } else if (!opts.opt) { + fprintf(stderr, "unrecognized option %s\n", opts.valstr); + ret = -1; + goto exit; + } else { + fprintf(stderr, "unrecognized option %c\n", opts.opt); + ret = -1; + goto exit; + } + } + + /* validate arguments */ + if (!fname) { + fprintf(stderr, "filename required\n"); + ret = -1; + goto exit; + } + + if ((ret = dhd_var_get(dhd, NULL, memszargs))) { + fprintf(stderr, "%s: error obtaining ramsize\n", __FUNCTION__); + goto exit; + } + ramsize = *(uint32*)buf; + + if (!ramsize) + ramsize = size; + + if ((fp = fopen(fname, "wb")) == NULL) { + fprintf(stderr, "%s: Could not open %s: %s\n", + __FUNCTION__, fname, strerror(errno)); + ret = -1; + goto exit; + } + + /* default size to full RAM */ + if (!size) + size = ramsize; + + /* read memory and write to file */ + while (size) { + char *ptr; + int params[2]; + + len = MIN(MEMBLOCK, size); + + params[0] = start; + params[1] = len; + ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr); + if (ret) { + fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n", + __FUNCTION__, len, start); + break; + } + + if (fwrite(ptr, sizeof(char), len, fp) != len) { + fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname); + ret = -1; + break; + } + + start += len; + size -= len; + } + + fclose(fp); +exit: + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +#ifdef BWL_FILESYSTEM_SUPPORT +static int +dhd_get_debug_info(void *dhd, hndrte_debug_t *debug_info) +{ + int i; + int ret; + int params[2]; + + uint32 *buffer; + uint32 debug_info_ptr; + uint32 ramstart; + + if ((ret = dhd_get_ramstart(dhd, &ramstart)) != BCME_OK) + return ret; + + /* + * Different chips have different fixed debug_info_ptrs + * because of different ROM locations/uses. Try them all looking + * for the magic number. + */ + for (i = 0; ; i++) { + if (debug_info_ptrs[i] == DEBUG_INFO_PTRS_END) { + fprintf(stderr, "Error: cannot find pointer to debug_info\n"); + return -1; + } + + params[0] = debug_info_ptrs[i] + ramstart; + params[1] = 8; + ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&buffer); + if ((ret == 0) && + (*buffer == HNDRTE_DEBUG_PTR_PTR_MAGIC)) { + break; + } + } + + debug_info_ptr = *(buffer + 1); + if (debug_info_ptr == 0) { + fprintf(stderr, "Error: Debug info pointer is zero\n"); + return -1; + } + + /* Read the area the debuginfoptr points at */ + params[0] = debug_info_ptr; + params[1] = sizeof(hndrte_debug_t); + ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&buffer); + if (ret) { + fprintf(stderr, "%s: failed reading %lu membytes from 0x%08lx\n", + __FUNCTION__, (long unsigned) params[1], (long unsigned) params[0]); + return ret; + } + + memcpy((char *) debug_info, buffer, sizeof(hndrte_debug_t)); + + /* Sanity check the area */ + if ((debug_info->magic != HNDRTE_DEBUG_MAGIC) || + (debug_info->version != HNDRTE_DEBUG_VERSION)) { + fprintf(stderr, "Error: Invalid debug info area\n"); + return -1; + } + + return 0; +} +#endif /* BWL_FILESYSTEM_SUPPORT */ + +static int +dhd_coredump(void *dhd, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + return (-1); +#else + char *fname = NULL; + int ret; + + FILE *fp; + + hndrte_debug_t debugInfo; + + miniopt_t opts; + int opt_err; + + int params[2]; + char *ptr; + + unsigned int start; + unsigned int size; + + prstatus_t prstatus; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + /* Parse command-line options */ + miniopt_init(&opts, "dump", "", TRUE); + + argv++; + while ((opt_err = miniopt(&opts, argv)) != -1) { + if (opt_err == 1) { + fprintf(stderr, "dump options error\n"); + ret = -1; + goto exit; + } + argv += opts.consumed; + + if (opts.positional) { + if (!fname) { + fname = opts.valstr; + } else { + fprintf(stderr, "dump options error\n"); + ret = -1; + goto exit; + } + } else if (!opts.opt) { + fprintf(stderr, "unrecognized option %s\n", opts.valstr); + ret = -1; + goto exit; + } else { + fprintf(stderr, "unrecognized option %c\n", opts.opt); + ret = -1; + goto exit; + } + } + + /* validate arguments */ + if (!fname) { + fprintf(stderr, "filename required\n"); + ret = -1; + goto exit; + } + + if ((ret = dhd_get_debug_info(dhd, &debugInfo)) < 0) + goto exit; + + /* Get the base and size to dump */ + start = debugInfo.ram_base; + size = debugInfo.ram_size; + + /* Get the arm trap area */ + bzero(&prstatus, sizeof(prstatus_t)); + if (debugInfo.trap_ptr != 0) { + int i; + trap_t armtrap; + uint32 *reg; + + params[0] = debugInfo.trap_ptr; + params[1] = sizeof(trap_t); + ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr); + if (ret) { + fprintf(stderr, "%s: failed reading %lu membytes from 0x%08lx\n", + __FUNCTION__, (long unsigned) params[1], (long unsigned) params[0]); + goto exit; + } + + memcpy((char *) &armtrap, ptr, sizeof(trap_t)); + + /* Populate the prstatus */ + prstatus.si_signo = armtrap.type; + reg = &armtrap.r0; + for (i = 0; i < 15; i++, reg++) { + prstatus.uregs[i] = *reg; + } + prstatus.uregs[15] = armtrap.epc; + } + + if ((fp = fopen(fname, "wb")) == NULL) { + fprintf(stderr, "%s: Could not open %s: %s\n", + __FUNCTION__, fname, strerror(errno)); + ret = -1; + goto exit; + } + + /* Write the preamble and debug header */ + fprintf(fp, "Dump starts for version %s FWID 01-%x\n", debugInfo.epivers, debugInfo.fwid); + fprintf(fp, "XXXXXXXXXXXXXXXXXXXX"); + fprintf(fp, "%8.8lX", (long unsigned) sizeof(debugInfo)); + if (fwrite(&debugInfo, sizeof(unsigned char), sizeof(debugInfo), fp) != sizeof(debugInfo)) { + fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname); + ret = -1; + fclose(fp); + goto exit; + } + + /* Write the prstatus */ + if (fwrite(&prstatus, sizeof(unsigned char), sizeof(prstatus), fp) != sizeof(prstatus)) { + fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname); + ret = -1; + fclose(fp); + goto exit; + } + + /* Write the ram size as another sanity check */ + fprintf(fp, "%8.8X", size); + + /* read memory and write to file */ + while (size) { + int len; + len = MIN(MEMBLOCK, size); + + params[0] = start; + params[1] = len; + ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr); + if (ret) { + fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n", + __FUNCTION__, len, start); + break; + } + + if (fwrite(ptr, sizeof(char), len, fp) != (uint) len) { + fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname); + ret = -1; + break; + } + + start += len; + size -= len; + } + + fclose(fp); +exit: + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +static int +dhd_consoledump(void *dhd, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + return (-1); +#else + int ret; + + hndrte_debug_t debugInfo; + + miniopt_t opts; + int opt_err; + + int params[2]; + char *ptr; + + unsigned int start; + unsigned int size; + int len; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + /* Parse command-line options */ + miniopt_init(&opts, "consoledump", "", TRUE); + + argv++; + while ((opt_err = miniopt(&opts, argv)) != -1) { + if (opt_err == 1) { + fprintf(stderr, "dump options error\n"); + ret = -1; + goto exit; + } + argv += opts.consumed; + + if (!opts.opt) { + fprintf(stderr, "unrecognized option %s\n", opts.valstr); + ret = -1; + goto exit; + } else { + fprintf(stderr, "unrecognized option %c\n", opts.opt); + ret = -1; + goto exit; + } + } + + if ((ret = dhd_get_debug_info(dhd, &debugInfo)) < 0) + goto exit; + + if (debugInfo.console <= debugInfo.ram_base) { + fprintf(stderr, "%s: console not found\n", __FUNCTION__); + ret = -1; + goto exit; + } + + /* Get the debug console area */ + params[0] = debugInfo.console; + params[1] = sizeof(hndrte_cons_t); + ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr); + if (ret) { + fprintf(stderr, "%s: failed reading %lu membytes from 0x%08lx\n", + __FUNCTION__, (long unsigned) params[1], (long unsigned) params[0]); + goto exit; + } + + if (ptr == NULL) { + fprintf(stderr, "%s: console not initialised\n", __FUNCTION__); + ret = -1; + goto exit; + } + + start = (unsigned int)((hndrte_cons_t *)ptr)->log.buf; + size = ((hndrte_cons_t *)ptr)->log.buf_size; + + if (start <= debugInfo.ram_base) { + fprintf(stderr, "%s: console buffer not initialised\n", __FUNCTION__); + ret = -1; + goto exit; + } + + /* read memory and write to file */ + while (size > 0) { + len = MIN(MEMBLOCK, size); + + params[0] = start; + params[1] = len; + ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr); + if (ret) { + fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n", + __FUNCTION__, len, start); + break; + } + + printf("%s", ptr); + + start += len; + size -= len; + } + +exit: + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +static int +dhd_logstamp(void *dhd, cmd_t *cmd, char **argv) +{ + int ret; + char *endptr = NULL; + uint argc; + int valn[2] = {0, 0}; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; argv++; + + if (argc > 2) + return BCME_USAGE_ERROR; + + if (argc) { + valn[0] = strtol(argv[0], &endptr, 0); + if (*endptr != '\0') { + printf("bad val1: %s\n", argv[0]); + return BCME_USAGE_ERROR; + } + } + + if (argc > 1) { + valn[1] = strtol(argv[1], &endptr, 0); + if (*endptr != '\0') { + printf("bad val2: %s\n", argv[1]); + return BCME_USAGE_ERROR; + } + } + + ret = dhd_var_setbuf(dhd, cmd->name, valn, argc * sizeof(int)); + + return (ret); +} + +static int +dhd_sd_reg(void *dhd, cmd_t *cmd, char **argv) +{ + int ret; + sdreg_t sdreg; + char *endptr = NULL; + uint argc; + void *ptr = NULL; + + bzero(&sdreg, sizeof(sdreg)); + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + /* hostreg: offset [value]; devreg: func offset [value] */ + if (!strcmp(cmd->name, "sd_hostreg")) { + argv++; + if (argc < 1) { + printf("required args: offset [value]\n"); + return BCME_USAGE_ERROR; + } + + } else if (!strcmp(cmd->name, "sd_devreg")) { + argv++; + if (argc < 2) { + printf("required args: func offset [value]\n"); + return BCME_USAGE_ERROR; + } + + sdreg.func = strtoul(*argv++, &endptr, 0); + if (*endptr != '\0') { + printf("Invalid function number\n"); + return BCME_USAGE_ERROR; + } + } else { + return BCME_USAGE_ERROR; + } + + sdreg.offset = strtoul(*argv++, &endptr, 0); + if (*endptr != '\0') { + printf("Invalid offset value\n"); + return BCME_USAGE_ERROR; + } + + /* third arg: value */ + if (*argv) { + sdreg.value = strtoul(*argv, &endptr, 0); + if (*endptr != '\0') { + printf("Invalid value\n"); + return BCME_USAGE_ERROR; + } + } + + /* no third arg means get, otherwise set */ + if (!*argv) { + if ((ret = dhd_var_getbuf(dhd, cmd->name, &sdreg, sizeof(sdreg), &ptr)) >= 0) + printf("0x%x\n", *(int *)ptr); + } else { + ret = dhd_var_setbuf(dhd, cmd->name, &sdreg, sizeof(sdreg)); + } + + return (ret); +} + +static dbg_msg_t dhd_msgs[] = { + {DHD_ERROR_VAL, "error"}, + {DHD_ERROR_VAL, "err"}, + {DHD_TRACE_VAL, "trace"}, + {DHD_INFO_VAL, "inform"}, + {DHD_INFO_VAL, "info"}, + {DHD_INFO_VAL, "inf"}, + {DHD_DATA_VAL, "data"}, + {DHD_CTL_VAL, "ctl"}, + {DHD_TIMER_VAL, "timer"}, + {DHD_HDRS_VAL, "hdrs"}, + {DHD_BYTES_VAL, "bytes"}, + {DHD_INTR_VAL, "intr"}, + {DHD_LOG_VAL, "log"}, + {DHD_GLOM_VAL, "glom"}, + {DHD_EVENT_VAL, "event"}, + {DHD_BTA_VAL, "bta"}, + {DHD_ISCAN_VAL, "iscan"}, + {DHD_ARPOE_VAL, "arpoe"}, + {DHD_REORDER_VAL, "reorder"}, + {0, NULL} +}; + +static int +dhd_msglevel(void *dhd, cmd_t *cmd, char **argv) +{ + return dhd_do_msglevel(dhd, cmd, argv, dhd_msgs); +} + +static int +dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg) +{ + int ret, i; + uint val, last_val = 0, msglevel = 0, msglevel_add = 0, msglevel_del = 0; + char *endptr = NULL; + + if ((ret = dhd_iovar_getint(dhd, cmd->name, (int*)&msglevel)) < 0) + return (ret); + + if (!*++argv) { + printf("0x%x ", msglevel); + for (i = 0; (val = dbg_msg[i].value); i++) { + if ((msglevel & val) && (val != last_val)) + printf(" %s", dbg_msg[i].string); + last_val = val; + } + printf("\n"); + return (0); + } + + while (*argv) { + char *s = *argv; + if (*s == '+' || *s == '-') + s++; + else + msglevel_del = ~0; /* make the whole list absolute */ + val = strtoul(s, &endptr, 0); + /* not a plain integer if not all the string was parsed by strtoul */ + if (*endptr != '\0') { + for (i = 0; (val = dbg_msg[i].value); i++) + if (stricmp(dbg_msg[i].string, s) == 0) + break; + if (!val) + goto usage; + } + if (**argv == '-') + msglevel_del |= val; + else + msglevel_add |= val; + ++argv; + } + + msglevel &= ~msglevel_del; + msglevel |= msglevel_add; + + return (dhd_iovar_setint(dhd, cmd->name, msglevel)); + +usage: + fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n"); + fprintf(stderr, "Use a + or - prefix to make an incremental change."); + + for (i = 0; (val = dbg_msg[i].value); i++) { + if (val != last_val) + fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string); + else + fprintf(stderr, ", %s", dbg_msg[i].string); + last_val = val; + } + fprintf(stderr, "\n"); + + return 0; +} + +static char * +ver2str(unsigned int vms, unsigned int vls) +{ + static char verstr[100]; + unsigned int maj, year, month, day, build; + + maj = (vms >> 16) & 0xFFFF; + if (maj > 1000) { + /* it is probably a date... */ + year = (vms >> 16) & 0xFFFF; + month = vms & 0xFFFF; + day = (vls >> 16) & 0xFFFF; + build = vls & 0xFFFF; + sprintf(verstr, "%d/%d/%d build %d", + month, day, year, build); + } else { + /* it is a tagged release. */ + sprintf(verstr, "%d.%d RC%d.%d", + (vms>>16)&0xFFFF, vms&0xFFFF, + (vls>>16)&0xFFFF, vls&0xFFFF); + } + return verstr; +} + +static int +dhd_version(void *dhd, cmd_t *cmd, char **argv) +{ + int ret; + char *ptr; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + /* Display the application version info */ + printf("%s: %s\n", dhdu_av0, + ver2str((EPI_MAJOR_VERSION << 16)| EPI_MINOR_VERSION, + (EPI_RC_NUMBER << 16) | EPI_INCREMENTAL_NUMBER)); + + if ((ret = dhd_var_getbuf(dhd, cmd->name, NULL, 0, (void**)&ptr)) < 0) + return ret; + + /* Display the returned string */ + printf("%s\n", ptr); + + return 0; +} + +static int +dhd_var_setint(void *dhd, cmd_t *cmd, char **argv) +{ + int32 val; + int len; + char *varname; + char *endptr = NULL; + char *p; + + if (cmd->set == -1) { + printf("set not defined for %s\n", cmd->name); + return BCME_ERROR; + } + + if (!*argv) { + printf("set: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + varname = *argv++; + + if (!*argv) { + printf("set: missing value argument for set of \"%s\"\n", varname); + return BCME_USAGE_ERROR; + } + + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n", + *argv, varname); + return BCME_USAGE_ERROR; + } + + strcpy(buf, varname); + p = buf; + while (*p != '\0') { + *p = tolower(*p); + p++; + } + + /* skip the NUL */ + p++; + + memcpy(p, &val, sizeof(uint)); + len = (p - buf) + sizeof(uint); + + return (dhd_set(dhd, DHD_SET_VAR, &buf[0], len)); +} + +static int +dhd_var_get(void *dhd, cmd_t *cmd, char **argv) +{ + char *varname; + char *p; + + UNUSED_PARAMETER(cmd); + + if (!*argv) { + printf("get: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + varname = *argv++; + + if (*argv) { + printf("get: error, extra arg \"%s\"\n", *argv); + return BCME_USAGE_ERROR; + } + + strcpy(buf, varname); + p = buf; + while (*p != '\0') { + *p = tolower(*p); + p++; + } + return (dhd_get(dhd, DHD_GET_VAR, &buf[0], DHD_IOCTL_MAXLEN)); +} + +static int +dhd_var_getint(void *dhd, cmd_t *cmd, char **argv) +{ + int err; + int32 val; + if (cmd->get == -1) { + printf("get not defined for %s\n", cmd->name); + return BCME_ERROR; + } + + if ((err = dhd_var_get(dhd, cmd, argv))) + return (err); + + val = *(int32*)buf; + + if (val < 10) + printf("%d\n", val); + else + printf("%d (0x%x)\n", val, val); + + return (0); +} + +static int +dhd_var_getandprintstr(void *dhd, cmd_t *cmd, char **argv) +{ + int err; + + if ((err = dhd_var_get(dhd, cmd, argv))) + return (err); + + printf("%s\n", buf); + return (0); +} + + +void +dhd_printlasterror(void *dhd) +{ + char *cmd[2] = {"bcmerrorstr"}; + + if (dhd_var_get(dhd, NULL, cmd) != 0) { + fprintf(stderr, "%s: \nError getting the last error\n", dhdu_av0); + } else { + fprintf(stderr, "%s: %s\n", dhdu_av0, buf); + } +} + +static int +dhd_varint(void *dhd, cmd_t *cmd, char *argv[]) +{ + if (argv[1]) + return (dhd_var_setint(dhd, cmd, argv)); + else + return (dhd_var_getint(dhd, cmd, argv)); +} + +static int +dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr) +{ + int len; + + memset(buf, 0, DHD_IOCTL_MAXLEN); + strcpy(buf, iovar); + + /* include the NUL */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&buf[len], param, param_len); + + *bufptr = buf; + + return dhd_get(dhd, DHD_GET_VAR, &buf[0], DHD_IOCTL_MAXLEN); +} + +static int +dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len) +{ + int len; + + memset(buf, 0, DHD_IOCTL_MAXLEN); + strcpy(buf, iovar); + + /* include the NUL */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&buf[len], param, param_len); + + len += param_len; + + return dhd_set(dhd, DHD_SET_VAR, &buf[0], len); +} + +static int +dhd_var_void(void *dhd, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(argv); + + if (cmd->set < 0) + return BCME_ERROR; + + return dhd_var_setbuf(dhd, cmd->name, NULL, 0); +} + +/* + * format an iovar buffer + */ +static uint +dhd_iovar_mkbuf(char *name, char *data, uint datalen, char *buf, uint buflen, int *perr) +{ + uint len; + + len = strlen(name) + 1; + + /* check for overflow */ + if ((len + datalen) > buflen) { + *perr = BCME_BUFTOOSHORT; + return 0; + } + + strcpy(buf, name); + + /* append data onto the end of the name string */ + if (datalen > 0) + memcpy(&buf[len], data, datalen); + + len += datalen; + + *perr = 0; + return len; +} + +static int +dhd_iovar_getint(void *dhd, char *name, int *var) +{ + char ibuf[DHD_IOCTL_SMLEN]; + int error; + + dhd_iovar_mkbuf(name, NULL, 0, ibuf, sizeof(ibuf), &error); + if (error) + return error; + + if ((error = dhd_get(dhd, DHD_GET_VAR, &ibuf, sizeof(ibuf))) < 0) + return error; + + memcpy(var, ibuf, sizeof(int)); + + return 0; +} + +static int +dhd_iovar_setint(void *dhd, char *name, int var) +{ + int len; + char ibuf[DHD_IOCTL_SMLEN]; + int error; + + len = dhd_iovar_mkbuf(name, (char *)&var, sizeof(var), ibuf, sizeof(ibuf), &error); + if (error) + return error; + + if ((error = dhd_set(dhd, DHD_SET_VAR, &ibuf, len)) < 0) + return error; + + return 0; +} + +static int +dhd_varstr(void *dhd, cmd_t *cmd, char **argv) +{ + int error; + char *str; + + if (!*++argv) { + void *ptr; + + if ((error = dhd_var_getbuf(dhd, cmd->name, NULL, 0, &ptr)) < 0) + return (error); + + str = (char *)ptr; + printf("%s\n", str); + return (0); + } else { + str = *argv; + /* iovar buffer length includes NUL */ + return dhd_var_setbuf(dhd, cmd->name, str, strlen(str) + 1); + } +} + + +static int +dhd_hostreorder_flows(void *dhd, cmd_t *cmd, char **argv) +{ + int ret, count, i = 0; + void *ptr; + uint8 *flow_id; + + + if ((ret = dhd_var_getbuf(dhd, cmd->name, NULL, 0, &ptr)) < 0) { + printf("error getting reorder flows from the host\n"); + return ret; + } + flow_id = (uint8 *)ptr; + count = *flow_id; + if (!count) + printf("there are no active flows\n"); + else { + printf("flows(%d): \t", count); + while (i++ < count) + printf("%d ", *flow_id++); + printf("\n"); + } + return 0; +} + +#ifdef BCMSPI +static int +dhd_spierrstats(void *dhd, cmd_t *cmd, char **argv) +{ + int ret, i; + struct spierrstats_t spierrstats, *p; + uint argc; + void *ptr = NULL; + + bzero(&spierrstats, sizeof(spierrstats)); + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (strcmp(cmd->name, "spi_errstats")) { + printf("Supported only for SPI. Required cmd name missing\n"); + return BCME_USAGE_ERROR; + } + + /* Check 3rd argument */ + argv++; + + /* no third arg means get, otherwise set */ + if (!*argv) { + if ((ret = dhd_var_getbuf(dhd, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + p = (struct spierrstats_t *)ptr; + + printf("Last %d device-status-bits\n", NUM_PREV_TRANSACTIONS); + + for (i = 0; i < NUM_PREV_TRANSACTIONS; i++) + printf("dstatus[%d] = 0x%x, spicmd[%d] = 0x%x\n", i, p->dstatus[i], + i, p->spicmd[i]); + + printf("The requested data was not available = %d\n", + p->dna); + printf("FIFO underflow happened due to F2 rd command = %d\n", + p->rdunderflow); + printf("FIFO overflow happened due to F1/F2 wr command = %d\n", + p->wroverflow); + printf("F2 interrupt (OR of all F2 related intr status bits) = %d\n", + p->f2interrupt); + printf("F2 FIFO is not ready to receive data = %d\n", + p->f2rxnotready); + printf("Error in command or host data, detected by checksum = %d\n", + p->hostcmddataerr); + printf("Packet is available in F2 TX FIFO = %d\n", + p->f2pktavailable); + + } else { + ret = dhd_var_setbuf(dhd, cmd->name, &spierrstats, sizeof(spierrstats)); + } + + return (ret); +} +#endif /* BCMSPI */ + +#ifdef WLBTAMP + +#define MATCH_OP(op, opstr) (strlen(op) == strlen(opstr) && strncmp(op, opstr, strlen(op)) == 0) + +static int +wl_HCI_cmd(void *wl, cmd_t *cmd, char **argv) +{ + union { + char buf[HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE]; + uint32 alignme; + } cbuf; + amp_hci_cmd_t *cpkt = (amp_hci_cmd_t *)&cbuf.buf[0]; + + char *op; + uint8 plen; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) + return BCME_USAGE_ERROR; + + /* recognize and encode operations */ + op = *argv++; + if (MATCH_OP(op, "Read_Link_Quality")) { + cpkt->opcode = HCI_Read_Link_Quality; + } else if (MATCH_OP(op, "Read_Local_AMP_Info")) { + cpkt->opcode = HCI_Read_Local_AMP_Info; + } else if (MATCH_OP(op, "Read_Local_AMP_ASSOC")) { + cpkt->opcode = HCI_Read_Local_AMP_ASSOC; + } else if (MATCH_OP(op, "Write_Remote_AMP_ASSOC")) { + cpkt->opcode = HCI_Write_Remote_AMP_ASSOC; + } else if (MATCH_OP(op, "Create_Physical_Link")) { + cpkt->opcode = HCI_Create_Physical_Link; + } else if (MATCH_OP(op, "Accept_Physical_Link_Request")) { + cpkt->opcode = HCI_Accept_Physical_Link_Request; + } else if (MATCH_OP(op, "Disconnect_Physical_Link")) { + cpkt->opcode = HCI_Disconnect_Physical_Link; + } else if (MATCH_OP(op, "Create_Logical_Link")) { + cpkt->opcode = HCI_Create_Logical_Link; + } else if (MATCH_OP(op, "Accept_Logical_Link")) { + cpkt->opcode = HCI_Accept_Logical_Link; + } else if (MATCH_OP(op, "Disconnect_Logical_Link")) { + cpkt->opcode = HCI_Disconnect_Logical_Link; + } else if (MATCH_OP(op, "Logical_Link_Cancel")) { + cpkt->opcode = HCI_Logical_Link_Cancel; + } else if (MATCH_OP(op, "Short_Range_Mode")) { + cpkt->opcode = HCI_Short_Range_Mode; + } else if (MATCH_OP(op, "Read_Connection_Accept_Timeout")) { + cpkt->opcode = HCI_Read_Connection_Accept_Timeout; + } else if (MATCH_OP(op, "Write_Connection_Accept_Timeout")) { + cpkt->opcode = HCI_Write_Connection_Accept_Timeout; + } else if (MATCH_OP(op, "Read_Link_Supervision_Timeout")) { + cpkt->opcode = HCI_Read_Link_Supervision_Timeout; + } else if (MATCH_OP(op, "Write_Link_Supervision_Timeout")) { + cpkt->opcode = HCI_Write_Link_Supervision_Timeout; + } else if (MATCH_OP(op, "Reset")) { + cpkt->opcode = HCI_Reset; + } else if (MATCH_OP(op, "Enhanced_Flush")) { + cpkt->opcode = HCI_Enhanced_Flush; + } else if (MATCH_OP(op, "Read_Best_Effort_Flush_Timeout")) { + cpkt->opcode = HCI_Read_Best_Effort_Flush_Timeout; + } else if (MATCH_OP(op, "Write_Best_Effort_Flush_Timeout")) { + cpkt->opcode = HCI_Write_Best_Effort_Flush_Timeout; + } else if (MATCH_OP(op, "Read_Logical_Link_Accept_Timeout")) { + cpkt->opcode = HCI_Read_Logical_Link_Accept_Timeout; + } else if (MATCH_OP(op, "Write_Logical_Link_Accept_Timeout")) { + cpkt->opcode = HCI_Write_Logical_Link_Accept_Timeout; + } else if (MATCH_OP(op, "Read_Buffer_Size")) { + cpkt->opcode = HCI_Read_Buffer_Size; + } else if (MATCH_OP(op, "Read_Data_Block_Size")) { + cpkt->opcode = HCI_Read_Data_Block_Size; + } else if (MATCH_OP(op, "Set_Event_Mask_Page_2")) { + cpkt->opcode = HCI_Set_Event_Mask_Page_2; + } else if (MATCH_OP(op, "Flow_Spec_Modify")) { + cpkt->opcode = HCI_Flow_Spec_Modify; + } else if (MATCH_OP(op, "Read_Local_Version_Info")) { + cpkt->opcode = HCI_Read_Local_Version_Info; + } else if (MATCH_OP(op, "Read_Local_Supported_Commands")) { + cpkt->opcode = HCI_Read_Local_Supported_Commands; + } else if (MATCH_OP(op, "Read_Failed_Contact_Counter")) { + cpkt->opcode = HCI_Read_Failed_Contact_Counter; + } else if (MATCH_OP(op, "Reset_Failed_Contact_Counter")) { + cpkt->opcode = HCI_Reset_Failed_Contact_Counter; + } else { + printf("unsupported HCI command: %s\n", op); + return (-1); + } + + plen = 0; + while (*argv && (plen < HCI_CMD_DATA_SIZE)) { + cpkt->parms[plen++] = (uint8)strtol(*argv++, NULL, 0); + } + cpkt->plen = plen; + + return dhd_var_setbuf(wl, cmd->name, cpkt, HCI_CMD_PREAMBLE_SIZE + plen); +} + +typedef union { + uint8 buf[HCI_ACL_DATA_PREAMBLE_SIZE + 2048]; + uint32 alignme; +} g_hci_dbuf_t; + +static int +wl_HCI_ACL_data(void *wl, cmd_t *cmd, char **argv) +{ + /* Align struct. Also declare static so that large array isn't allocated + * from the stack. + */ + static g_hci_dbuf_t g_hci_dbuf; + + amp_hci_ACL_data_t *dpkt = (amp_hci_ACL_data_t *)&g_hci_dbuf.buf[0]; + uint16 dlen; + + if (!*++argv) + return BCME_USAGE_ERROR; + + /* get logical link handle */ + dpkt->handle = (HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS); + dpkt->handle |= (uint16)strtol(*argv++, NULL, 0); + + /* get data */ + dlen = 0; + while (*argv && (dlen < 2048)) { + dpkt->data[dlen++] = (uint8)strtol(*argv++, NULL, 0); + } + dpkt->dlen = dlen; + + return dhd_var_setbuf(wl, cmd->name, dpkt, HCI_ACL_DATA_PREAMBLE_SIZE + dlen); +} +#endif /* WLBTAMP */ + +/* These two utility functions are used by dhdu_linux.c + * The code is taken from wlu.c. + */ +int +dhd_atoip(const char *a, struct ipv4_addr *n) +{ + char *c; + int i = 0; + + for (;;) { + n->addr[i++] = (uint8)strtoul(a, &c, 0); + if (*c++ != '.' || i == IPV4_ADDR_LEN) + break; + a = c; + } + return (i == IPV4_ADDR_LEN); +} + +int +dhd_ether_atoe(const char *a, struct ether_addr *n) +{ + char *c; + int i = 0; + + memset(n, 0, ETHER_ADDR_LEN); + for (;;) { + n->octet[i++] = (uint8)strtoul(a, &c, 16); + if (!*c++ || i == ETHER_ADDR_LEN) + break; + a = c; + } + return (i == ETHER_ADDR_LEN); +}
diff --git a/src/dhd/exe/dhdu.h b/src/dhd/exe/dhdu.h new file mode 100644 index 0000000..6718c10 --- /dev/null +++ b/src/dhd/exe/dhdu.h
@@ -0,0 +1,47 @@ +/* + * Definitions for DHD command-line utility + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: dhdu.h 379386 2013-01-17 07:20:55Z $ + */ + +#ifndef _dhdu_h_ +#define _dhdu_h_ + +#include "dhdu_cmd.h" + +extern char *dhdu_av0; + +/* parse common option */ +extern int dhd_option(char ***pargv, char **pifname, int *phelp); +extern void dhd_cmd_init(void); + +/* print usage */ +extern void dhd_cmd_usage(cmd_t *cmd); +extern void dhd_usage(cmd_t *port_cmds); +extern void dhd_cmds_usage(cmd_t *port_cmds); + +/* print helpers */ +extern void dhd_printlasterror(void *dhd); +extern void dhd_printint(int val); + +/* check driver version */ +extern int dhd_check(void *dhd); + +/* utility functions */ +struct ipv4_addr; +int dhd_ether_atoe(const char *a, struct ether_addr *n); +int dhd_atoip(const char *a, struct ipv4_addr *n); + +/* integer output format */ +#define INT_FMT_DEC 0 /* signed integer */ +#define INT_FMT_UINT 1 /* unsigned integer */ +#define INT_FMT_HEX 2 /* hexdecimal */ + +/* command line argument usage */ +#define CMD_ERR -1 /* Error for command */ +#define CMD_OPT 0 /* a command line option */ +#define CMD_DHD 1 /* the start of a dhd command */ + +#endif /* _dhdu_h_ */
diff --git a/src/dhd/exe/dhdu_cmd.h b/src/dhd/exe/dhdu_cmd.h new file mode 100644 index 0000000..e7f9a3e --- /dev/null +++ b/src/dhd/exe/dhdu_cmd.h
@@ -0,0 +1,37 @@ +/* + * Command structure for dhd command line utility, copied from wl utility + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: dhdu_cmd.h 241182 2011-02-17 21:50:03Z $ + */ + +#ifndef _dhdu_cmd_h_ +#define _dhdu_cmd_h_ + +typedef struct cmd cmd_t; +typedef int (cmd_func_t)(void *dhd, cmd_t *cmd, char **argv); + +/* generic command line argument handler */ +struct cmd { + char *name; + cmd_func_t *func; + int get; + int set; + char *help; +}; + +/* list of command line arguments */ +extern cmd_t dhd_cmds[]; +extern cmd_t dhd_varcmd; + +/* Special set cmds to do download via dev node interface if present */ +#define DHD_DLDN_ST 0x400 +#define DHD_DLDN_WRITE (DHD_DLDN_ST + 1) +#define DHD_DLDN_END (DHD_DLDN_ST + 2) + +/* per-port ioctl handlers */ +extern int dhd_get(void *dhd, int cmd, void *buf, int len); +extern int dhd_set(void *dhd, int cmd, void *buf, int len); + +#endif /* _dhdu_cmd_h_ */
diff --git a/src/dhd/exe/dhdu_common.h b/src/dhd/exe/dhdu_common.h new file mode 100644 index 0000000..8464b3c --- /dev/null +++ b/src/dhd/exe/dhdu_common.h
@@ -0,0 +1,83 @@ +/* + * Linux port of dhd command line utility, hacked from wl utility. + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: dhdu_common.h 379386 2013-01-17 07:20:55Z $ + */ + +/* Common header file for dhdu_linux.c and dhdu_ndis.c */ + +#ifndef _dhdu_common_h +#define _dhdu_common_h + +#if !defined(RWL_WIFI) && !defined(RWL_DONGLE) && !defined(RWL_SOCKET) && \ + !defined(RWL_SERIAL) + +#define NO_REMOTE 0 +#define REMOTE_SERIAL 1 +#define REMOTE_SOCKET 2 +#define REMOTE_WIFI 3 +#define REMOTE_DONGLE 4 + +/* For cross OS support */ +#define LINUX_OS 1 +#define WIN32_OS 2 +#define MAC_OSX 3 +#define BACKLOG 4 +#define WINVISTA_OS 5 +#define INDONGLE 6 + +#define RWL_WIFI_ACTION_CMD "wifiaction" +#define RWL_WIFI_GET_ACTION_CMD "rwlwifivsaction" +#define RWL_DONGLE_SET_CMD "dongleset" + +#define SUCCESS 1 +#define FAIL -1 +#define NO_PACKET -2 + +/* Added for debug utility support */ +#define ERR stderr +#define OUTPUT stdout +#define DEBUG_ERR 0x0001 +#define DEBUG_INFO 0x0002 +#define DEBUG_DBG 0x0004 + +#define DPRINT_ERR if (defined_debug & DEBUG_ERR) \ + fprintf +#define DPRINT_INFO if (defined_debug & DEBUG_INFO) \ + fprintf +#define DPRINT_DBG if (defined_debug & DEBUG_DBG) \ + fprintf + +extern int wl_get(void *wl, int cmd, void *buf, int len); +extern int wl_set(void *wl, int cmd, void *buf, int len); +#endif /* !RWL_WIFI & !RWL_DONGLE & !RWL_SOCKET & !RWL_SERIAL */ + +/* DHD utility function declarations */ +extern int dhd_check(void *dhd); +extern int dhd_atoip(const char *a, struct ipv4_addr *n); +extern int dhd_option(char ***pargv, char **pifname, int *phelp); +void dhd_usage(cmd_t *port_cmds); + +/* Remote DHD declarations */ +int remote_type = NO_REMOTE; +extern char *g_rwl_buf_mac; +extern char* g_rwl_device_name_serial; +unsigned short g_rwl_servport; +char *g_rwl_servIP = NULL; +unsigned short defined_debug = DEBUG_ERR | DEBUG_INFO; + + +static int process_args(struct ifreq* ifr, char **argv); + +#define dtoh32(i) i +#define dtoh16(i) i + +#endif /* _dhdu_common_h_ */
diff --git a/src/dhd/exe/dhdu_linux.c b/src/dhd/exe/dhdu_linux.c new file mode 100644 index 0000000..d64c609 --- /dev/null +++ b/src/dhd/exe/dhdu_linux.c
@@ -0,0 +1,721 @@ +/* + * Linux port of dhd command line utility, hacked from wl utility. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: dhdu_linux.c 454520 2014-02-11 01:37:22Z $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <proto/ethernet.h> +#include <proto/bcmip.h> +#include <arpa/inet.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#ifndef TARGETENV_android +#include <error.h> +typedef u_int64_t u64; +typedef u_int32_t u32; +typedef u_int16_t u16; +typedef u_int8_t u8; +#endif /* TARGETENV_android */ +#include <linux/sockios.h> +#include <linux/types.h> +#include <linux/ethtool.h> + +#include <typedefs.h> +#include <signal.h> +#include <dhdioctl.h> +#include <wlioctl.h> +#include <bcmcdc.h> +#include <bcmutils.h> + +#if defined(RWL_WIFI) || defined(RWL_DONGLE) || defined(RWL_SOCKET) \ + ||defined(RWL_SERIAL) +#define RWL_ENABLE +#endif /* RWL_WIFI | RWL_DONGLE | RWL_SOCKET | RWL_SERIAL */ + +#include "dhdu.h" +#ifdef RWL_ENABLE +#include "wlu_remote.h" +#include "wlu_client_shared.h" +#include "wlu_pipe.h" +#endif /* RWL_ENABLE */ +#include <netdb.h> +#include <netinet/in.h> +#include <dhdioctl.h> +#include "dhdu_common.h" +#include "dhdu_nl80211.h" + +char *av0; +static int rwl_os_type = LINUX_OS; +/* Search the dhd_cmds table for a matching command name. + * Return the matching command or NULL if no match found. + */ +static cmd_t * +dhd_find_cmd(char* name) +{ + cmd_t *cmd = NULL; + /* search the dhd_cmds for a matching name */ + for (cmd = dhd_cmds; cmd->name && strcmp(cmd->name, name); cmd++); + if (cmd->name == NULL) + cmd = NULL; + return cmd; +} + +#ifdef NL80211 +static void +syserr(const char *s) +{ +} + +static int __dhd_drvio_nltestmode(void *dhd, dhd_ioctl_t *ioc) +{ + struct dhd_netlink_info dhd_nli; + struct ifreq *ifr = (struct ifreq *)dhd; + int ret = 0; + + dhd_nli.ifidx = if_nametoindex(ifr->ifr_name); + if (!dhd_nli.ifidx) { + fprintf(stderr, "invalid device %s\n", ifr->ifr_name); + return BCME_IOCTL_ERROR; + } + + if (dhd_nl_sock_connect(&dhd_nli) < 0) { + fprintf(stderr, "%s: ", av0); + perror("socket"); + exit(errno); + } + + ret = dhd_nl_do_testmode(&dhd_nli, ioc); + dhd_nl_sock_disconnect(&dhd_nli); + return ret; +} +#else +static void +syserr(const char *s) +{ + fprintf(stderr, "%s: ", av0); + perror(s); + exit(errno); +} + +static int __dhd_drvio_nltestmode(void *dhd, dhd_ioctl_t *ioc) +{ + return BCME_IOCTL_ERROR; +} +#endif /* NL80211 */ +static int __dhd_drvio_ioctl(void *dhd, dhd_ioctl_t *ioc) +{ + struct ifreq *ifr = (struct ifreq *)dhd; + int s; + int ret = 0; + + /* pass ioctl data */ + ifr->ifr_data = (caddr_t)ioc; + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + syserr("socket"); + + ret = ioctl(s, SIOCDEVPRIVATE, ifr); + if (ret < 0 && errno != EAGAIN) + syserr(__FUNCTION__); + + /* cleanup */ + close(s); + return ret; +} + +static int (*g_dhd_driver_io)(void *dhd, dhd_ioctl_t *ioc) = __dhd_drvio_ioctl; +/* This function is called by ioctl_setinformation_fe or ioctl_queryinformation_fe + * for executing remote commands or local commands + */ +static int +dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set) +{ + dhd_ioctl_t ioc; + int ret = 0; + + /* By default try to execute wl commands */ + int driver_magic = WLC_IOCTL_MAGIC; + int get_magic = WLC_GET_MAGIC; + + /* For local dhd commands execute dhd. For wifi transport we still + * execute wl commands. + */ + if (remote_type == NO_REMOTE && strncmp (buf, RWL_WIFI_ACTION_CMD, + strlen(RWL_WIFI_ACTION_CMD)) && strncmp(buf, RWL_WIFI_GET_ACTION_CMD, + strlen(RWL_WIFI_GET_ACTION_CMD))) { + driver_magic = DHD_IOCTL_MAGIC; + get_magic = DHD_GET_MAGIC; + } + + /* do it */ + ioc.cmd = cmd; + ioc.buf = buf; + ioc.len = len; + ioc.set = set; + ioc.driver = driver_magic; + + ret = g_dhd_driver_io(dhd, &ioc); + if (ret < 0) { + if (g_dhd_driver_io == __dhd_drvio_ioctl) { + /* try using nl80211 testmode interface */ + ret = __dhd_drvio_nltestmode(dhd, &ioc); + if (ret >= 0) { + g_dhd_driver_io = __dhd_drvio_nltestmode; + goto exit; + } + } + if (cmd != get_magic) + ret = BCME_IOCTL_ERROR; + } + +exit: + return ret; +} + +/* This function is called in wlu_pipe.c remote_wifi_ser_init() to execute + * the initial set of wl commands for wifi transport (e.g slow_timer, fast_timer etc) + */ +int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set) +{ + return dhd_ioctl(wl, cmd, buf, len, set); /* Call actual wl_ioctl here: Shubhro */ +} + +/* Search if dhd adapter or wl adapter is present + * This is called by dhd_find to check if it supports wl or dhd + * The reason for checking wl adapter is that we can still send remote dhd commands over + * wifi transport. + */ +static int +dhd_get_dev_type(char *name, void *buf, char *type) +{ + int s; + int ret; + struct ifreq ifr; + struct ethtool_drvinfo info; + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + syserr("socket"); + + /* get device type */ + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GDRVINFO; + strcpy(info.driver, "?"); + strcat(info.driver, type); + ifr.ifr_data = (caddr_t)&info; + strncpy(ifr.ifr_name, name, IFNAMSIZ); + if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) { + + if (errno != EAGAIN) + syserr(__FUNCTION__); + + *(char *)buf = '\0'; + } + else + strcpy(buf, info.driver); + + close(s); + return ret; +} + +/* dhd_get/dhd_set is called by several functions in dhdu.c. This used to call dhd_ioctl + * directly. However now we need to execute the dhd commands remotely. + * So we make use of wl pipes to execute this. + * wl_get or wl_set functions also check if it is a local command hence they in turn + * call dhd_ioctl if required. Name wl_get/wl_set is retained because these functions are + * also called by wlu_pipe.c wlu_client_shared.c + */ +int +dhd_get(void *dhd, int cmd, void *buf, int len) +{ + return wl_get(dhd, cmd, buf, len); +} + +/* + * To use /dev/node interface: + * 1. mknod /dev/hnd0 c 248 0 + * 2. chmod 777 /dev/hnd0 + */ +#define NODE "/dev/hnd0" + +int +dhd_set(void *dhd, int cmd, void *buf, int len) +{ + static int dnode = -1; + + switch (cmd) { + case DHD_DLDN_ST: + if (dnode == -1) + dnode = open(NODE, O_RDWR); + else + fprintf(stderr, "devnode already opened!\n"); + + return dnode; + break; + case DHD_DLDN_WRITE: + if (dnode > 0) + return write(dnode, buf, len); + break; + case DHD_DLDN_END: + if (dnode > 0) + return close(dnode); + break; + default: + return wl_set(dhd, cmd, buf, len); + + } + + return -1; +} + +/* Verify the wl adapter found. + * This is called by dhd_find to check if it supports wl + * The reason for checking wl adapter is that we can still send remote dhd commands over + * wifi transport. The function is copied from wlu.c. + */ +int +wl_check(void *wl) +{ + int ret; + int val = 0; + + if (!dhd_check (wl)) + return 0; + + /* + * If dhd_check() fails then go for a regular wl driver verification + */ + if ((ret = wl_get(wl, WLC_GET_MAGIC, &val, sizeof(int))) < 0) + return ret; + if (val != WLC_IOCTL_MAGIC) + return BCME_ERROR; + if ((ret = wl_get(wl, WLC_GET_VERSION, &val, sizeof(int))) < 0) + return ret; + if (val > WLC_IOCTL_VERSION) { + fprintf(stderr, "Version mismatch, please upgrade\n"); + return BCME_ERROR; + } + return 0; +} +/* Search and verify the request type of adapter (wl or dhd) + * This is called by main before executing local dhd commands + * or sending remote dhd commands over wifi transport + */ +void +dhd_find(struct ifreq *ifr, char *type) +{ + char proc_net_dev[] = "/proc/net/dev"; + FILE *fp = NULL; + static char buf[400]; + char *c, *name; + char dev_type[32]; + + ifr->ifr_name[0] = '\0'; + /* eat first two lines */ + if (!(fp = fopen(proc_net_dev, "r")) || + !fgets(buf, sizeof(buf), fp) || + !fgets(buf, sizeof(buf), fp)) + goto exit; + + while (fgets(buf, sizeof(buf), fp)) { + c = buf; + while (isspace(*c)) + c++; + if (!(name = strsep(&c, ":"))) + continue; + strncpy(ifr->ifr_name, name, IFNAMSIZ); + if (dhd_get_dev_type(name, dev_type, type) >= 0 && + !strncmp(dev_type, type, strlen(dev_type) - 1)) + { + if (!wl_check((void*)ifr)) + break; + } + ifr->ifr_name[0] = '\0'; + } + +exit: + if (fp) + fclose(fp); +} +/* This function is called by wl_get to execute either local dhd command + * or send a dhd command over wl transport + */ +static int +ioctl_queryinformation_fe(void *wl, int cmd, void* input_buf, int *input_len) +{ + if (remote_type == NO_REMOTE) { + return dhd_ioctl(wl, cmd, input_buf, *input_len, FALSE); + } +#ifdef RWL_ENABLE + else { + return rwl_queryinformation_fe(wl, cmd, input_buf, + (unsigned long*)input_len, 0, RDHD_GET_IOCTL); + } +#else /* RWL_ENABLE */ + return BCME_IOCTL_ERROR; +#endif /* RWL_ENABLE */ +} + +/* This function is called by wl_set to execute either local dhd command + * or send a dhd command over wl transport + */ +static int +ioctl_setinformation_fe(void *wl, int cmd, void* buf, int *len) +{ + if (remote_type == NO_REMOTE) { + return dhd_ioctl(wl, cmd, buf, *len, TRUE); + } +#ifdef RWL_ENABLE + else { + return rwl_setinformation_fe(wl, cmd, buf, (unsigned long*)len, 0, RDHD_SET_IOCTL); + + } +#else /* RWL_ENABLE */ + return BCME_IOCTL_ERROR; +#endif /* RWL_ENABLE */ +} + +/* The function is replica of wl_get in wlu_linux.c. Optimize when we have some + * common code between wlu_linux.c and dhdu_linux.c + */ +int +wl_get(void *wl, int cmd, void *buf, int len) +{ + int error = BCME_OK; + /* For RWL: When interfacing to a Windows client, need t add in OID_BASE */ + if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) { + error = (int)ioctl_queryinformation_fe(wl, WL_OID_BASE + cmd, buf, &len); + } else { + error = (int)ioctl_queryinformation_fe(wl, cmd, buf, &len); + } + if (error == BCME_SERIAL_PORT_ERR) + return BCME_SERIAL_PORT_ERR; + + if (error != 0) + return BCME_IOCTL_ERROR; + + return error; +} + +/* The function is replica of wl_set in wlu_linux.c. Optimize when we have some + * common code between wlu_linux.c and dhdu_linux.c + */ +int +wl_set(void *wl, int cmd, void *buf, int len) +{ + int error = BCME_OK; + + /* For RWL: When interfacing to a Windows client, need t add in OID_BASE */ + if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) { + error = (int)ioctl_setinformation_fe(wl, WL_OID_BASE + cmd, buf, &len); + } else { + error = (int)ioctl_setinformation_fe(wl, cmd, buf, &len); + } + + if (error == BCME_SERIAL_PORT_ERR) + return BCME_SERIAL_PORT_ERR; + + if (error != 0) { + return BCME_IOCTL_ERROR; + } + return error; +} + +int +wl_validatedev(void *dev_handle) +{ + int retval = 1; + struct ifreq *ifr = (struct ifreq *)dev_handle; + /* validate the interface */ + if (!ifr->ifr_name || wl_check((void *)ifr)) { + retval = 0; + } + return retval; +} + +/* Main client function + * The code is mostly from wlu_linux.c. This function takes care of executing remote dhd commands + * along with the local dhd commands now. + */ +int +main(int argc, char **argv) +{ + struct ifreq ifr; + char *ifname = NULL; + int err = 0; + int help = 0; + int status = CMD_DHD; +#ifdef RWL_DONGLE + void* serialHandle = NULL; +#endif /* RWL_DONGLE */ +#ifdef RWL_SOCKET + struct ipv4_addr temp; +#endif /* RWL_SOCKET */ + + UNUSED_PARAMETER(argc); + + av0 = argv[0]; + memset(&ifr, 0, sizeof(ifr)); + argv++; + + if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) { + if (ifname) + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + } + /* Linux client looking for a Win32 server */ + if (*argv && strncmp (*argv, "--wince", strlen(*argv)) == 0) { + rwl_os_type = WIN32_OS; + argv++; + } + + /* RWL socket transport Usage: --socket ipaddr [port num] */ + if (*argv && strncmp (*argv, "--socket", strlen(*argv)) == 0) { + argv++; + + remote_type = REMOTE_SOCKET; +#ifdef RWL_SOCKET + if (!(*argv)) { + rwl_usage(remote_type); + return err; + } + + if (!dhd_atoip(*argv, &temp)) { + rwl_usage(remote_type); + return err; + } + g_rwl_servIP = *argv; + argv++; + + g_rwl_servport = DEFAULT_SERVER_PORT; + if ((*argv) && isdigit(**argv)) { + g_rwl_servport = atoi(*argv); + argv++; + } +#endif /* RWL_SOCKET */ + } + + /* RWL from system serial port on client to uart dongle port on server */ + /* Usage: --dongle /dev/ttyS0 */ + if (*argv && strncmp (*argv, "--dongle", strlen(*argv)) == 0) { + argv++; + remote_type = REMOTE_DONGLE; +#ifdef RWL_DONGLE + if (!(*argv)) { + rwl_usage(remote_type); + return err; + } + g_rwl_device_name_serial = *argv; + argv++; + if ((serialHandle = rwl_open_pipe(remote_type, "\0", 0, 0)) == NULL) { + DPRINT_ERR(ERR, "serial device open error\r\n"); + return BCME_ERROR; + } + ifr = (*(struct ifreq *)serialHandle); +#endif /* RWL_DONGLE */ + } + + /* RWL over wifi. Usage: --wifi mac_address */ + if (*argv && strncmp (*argv, "--wifi", strlen(*argv)) == 0) { + argv++; +#ifdef RWL_WIFI + remote_type = NO_REMOTE; + if (!ifr.ifr_name[0]) + { + dhd_find(&ifr, "wl"); + } + /* validate the interface */ + if (!ifr.ifr_name[0] || wl_check((void*)&ifr)) { + fprintf(stderr, "%s: wl driver adapter not found\n", av0); + exit(1); + } + remote_type = REMOTE_WIFI; + + if (argc < 4) { + rwl_usage(remote_type); + return err; + } + /* copy server mac address to local buffer for later use by findserver cmd */ + if (!dhd_ether_atoe(*argv, (struct ether_addr *)g_rwl_buf_mac)) { + fprintf(stderr, + "could not parse as an ethernet MAC address\n"); + return FAIL; + } + argv++; +#else /* RWL_WIFI */ + remote_type = REMOTE_WIFI; +#endif /* RWL_WIFI */ + } + + /* Process for local dhd */ + if (remote_type == NO_REMOTE) { + err = process_args(&ifr, argv); + return err; + } + +#ifdef RWL_ENABLE + if (*argv) { + err = process_args(&ifr, argv); + if ((err == BCME_SERIAL_PORT_ERR) && (remote_type == REMOTE_DONGLE)) { + DPRINT_ERR(ERR, "\n Retry again\n"); + err = process_args((struct ifreq*)&ifr, argv); + } + return err; + } + rwl_usage(remote_type); +#endif /* RWL_ENABLE */ + +#ifdef RWL_DONGLE + if (remote_type == REMOTE_DONGLE) + rwl_close_pipe(remote_type, (void*)&ifr); +#endif /* RWL_DONGLE */ + return err; +} +/* + * Function called for 'local' execution and for 'remote' non-interactive session + * (shell cmd, wl cmd) .The code is mostly from wlu_linux.c. This code can be + * common to wlu_linux.c and dhdu_linux.c + */ +static int +process_args(struct ifreq* ifr, char **argv) +{ + char *ifname = NULL; + int help = 0; + int status = 0; + int err = BCME_OK; + cmd_t *cmd = NULL; + while (*argv) { +#ifdef RWL_ENABLE + if ((strcmp (*argv, "sh") == 0) && (remote_type != NO_REMOTE)) { + argv++; /* Get the shell command */ + if (*argv) { + /* Register handler in case of shell command only */ + signal(SIGINT, ctrlc_handler); + err = rwl_shell_cmd_proc((void*)ifr, argv, SHELL_CMD); + } else { + DPRINT_ERR(ERR, + "Enter the shell command (e.g ls(Linux) or dir(Win CE) \n"); + err = BCME_ERROR; + } + return err; + } +#endif /* RWL_ENABLE */ + if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) { + if (help) + break; + if (ifname) + strncpy(ifr->ifr_name, ifname, IFNAMSIZ); + continue; + } + /* parse error */ + else if (status == CMD_ERR) + break; + + if (remote_type == NO_REMOTE) { + int ret; + + /* use default interface */ + if (!ifr->ifr_name[0]) + dhd_find(ifr, "dhd"); + /* validate the interface */ + if (!ifr->ifr_name[0]) { + if (strcmp("dldn", *argv) != 0) { + exit(ENXIO); + syserr("interface"); + } + } + if ((ret = dhd_check((void *)ifr)) != 0) { + if (strcmp("dldn", *argv) != 0) { + errno = -ret; + syserr("dhd_check"); + } + } + } + /* search for command */ + cmd = dhd_find_cmd(*argv); + /* if not found, use default set_var and get_var commands */ + if (!cmd) { + cmd = &dhd_varcmd; + } + + /* do command */ + err = (*cmd->func)((void *) ifr, cmd, argv); + break; + } /* while loop end */ + + /* provide for help on a particular command */ + if (help && *argv) { + cmd = dhd_find_cmd(*argv); + if (cmd) { + dhd_cmd_usage(cmd); + } else { + DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n", + av0, *argv); + } + } else if (!cmd) + dhd_usage(NULL); + else if (err == BCME_USAGE_ERROR) + dhd_cmd_usage(cmd); + else if (err == BCME_IOCTL_ERROR) + dhd_printlasterror((void *) ifr); + + return err; +} + +int +rwl_shell_createproc(void *wl) +{ + UNUSED_PARAMETER(wl); + return fork(); +} + +void +rwl_shell_killproc(int pid) +{ + kill(pid, SIGKILL); +} + +#ifdef RWL_SOCKET +/* validate hostname/ip given by the client */ +int +validate_server_address() +{ + struct hostent *he; + struct ipv4_addr temp; + + if (!dhd_atoip(g_rwl_servIP, &temp)) { + /* Wrong IP address format check for hostname */ + if ((he = gethostbyname(g_rwl_servIP)) != NULL) { + if (!dhd_atoip(*he->h_addr_list, &temp)) { + g_rwl_servIP = inet_ntoa(*(struct in_addr *)*he->h_addr_list); + if (g_rwl_servIP == NULL) { + DPRINT_ERR(ERR, "Error at inet_ntoa \n"); + return FAIL; + } + } else { + DPRINT_ERR(ERR, "Error in IP address \n"); + return FAIL; + } + } else { + DPRINT_ERR(ERR, "Enter correct IP address/hostname format\n"); + return FAIL; + } + } + return SUCCESS; +} +#endif /* RWL_SOCKET */
diff --git a/src/dhd/exe/dhdu_nl80211.c b/src/dhd/exe/dhdu_nl80211.c new file mode 100644 index 0000000..322d5f1 --- /dev/null +++ b/src/dhd/exe/dhdu_nl80211.c
@@ -0,0 +1,185 @@ +/* + * nl80211 linux driver interface. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: $ + */ +#include <errno.h> +#include <linux/nl80211.h> +#include <dhdioctl.h> +#include <brcm_nl80211.h> +#include "dhdu_nl80211.h" + +static struct nla_policy dhd_nl_policy[BCM_NLATTR_MAX + 1] = { + [BCM_NLATTR_LEN] = { .type = NLA_U16 }, + [BCM_NLATTR_DATA] = { .type = NLA_UNSPEC }, +}; + +/* libnl 1.x compatibility code */ +#if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30) +static inline struct nl_handle *nl_socket_alloc(void) +{ + return nl_handle_alloc(); +} + +static inline void nl_socket_free(struct nl_sock *h) +{ + nl_handle_destroy(h); +} +#endif /* CONFIG_LIBNL20 && CONFIG_LIBNL30 */ + +static int dhd_nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) +{ + if (err->error) + fprintf(stderr, "%s:error:%d\n", __func__, err->error); + return NL_SKIP; +} + +static int dhd_nl_finish_handler(struct nl_msg *msg, void *arg) +{ + return NL_SKIP; +} + +static int dhd_nl_ack_handler(struct nl_msg *msg, void *arg) +{ + struct nl_prv_data *prv = arg; + + prv->err = 0; + return NL_STOP; +} + +static int dhd_nl_valid_handler(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *attrs[NL80211_ATTR_MAX + 1]; + struct nlattr *nl_dhd[BCM_NLATTR_MAX + 1]; + struct nl_prv_data *prv = arg; + int ret; + uint payload; + + nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!attrs[NL80211_ATTR_TESTDATA]) { + fprintf(stderr, "Could not find attrs NL80211_ATTR_TESTDATA\n"); + return NL_SKIP; + } + + ret = nla_parse_nested(nl_dhd, BCM_NLATTR_MAX, + attrs[NL80211_ATTR_TESTDATA], dhd_nl_policy); + if (ret != 0 || !nl_dhd[BCM_NLATTR_LEN] || !nl_dhd[BCM_NLATTR_DATA]) { + fprintf(stderr, "nla_parse_nested error\n"); + return NL_SKIP; + } + + payload = nla_get_u16(nl_dhd[BCM_NLATTR_LEN]); + if (payload > prv->len) + payload = prv->len; + memcpy(prv->data, nla_data(nl_dhd[BCM_NLATTR_DATA]), payload); + prv->data += payload; + prv->len -= payload; + + return NL_SKIP; +} + +int dhd_nl_sock_connect(struct dhd_netlink_info *dhd_nli) +{ + dhd_nli->nl = nl_socket_alloc(); + if (dhd_nli->nl == NULL) + return -1; + + if (genl_connect(dhd_nli->nl) < 0) { + fprintf(stderr, "netlink connection failed\n"); + goto err; + } + + dhd_nli->nl_id = genl_ctrl_resolve(dhd_nli->nl, "nl80211"); + if (dhd_nli->nl_id < 0) { + fprintf(stderr, "'nl80211' netlink not found\n"); + goto err; + } + + dhd_nli->cb = nl_cb_alloc(NL_CB_DEBUG); + if (dhd_nli->cb == NULL) + goto err; + + nl_socket_set_cb(dhd_nli->nl, dhd_nli->cb); + return 0; + +err: + nl_cb_put(dhd_nli->cb); + nl_socket_free(dhd_nli->nl); + fprintf(stderr, "nl80211 connection failed\n"); + return -1; +} + +void dhd_nl_sock_disconnect(struct dhd_netlink_info *dhd_nli) +{ + nl_cb_put(dhd_nli->cb); + nl_socket_free(dhd_nli->nl); +} + +int dhd_nl_do_testmode(struct dhd_netlink_info *dhd_nli, dhd_ioctl_t *ioc) +{ + struct nl_msg *msg; + struct nl_prv_data prv_dat; + struct bcm_nlmsg_hdr *nlioc; + uint msglen = ioc->len; + + msg = nlmsg_alloc(); + if (msg == NULL) + return -ENOMEM; + + /* nlmsg_alloc() can only allocate default_pagesize packet, cap + * any buffer send down to 1024 bytes + * Maximum downlink buffer ATM is required for PNO ssid list (900 bytes) + * DO NOT switch to nlmsg_alloc_size because Android doesn't support it + */ + if (msglen > 0x400) + msglen = 0x400; + msglen += sizeof(struct bcm_nlmsg_hdr); + nlioc = malloc(msglen); + if (nlioc == NULL) { + nlmsg_free(msg); + return -ENOMEM; + } + nlioc->cmd = ioc->cmd; + nlioc->len = ioc->len; + nlioc->offset = sizeof(struct bcm_nlmsg_hdr); + nlioc->set = ioc->set; + nlioc->magic = ioc->driver; + memcpy(((void *)nlioc) + nlioc->offset, ioc->buf, msglen - nlioc->offset); + + /* fill testmode message */ + genlmsg_put(msg, 0, 0, dhd_nli->nl_id, 0, 0, + NL80211_CMD_TESTMODE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dhd_nli->ifidx); + NLA_PUT(msg, NL80211_ATTR_TESTDATA, msglen, nlioc); + + prv_dat.err = nl_send_auto_complete(dhd_nli->nl, msg); + if (prv_dat.err < 0) + goto out; + + prv_dat.err = 1; + prv_dat.nlioc = nlioc; + prv_dat.data = ioc->buf; + prv_dat.len = ioc->len; + nl_cb_err(dhd_nli->cb, NL_CB_CUSTOM, dhd_nl_error_handler, &prv_dat); + nl_cb_set(dhd_nli->cb, NL_CB_ACK, NL_CB_CUSTOM, + dhd_nl_ack_handler, &prv_dat); + nl_cb_set(dhd_nli->cb, NL_CB_FINISH, NL_CB_CUSTOM, + dhd_nl_finish_handler, &prv_dat); + nl_cb_set(dhd_nli->cb, NL_CB_VALID, NL_CB_CUSTOM, + dhd_nl_valid_handler, &prv_dat); + while (prv_dat.err > 0) + nl_recvmsgs(dhd_nli->nl, dhd_nli->cb); +out: + free(nlioc); + nlmsg_free(msg); + return prv_dat.err; + +nla_put_failure: + fprintf(stderr, "setting netlink attribute failed\n"); + prv_dat.err = -EFAULT; + goto out; +}
diff --git a/src/dhd/exe/dhdu_nl80211.h b/src/dhd/exe/dhdu_nl80211.h new file mode 100644 index 0000000..30be86f --- /dev/null +++ b/src/dhd/exe/dhdu_nl80211.h
@@ -0,0 +1,37 @@ +/* + * Definitions for DHD nl80211 driver interface. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: $ + */ + +#ifndef DHDU_NL80211_H_ +#define DHDU_NL80211_H_ + +#ifdef NL80211 + +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> + +/* libnl 1.x compatibility code */ +#if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30) +#define nl_sock nl_handle +#endif + +struct dhd_netlink_info +{ + struct nl_sock *nl; + struct nl_cb *cb; + int nl_id; + int ifidx; +}; + +int dhd_nl_sock_connect(struct dhd_netlink_info *dhd_nli); +void dhd_nl_sock_disconnect(struct dhd_netlink_info *dhd_nli); +int dhd_nl_do_testmode(struct dhd_netlink_info *dhd_nli, dhd_ioctl_t *ioc); + +#endif /* NL80211 */ + +#endif /* DHDU_NL80211_H_ */
diff --git a/src/dhd/exe/netlink.inc b/src/dhd/exe/netlink.inc new file mode 100644 index 0000000..6d6a4ad --- /dev/null +++ b/src/dhd/exe/netlink.inc
@@ -0,0 +1,90 @@ +# +# netlink.inc for dhd/exe +# +# Copyright (c) 2013, Broadcom Corp. +# $Id: netlink.inc 454524 2014-02-11 01:45:50Z $ + +ifdef NL80211 + +ifneq ($(findstring android,$(TARGETENV)),) + +include $(dir $(lastword $(MAKEFILE_LIST)))/../../makefiles/WLAN_Common.mk + +ifeq ($(NLHEADERS_PATH),) +$(error libnl headers path must be specified) +endif +ifeq ($(NLSTATICLIB_PATH),) +$(error libnl static library path must be specified) +endif + +CFLAGS += -I$(NLHEADERS_PATH) +LIBS += -Wl,--whole-archive -Wl,--no-whole-archive $(NLSTATICLIB_PATH) + +LIBNLVER = $(shell grep "LIBNL_VERSION" $(NLHEADERS_PATH)/netlink/version.h | cut -d " " -f 3 | sed "s/\"//g") + +ifeq ($(call wlan_version_ge,$(LIBNLVER),3.0),TRUE) +CFLAGS += -DCONFIG_LIBNL30 +else ifeq ($(call wlan_version_ge,$(LIBNLVER),2.0),TRUE) +CFLAGS += -DCONFIG_LIBNL20 +endif + +else #ifneq ($(findstring android,$(TARGETENV)),) + +PKG_CONFIG ?= pkg-config + +NL1FOUND := $(shell $(PKG_CONFIG) --atleast-version=1 libnl-1 && echo Y) +NL2FOUND := $(shell $(PKG_CONFIG) --atleast-version=2 libnl-2.0 && echo Y) +NL3FOUND := $(shell $(PKG_CONFIG) --atleast-version=3 libnl-3.0 && echo Y) +NL31FOUND := $(shell $(PKG_CONFIG) --exact-version=3.1 libnl-3.1 && echo Y) +NL3xFOUND := $(shell $(PKG_CONFIG) --atleast-version=3.2 libnl-3.0 && echo Y) + +$(sh echo "what to do") + +ifeq ($(NL1FOUND),Y) +NLLIBNAME = libnl-1 +endif + +ifeq ($(NL2FOUND),Y) +CFLAGS += -DCONFIG_LIBNL20 +LIBS += -lnl-genl +NLLIBNAME = libnl-2.0 +endif + +ifeq ($(NL3xFOUND),Y) +# libnl 3.2 might be found as 3.2 and 3.0 +NL3FOUND = N +CFLAGS += -DCONFIG_LIBNL30 +LIBS += -lnl-genl-3 +NLLIBNAME = libnl-3.0 +endif + +ifeq ($(NL3FOUND),Y) +CFLAGS += -DCONFIG_LIBNL30 +LIBS += -lnl-genl +NLLIBNAME = libnl-3.0 +endif + +# nl-3.1 has a broken libnl-gnl-3.1.pc file +# as show by pkg-config --debug --libs --cflags --exact-version=3.1 libnl-genl-3.1;echo $? +ifeq ($(NL31FOUND),Y) +CFLAGS += -DCONFIG_LIBNL30 +LIBS += -lnl-genl +NLLIBNAME = libnl-3.1 +endif + +ifeq ($(NLLIBNAME),) +$(error Cannot find development files for any supported version of libnl) +endif + +LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME)) +CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME)) + +endif #ifneq ($(findstring android,$(TARGETENV)),) + +ifeq ($(BUILD_TAG),TRUNK) +DHD_OBJS += $(TARGETARCH)/dhdu_nl80211.o +else +DHD_OBJS += dhdu_nl80211.o +endif + +endif # NL80211
diff --git a/src/dhd/exe/ucode_download.c b/src/dhd/exe/ucode_download.c new file mode 100644 index 0000000..b2c7a3c --- /dev/null +++ b/src/dhd/exe/ucode_download.c
@@ -0,0 +1,251 @@ +/* + * Ucode download related utility functions + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: ucode_download.c 297277 2011-11-18 14:10:09Z $ + */ + +#include <unistd.h> +#include <errno.h> +#include <trxhdr.h> +#include <bcmendian.h> +#include <wlu_common.h> + +#define DEVPRESENT_DELAY 10000 /* in microsecs */ +#define DEVPRESENT_RETRIES 100 + +extern int wl_validatedev(void *dev_handle); + +int +dload_generic_data(void *wl, uint16 dload_type, unsigned char *dload_buf, int len) +{ + struct wl_dload_data *dload_ptr = (struct wl_dload_data *)dload_buf; + int err = 0; + int actual_data_offset; + char *buf; + + actual_data_offset = OFFSETOF(struct wl_dload_data, data); + dload_ptr->flag = (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT); + dload_ptr->flag |= DL_CRC_NOT_INUSE; + dload_ptr->dload_type = dload_type; + dload_ptr->len = htod32(len - actual_data_offset); + dload_ptr->crc = 0; + + len = len + 8 - (len%8); + + buf = malloc(WLC_IOCTL_MEDLEN); + if (buf) { + bzero(buf, WLC_IOCTL_MEDLEN); + err = wlu_iovar_setbuf(wl, "generic_dload", dload_buf, len, buf, + WLC_IOCTL_MEDLEN); + } + free(buf); + return err; +} + +int +dload_ucode_part(void *wl, uint8 ucode_type, uint32 datalen, unsigned char *org_buf) +{ + int num_chunks, chunk_len, cumulative_len = 0; + int size2alloc, ucode_chunk_len = 0; + unsigned char *new_buf; + struct wl_ucode_info *ucode_ptr; + int err = 0, ucode_offset, chunk_offset; + + ucode_offset = OFFSETOF(wl_dload_data_t, data); + chunk_offset = OFFSETOF(wl_ucode_info_t, data_chunk); + + err = wlu_iovar_getint(wl, "ucdload_chunk_len", + &ucode_chunk_len); + if (err) { + printf("err in getting ucode chunk len, exiting\n"); + return err; + } + + num_chunks = datalen/ucode_chunk_len; + if (datalen % ucode_chunk_len != 0) + num_chunks++; + size2alloc = ucode_offset + chunk_offset + ucode_chunk_len; + + /* single chunk buffer */ + new_buf = (unsigned char *)malloc(size2alloc); + memset(new_buf, 0, size2alloc); + ucode_ptr = (struct wl_ucode_info *)((uint8 *)new_buf+ucode_offset); + ucode_ptr->ucode_type = ucode_type; + ucode_ptr->num_chunks = num_chunks; + do { + if (datalen >= ucode_chunk_len) + chunk_len = ucode_chunk_len; + else + chunk_len = datalen; + memset(new_buf+ucode_offset+chunk_offset, 0, size2alloc-ucode_offset-chunk_offset); + ucode_ptr->chunk_len = htod32(chunk_len); + ucode_ptr->chunk_num++; + memcpy(&ucode_ptr->data_chunk[0], org_buf + cumulative_len, chunk_len); + cumulative_len += chunk_len; + err = dload_generic_data(wl, DL_TYPE_UCODE, new_buf, size2alloc); + if (err) { + printf("error while writing %s to the memory\n", + (ucode_type == UCODE_FW)? "ucode" : "initvals"); + break; + } + datalen = datalen - chunk_len; + } while (datalen > 0); + free(new_buf); + + return err; +} + +static int +check_ucode_file(unsigned char *headers) +{ + struct trx_header *trx; + int actual_data_len = -1; + + /* Extract trx header */ + trx = (struct trx_header *)headers; + if (trx->magic != TRX_MAGIC) { + printf("Error: trx bad hdr\n"); + goto err; + } + actual_data_len = ROUNDUP(trx->offsets[0], 4) + ROUNDUP(trx->offsets[1], 4); +err: + return actual_data_len; +} + +int +proc_ucode_download(char* fw_filename, void *dev_handle) +{ + FILE *fp = NULL; + int ret = 0, loopcnt = 0; + struct trx_header main_trx_hdr, *ucode_trx_hdr; + uint32 maintrx_hdr_len, tmp_len; + uint32 fw_size, second_offset, ucode_trx_offset; + long ucode_pos; + unsigned long ucode_info_len = 0, status; + unsigned char *ucodetrx_buf, *initvals_ptr; + int ucode_len, initvals_len; + int ucdload_status = 0; + int is_devpresent; + + /* read the file and push blocks down to memory */ + if ((fp = fopen(fw_filename, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open %s: %s\n", + __FUNCTION__, fw_filename, strerror(errno)); + ret = -1; + goto exit; + } + + maintrx_hdr_len = sizeof(struct trx_header); + tmp_len = fread(&main_trx_hdr, sizeof(uint8), maintrx_hdr_len, fp); + + if (tmp_len == maintrx_hdr_len) { + if (main_trx_hdr.magic == TRX_MAGIC) { + fw_size = main_trx_hdr.offsets[0]; + second_offset = main_trx_hdr.offsets[2]; + + if (second_offset == maintrx_hdr_len) { + second_offset = 0; + } + ucode_trx_offset = maintrx_hdr_len + + ROUNDUP(fw_size, 4) + ROUNDUP(second_offset, 4); + ucode_pos = fseek(fp, ucode_trx_offset, SEEK_SET); + BCM_REFERENCE(ucode_pos); + + if ((ucode_trx_hdr = malloc(sizeof(struct trx_header))) + == NULL) { + printf("Unable to allocate %d bytes!\n", maintrx_hdr_len); + ret = -ENOMEM; + goto exit; + } + + /* Read ONLY the firmware-file-header into the new_buffer */ + status = fread(ucode_trx_hdr, sizeof(uint8), + maintrx_hdr_len, fp); + if (status < sizeof(struct trx_header)) { + printf("Short read in hdr read for %s!\n", fw_filename); + ret = -EINVAL; + goto exit; + } + + if ((ucode_info_len = check_ucode_file( + (unsigned char *)ucode_trx_hdr)) <= 0) { + printf("not a valid ucode.trx\n"); + ret = -1; + goto exit; + } + + ucodetrx_buf = (unsigned char *)malloc(ucode_info_len * + sizeof(char)); + tmp_len = fread(ucodetrx_buf, sizeof(uint8), + ucode_info_len, fp); + if (ucode_info_len > 0) { + ucode_len = ucode_trx_hdr->offsets[0]; + initvals_ptr = ucodetrx_buf + + ROUNDUP(ucode_trx_hdr->offsets[0], 4); + initvals_len = ucode_trx_hdr->offsets[1]; + } + free(ucode_trx_hdr); + + init_cmd_batchingmode(); + do { + is_devpresent = wl_validatedev(dev_handle); + loopcnt++; + /* in USB after dongle fw starts running wl interface + might not appear in the list of interfaces immediately, hence try + after some delay of 10ms + */ + if (!is_devpresent) + usleep(DEVPRESENT_DELAY); + else { + /* below iovar to verify if the for foundout + interface has already ucode been downloaded + */ + ret = wlu_iovar_getint(dev_handle, "ucdload_status", + &ucdload_status); + if (ret) { + printf("err in ucdload_status, exiting\n"); + goto exit; + } + if (ucdload_status) { + /* Number of 'wl' interfaces to skip + in the next round of going thru wl_find + */ + printf("ucode is already downloaded\n"); + } + } + /* usb seems to take some time to come up, hence the + loop value of 100 + */ + } while (loopcnt < DEVPRESENT_RETRIES && !is_devpresent); + + if (loopcnt < DEVPRESENT_RETRIES) { + /* download the ucode fw */ + ret = dload_ucode_part(dev_handle, UCODE_FW, ucode_len, + ucodetrx_buf); + if (ret) { + printf("error while downloading ucode, exiting\n"); + goto exit; + } + /* download the initvals to the dongle */ + ret = dload_ucode_part(dev_handle, INIT_VALS, + initvals_len, initvals_ptr); + + if (ret) { + printf("error while downloading initvals, exiting\n"); + goto exit; + } + } + else { + printf("wl device is not present\n"); + } + free(ucodetrx_buf); + } + } + +exit: + if (fp) + fclose(fp); + return ret; +}
diff --git a/src/dhd/exe/ucode_download.h b/src/dhd/exe/ucode_download.h new file mode 100644 index 0000000..ad0a3e5 --- /dev/null +++ b/src/dhd/exe/ucode_download.h
@@ -0,0 +1,9 @@ +/* + * Ucode download related utility functions + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: ucode_download.h 241182 2011-02-17 21:50:03Z $ + */ +extern int +proc_ucode_download(char* fw_filename, void *dev_handle);
diff --git a/src/include/bcm_cfg.h b/src/include/bcm_cfg.h new file mode 100644 index 0000000..eaea1cc --- /dev/null +++ b/src/include/bcm_cfg.h
@@ -0,0 +1,11 @@ +/* + * BCM common config options + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcm_cfg.h 351867 2012-08-21 18:46:16Z $ + */ + +#ifndef _bcm_cfg_h_ +#define _bcm_cfg_h_ +#endif
diff --git a/src/include/bcm_mpool_pub.h b/src/include/bcm_mpool_pub.h new file mode 100644 index 0000000..0375285 --- /dev/null +++ b/src/include/bcm_mpool_pub.h
@@ -0,0 +1,343 @@ +/* + * Memory pools library, Public interface + * + * API Overview + * + * This package provides a memory allocation subsystem based on pools of + * homogenous objects. + * + * Instrumentation is available for reporting memory utilization both + * on a per-data-structure basis and system wide. + * + * There are two main types defined in this API. + * + * pool manager: A singleton object that acts as a factory for + * pool allocators. It also is used for global + * instrumentation, such as reporting all blocks + * in use across all data structures. The pool manager + * creates and provides individual memory pools + * upon request to application code. + * + * memory pool: An object for allocating homogenous memory blocks. + * + * Global identifiers in this module use the following prefixes: + * bcm_mpm_* Memory pool manager + * bcm_mp_* Memory pool + * + * There are two main types of memory pools: + * + * prealloc: The contiguous memory block of objects can either be supplied + * by the client or malloc'ed by the memory manager. The objects are + * allocated out of a block of memory and freed back to the block. + * + * heap: The memory pool allocator uses the heap (malloc/free) for memory. + * In this case, the pool allocator is just providing statistics + * and instrumentation on top of the heap, without modifying the heap + * allocation implementation. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcm_mpool_pub.h 407097 2013-06-11 18:43:16Z $ + */ + +#ifndef _BCM_MPOOL_PUB_H +#define _BCM_MPOOL_PUB_H 1 + +#include <typedefs.h> /* needed for uint16 */ + + +/* +************************************************************************** +* +* Type definitions, handles +* +************************************************************************** +*/ + +/* Forward declaration of OSL handle. */ +struct osl_info; + +/* Forward declaration of string buffer. */ +struct bcmstrbuf; + +/* + * Opaque type definition for the pool manager handle. This object is used for global + * memory pool operations such as obtaining a new pool, deleting a pool, iterating and + * instrumentation/debugging. + */ +struct bcm_mpm_mgr; +typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; + +/* + * Opaque type definition for an instance of a pool. This handle is used for allocating + * and freeing memory through the pool, as well as management/instrumentation on this + * specific pool. + */ +struct bcm_mp_pool; +typedef struct bcm_mp_pool *bcm_mp_pool_h; + + +/* + * To make instrumentation more readable, every memory + * pool must have a readable name. Pool names are up to + * 8 bytes including '\0' termination. (7 printable characters.) + */ +#define BCM_MP_NAMELEN 8 + + +/* + * Type definition for pool statistics. + */ +typedef struct bcm_mp_stats { + char name[BCM_MP_NAMELEN]; /* Name of this pool. */ + unsigned int objsz; /* Object size allocated in this pool */ + uint16 nobj; /* Total number of objects in this pool */ + uint16 num_alloc; /* Number of objects currently allocated */ + uint16 high_water; /* Max number of allocated objects. */ + uint16 failed_alloc; /* Failed allocations. */ +} bcm_mp_stats_t; + + +/* +************************************************************************** +* +* API Routines on the pool manager. +* +************************************************************************** +*/ + +/* + * bcm_mpm_init() - initialize the whole memory pool system. + * + * Parameters: + * osh: INPUT Operating system handle. Needed for heap memory allocation. + * max_pools: INPUT Maximum number of mempools supported. + * mgr: OUTPUT The handle is written with the new pools manager object/handle. + * + * Returns: + * BCME_OK Object initialized successfully. May be used. + * BCME_NOMEM Initialization failed due to no memory. Object must not be used. + */ +int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); + + +/* + * bcm_mpm_deinit() - de-initialize the whole memory pool system. + * + * Parameters: + * mgr: INPUT Pointer to pool manager handle. + * + * Returns: + * BCME_OK Memory pool manager successfully de-initialized. + * other Indicated error occured during de-initialization. + */ +int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); + +/* + * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The + * pool uses a contiguous block of pre-alloced + * memory. The memory block may either be provided + * by the client or dynamically allocated by the + * pool manager. + * + * Parameters: + * mgr: INPUT The handle to the pool manager + * obj_sz: INPUT Size of objects that will be allocated by the new pool + * Must be >= sizeof(void *). + * nobj: INPUT Maximum number of concurrently existing objects to support + * memstart INPUT Pointer to the memory to use, or NULL to malloc() + * memsize INPUT Number of bytes referenced from memstart (for error checking). + * Must be 0 if 'memstart' is NULL. + * poolname INPUT For instrumentation, the name of the pool + * newp: OUTPUT The handle for the new pool, if creation is successful + * + * Returns: + * BCME_OK Pool created ok. + * other Pool not created due to indicated error. newpoolp set to NULL. + * + * + */ +int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, + unsigned int obj_sz, + int nobj, + void *memstart, + unsigned int memsize, + const char poolname[BCM_MP_NAMELEN], + bcm_mp_pool_h *newp); + + +/* + * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after + * all memory objects have been freed back to the pool. + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * pool: INPUT The handle of the pool to delete + * + * Returns: + * BCME_OK Pool deleted ok. + * other Pool not deleted due to indicated error. + * + */ +int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); + +/* + * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory + * pool allocator uses the heap (malloc/free) for memory. + * In this case, the pool allocator is just providing + * statistics and instrumentation on top of the heap, + * without modifying the heap allocation implementation. + * + * Parameters: + * mgr: INPUT The handle to the pool manager + * obj_sz: INPUT Size of objects that will be allocated by the new pool + * poolname INPUT For instrumentation, the name of the pool + * newp: OUTPUT The handle for the new pool, if creation is successful + * + * Returns: + * BCME_OK Pool created ok. + * other Pool not created due to indicated error. newpoolp set to NULL. + * + * + */ +int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, + const char poolname[BCM_MP_NAMELEN], + bcm_mp_pool_h *newp); + + +/* + * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after + * all memory objects have been freed back to the pool. + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * pool: INPUT The handle of the pool to delete + * + * Returns: + * BCME_OK Pool deleted ok. + * other Pool not deleted due to indicated error. + * + */ +int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); + + +/* + * bcm_mpm_stats() - Return stats for all pools + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * stats: OUTPUT Array of pool statistics. + * nentries: MOD Max elements in 'stats' array on INPUT. Actual number + * of array elements copied to 'stats' on OUTPUT. + * + * Returns: + * BCME_OK Ok + * other Error getting stats. + * + */ +int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); + + +/* + * bcm_mpm_dump() - Display statistics on all pools + * + * Parameters: + * mgr: INPUT The handle to the pools manager + * b: OUTPUT Output buffer. + * + * Returns: + * BCME_OK Ok + * other Error during dump. + * + */ +int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); + + +/* + * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to + * compensate for alignment requirements of the objects. + * This function provides the padded object size. If clients + * pre-allocate a memory slab for a memory pool, the + * padded object size should be used by the client to allocate + * the memory slab (in order to provide sufficent space for + * the maximum number of objects). + * + * Parameters: + * mgr: INPUT The handle to the pools manager. + * obj_sz: INPUT Input object size. + * padded_obj_sz: OUTPUT Padded object size. + * + * Returns: + * BCME_OK Ok + * BCME_BADARG Bad arguments. + * + */ +int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); + + +/* +*************************************************************************** +* +* API Routines on a specific pool. +* +*************************************************************************** +*/ + + +/* + * bcm_mp_alloc() - Allocate a memory pool object. + * + * Parameters: + * pool: INPUT The handle to the pool. + * + * Returns: + * A pointer to the new object. NULL on error. + * + */ +void* bcm_mp_alloc(bcm_mp_pool_h pool); + +/* + * bcm_mp_free() - Free a memory pool object. + * + * Parameters: + * pool: INPUT The handle to the pool. + * objp: INPUT A pointer to the object to free. + * + * Returns: + * BCME_OK Ok + * other Error during free. + * + */ +int bcm_mp_free(bcm_mp_pool_h pool, void *objp); + +/* + * bcm_mp_stats() - Return stats for this pool + * + * Parameters: + * pool: INPUT The handle to the pool + * stats: OUTPUT Pool statistics + * + * Returns: + * BCME_OK Ok + * other Error getting statistics. + * + */ +int bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); + + +/* + * bcm_mp_dump() - Dump a pool + * + * Parameters: + * pool: INPUT The handle to the pool + * b OUTPUT Output buffer + * + * Returns: + * BCME_OK Ok + * other Error during dump. + * + */ +int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); + + +#endif /* _BCM_MPOOL_PUB_H */
diff --git a/src/include/bcmcdc.h b/src/include/bcmcdc.h new file mode 100644 index 0000000..7d00f1e --- /dev/null +++ b/src/include/bcmcdc.h
@@ -0,0 +1,108 @@ +/* + * CDC network driver ioctl/indication encoding + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmcdc.h 318308 2012-03-02 02:23:42Z $ + */ +#ifndef _bcmcdc_h_ +#define _bcmcdc_h_ +#include <proto/ethernet.h> + +typedef struct cdc_ioctl { + uint32 cmd; + uint32 len; + uint32 flags; + uint32 status; +} cdc_ioctl_t; + + +#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN + + +#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF + +#define CDCL_IOC_OUTLEN_SHIFT 0 +#define CDCL_IOC_INLEN_MASK 0xFFFF0000 +#define CDCL_IOC_INLEN_SHIFT 16 + + +#define CDCF_IOC_ERROR 0x01 +#define CDCF_IOC_SET 0x02 +#define CDCF_IOC_OVL_IDX_MASK 0x3c +#define CDCF_IOC_OVL_RSV 0x40 +#define CDCF_IOC_OVL 0x80 +#define CDCF_IOC_ACTION_MASK 0xfe +#define CDCF_IOC_ACTION_SHIFT 1 +#define CDCF_IOC_IF_MASK 0xF000 +#define CDCF_IOC_IF_SHIFT 12 +#define CDCF_IOC_ID_MASK 0xFFFF0000 +#define CDCF_IOC_ID_SHIFT 16 + +#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) +#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) + +#define CDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) +#define CDC_SET_IF_IDX(hdr, idx) \ + ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) + + + +struct bdc_header { + uint8 flags; + uint8 priority; + uint8 flags2; + uint8 dataOffset; +}; + +#define BDC_HEADER_LEN 4 + + +#define BDC_FLAG_80211_PKT 0x01 +#define BDC_FLAG_SUM_GOOD 0x04 +#define BDC_FLAG_SUM_NEEDED 0x08 +#define BDC_FLAG_EVENT_MSG 0x08 +#define BDC_FLAG_VER_MASK 0xf0 +#define BDC_FLAG_VER_SHIFT 4 + + +#define BDC_PRIORITY_MASK 0x07 +#define BDC_PRIORITY_FC_MASK 0xf0 +#define BDC_PRIORITY_FC_SHIFT 4 + + +#define BDC_FLAG2_IF_MASK 0x0f +#define BDC_FLAG2_IF_SHIFT 0 +#define BDC_FLAG2_FC_FLAG 0x10 + + + +#define BDC_PROTO_VER_1 1 +#define BDC_PROTO_VER 2 + + +#define BDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) +#define BDC_SET_IF_IDX(hdr, idx) \ + ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT))) + +#define BDC_FLAG2_PAD_MASK 0xf0 +#define BDC_FLAG_PAD_MASK 0x03 +#define BDC_FLAG2_PAD_SHIFT 2 +#define BDC_FLAG_PAD_SHIFT 0 +#define BDC_FLAG2_PAD_IDX 0x3c +#define BDC_FLAG_PAD_IDX 0x03 +#define BDC_GET_PAD_LEN(hdr) \ + ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ + ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) +#define BDC_SET_PAD_LEN(hdr, idx) \ + ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ + (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ + ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ + (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) + +#endif
diff --git a/src/include/bcmdefs.h b/src/include/bcmdefs.h new file mode 100644 index 0000000..be36485 --- /dev/null +++ b/src/include/bcmdefs.h
@@ -0,0 +1,297 @@ +/* + * Misc system wide definitions + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmdefs.h 433011 2013-10-30 09:19:54Z $ + */ + +#ifndef _bcmdefs_h_ +#define _bcmdefs_h_ + + + + +#define BCM_REFERENCE(data) ((void)(data)) + + +#ifdef __GNUC__ +#define UNUSED_VAR __attribute__ ((unused)) +#else +#define UNUSED_VAR +#endif + + +#define STATIC_ASSERT(expr) { \ + \ + typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \ + \ + typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \ +} + + + +#define bcmreclaimed 0 +#define BCMATTACHDATA(_data) _data +#define BCMATTACHFN(_fn) _fn +#define BCMPREATTACHDATA(_data) _data +#define BCMPREATTACHFN(_fn) _fn +#define BCMINITDATA(_data) _data +#define BCMINITFN(_fn) _fn +#define BCMUNINITFN(_fn) _fn +#define BCMNMIATTACHFN(_fn) _fn +#define BCMNMIATTACHDATA(_data) _data +#define CONST const + +#if defined(__ARM_ARCH_7A__) && !defined(OEM_ANDROID) +#define BCM47XX_CA9 +#else +#undef BCM47XX_CA9 +#endif + +#ifndef BCMFASTPATH +#if defined(BCM47XX_CA9) +#define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath"))) +#define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host"))) +#else +#define BCMFASTPATH +#define BCMFASTPATH_HOST +#endif +#endif + + + + #define BCMRAMFN(_fn) _fn + + + + +#define BCMROMDATA(_data) _data +#define BCMROMDAT_NAME(_data) _data +#define BCMROMFN(_fn) _fn +#define BCMROMFN_NAME(_fn) _fn +#define STATIC static +#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) +#define BCMROMDAT_SIZEOF(data) sizeof(data) +#define BCMROMDAT_APATCH(data) +#define BCMROMDAT_SPATCH(data) + + +#define SI_BUS 0 +#define PCI_BUS 1 +#define PCMCIA_BUS 2 +#define SDIO_BUS 3 +#define JTAG_BUS 4 +#define USB_BUS 5 +#define SPI_BUS 6 +#define RPC_BUS 7 + + +#ifdef BCMBUSTYPE +#define BUSTYPE(bus) (BCMBUSTYPE) +#else +#define BUSTYPE(bus) (bus) +#endif + + +#ifdef BCMCHIPTYPE +#define CHIPTYPE(bus) (BCMCHIPTYPE) +#else +#define CHIPTYPE(bus) (bus) +#endif + + + +#if defined(BCMSPROMBUS) +#define SPROMBUS (BCMSPROMBUS) +#elif defined(SI_PCMCIA_SROM) +#define SPROMBUS (PCMCIA_BUS) +#else +#define SPROMBUS (PCI_BUS) +#endif + + +#ifdef BCMCHIPID +#define CHIPID(chip) (BCMCHIPID) +#else +#define CHIPID(chip) (chip) +#endif + +#ifdef BCMCHIPREV +#define CHIPREV(rev) (BCMCHIPREV) +#else +#define CHIPREV(rev) (rev) +#endif + + +#define DMADDR_MASK_32 0x0 +#define DMADDR_MASK_30 0xc0000000 +#define DMADDR_MASK_0 0xffffffff + +#define DMADDRWIDTH_30 30 +#define DMADDRWIDTH_32 32 +#define DMADDRWIDTH_63 63 +#define DMADDRWIDTH_64 64 + +typedef struct { + uint32 loaddr; + uint32 hiaddr; +} dma64addr_t; + +#define PHYSADDR64HI(_pa) ((_pa).hiaddr) +#define PHYSADDR64HISET(_pa, _val) \ + do { \ + (_pa).hiaddr = (_val); \ + } while (0) +#define PHYSADDR64LO(_pa) ((_pa).loaddr) +#define PHYSADDR64LOSET(_pa, _val) \ + do { \ + (_pa).loaddr = (_val); \ + } while (0) + +#ifdef BCMDMA64OSL +typedef dma64addr_t dmaaddr_t; +#define PHYSADDRHI(_pa) PHYSADDR64HI(_pa) +#define PHYSADDRHISET(_pa, _val) PHYSADDR64HISET(_pa, _val) +#define PHYSADDRLO(_pa) PHYSADDR64LO(_pa) +#define PHYSADDRLOSET(_pa, _val) PHYSADDR64LOSET(_pa, _val) + +#else +typedef unsigned long dmaaddr_t; +#define PHYSADDRHI(_pa) (0) +#define PHYSADDRHISET(_pa, _val) +#define PHYSADDRLO(_pa) ((_pa)) +#define PHYSADDRLOSET(_pa, _val) \ + do { \ + (_pa) = (_val); \ + } while (0) +#endif + + +typedef struct { + dmaaddr_t addr; + uint32 length; +} hnddma_seg_t; + +#define MAX_DMA_SEGS 8 + + +typedef struct { + void *oshdmah; + uint origsize; + uint nsegs; + hnddma_seg_t segs[MAX_DMA_SEGS]; +} hnddma_seg_map_t; + + + + +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) + +#define BCMEXTRAHDROOM 260 +#else +#if defined(BCM47XX_CA9) +#define BCMEXTRAHDROOM 224 +#else +#define BCMEXTRAHDROOM 204 +#endif +#endif + + +#ifndef SDALIGN +#define SDALIGN 32 +#endif + + +#define BCMDONGLEHDRSZ 12 +#define BCMDONGLEPADSZ 16 + +#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) + + +#if defined(NO_BCMDBG_ASSERT) +# undef BCMDBG_ASSERT +# undef BCMASSERT_LOG +#endif + +#if defined(BCMASSERT_LOG) +#define BCMASSERT_SUPPORT +#endif + + +#define BITFIELD_MASK(width) \ + (((unsigned)1 << (width)) - 1) +#define GFIELD(val, field) \ + (((val) >> field ## _S) & field ## _M) +#define SFIELD(val, field, bits) \ + (((val) & (~(field ## _M << field ## _S))) | \ + ((unsigned)(bits) << field ## _S)) + + +#ifdef BCMSMALL +#undef BCMSPACE +#define bcmspace FALSE +#else +#define BCMSPACE +#define bcmspace TRUE +#endif + + +#ifndef MAXSZ_NVRAM_VARS +#define MAXSZ_NVRAM_VARS 4096 +#endif + + + + + + +#ifdef BCMLFRAG + extern bool _bcmlfrag; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCMLFRAG_ENAB() (_bcmlfrag) + #elif defined(BCMLFRAG_DISABLED) + #define BCMLFRAG_ENAB() (0) + #else + #define BCMLFRAG_ENAB() (1) + #endif +#else + #define BCMLFRAG_ENAB() (0) +#endif +#ifdef BCMSPLITRX + extern bool _bcmsplitrx; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCMSPLITRX_ENAB() (_bcmsplitrx) + #elif defined(BCMSPLITRX_DISABLED) + #define BCMSPLITRX_ENAB() (0) + #else + #define BCMSPLITRX_ENAB() (1) + #endif +#else + #define BCMSPLITRX_ENAB() (0) +#endif +#ifdef BCM_SPLITBUF + extern bool _bcmsplitbuf; + #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) + #define BCM_SPLITBUF_ENAB() (_bcmsplitbuf) + #elif defined(BCM_SPLITBUF_DISABLED) + #define BCM_SPLITBUF_ENAB() (0) + #else + #define BCM_SPLITBUF_ENAB() (1) + #endif +#else + #define BCM_SPLITBUF_ENAB() (0) +#endif + +#ifdef DL_NVRAM +#define NVRAM_ARRAY_MAXSIZE DL_NVRAM +#else +#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS +#endif + +#ifdef BCMUSBDEV_ENABLED +extern uint32 gFWID; +#endif + + +#endif
diff --git a/src/include/bcmdevs.h b/src/include/bcmdevs.h new file mode 100644 index 0000000..3fd94a0 --- /dev/null +++ b/src/include/bcmdevs.h
@@ -0,0 +1,1029 @@ +/* + * Broadcom device-specific manifest constants. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmdevs.h 475454 2014-05-05 20:54:58Z $ + */ + +#ifndef _BCMDEVS_H +#define _BCMDEVS_H + + +#define VENDOR_EPIGRAM 0xfeda +#define VENDOR_BROADCOM 0x14e4 +#define VENDOR_3COM 0x10b7 +#define VENDOR_NETGEAR 0x1385 +#define VENDOR_DIAMOND 0x1092 +#define VENDOR_INTEL 0x8086 +#define VENDOR_DELL 0x1028 +#define VENDOR_HP 0x103c +#define VENDOR_HP_COMPAQ 0x0e11 +#define VENDOR_APPLE 0x106b +#define VENDOR_SI_IMAGE 0x1095 +#define VENDOR_BUFFALO 0x1154 +#define VENDOR_TI 0x104c +#define VENDOR_RICOH 0x1180 +#define VENDOR_JMICRON 0x197b + + + +#define VENDOR_BROADCOM_PCMCIA 0x02d0 + + +#define VENDOR_BROADCOM_SDIO 0x00BF + + +#define BCM_DNGL_VID 0x0a5c +#define BCM_DNGL_BL_PID_4328 0xbd12 +#define BCM_DNGL_BL_PID_4322 0xbd13 +#define BCM_DNGL_BL_PID_4319 0xbd16 +#define BCM_DNGL_BL_PID_43236 0xbd17 +#define BCM_DNGL_BL_PID_4332 0xbd18 +#define BCM_DNGL_BL_PID_4330 0xbd19 +#define BCM_DNGL_BL_PID_4334 0xbd1a +#define BCM_DNGL_BL_PID_43239 0xbd1b +#define BCM_DNGL_BL_PID_4324 0xbd1c +#define BCM_DNGL_BL_PID_4360 0xbd1d +#define BCM_DNGL_BL_PID_43143 0xbd1e +#define BCM_DNGL_BL_PID_43242 0xbd1f +#define BCM_DNGL_BL_PID_43342 0xbd21 +#define BCM_DNGL_BL_PID_4335 0xbd20 +#define BCM_DNGL_BL_PID_43341 0xbd22 +#define BCM_DNGL_BL_PID_4350 0xbd23 +#define BCM_DNGL_BL_PID_4345 0xbd24 +#define BCM_DNGL_BL_PID_4349 0xbd25 +#define BCM_DNGL_BL_PID_4354 0xbd26 + +#define BCM_DNGL_BDC_PID 0x0bdc +#define BCM_DNGL_JTAG_PID 0x4a44 + + +#define BCM_HWUSB_PID_43239 43239 + + +#define BCM4210_DEVICE_ID 0x1072 +#define BCM4230_DEVICE_ID 0x1086 +#define BCM4401_ENET_ID 0x170c +#define BCM3352_DEVICE_ID 0x3352 +#define BCM3360_DEVICE_ID 0x3360 +#define BCM4211_DEVICE_ID 0x4211 +#define BCM4231_DEVICE_ID 0x4231 +#define BCM4303_D11B_ID 0x4303 +#define BCM4311_D11G_ID 0x4311 +#define BCM4311_D11DUAL_ID 0x4312 +#define BCM4311_D11A_ID 0x4313 +#define BCM4328_D11DUAL_ID 0x4314 +#define BCM4328_D11G_ID 0x4315 +#define BCM4328_D11A_ID 0x4316 +#define BCM4318_D11G_ID 0x4318 +#define BCM4318_D11DUAL_ID 0x4319 +#define BCM4318_D11A_ID 0x431a +#define BCM4325_D11DUAL_ID 0x431b +#define BCM4325_D11G_ID 0x431c +#define BCM4325_D11A_ID 0x431d +#define BCM4306_D11G_ID 0x4320 +#define BCM4306_D11A_ID 0x4321 +#define BCM4306_UART_ID 0x4322 +#define BCM4306_V90_ID 0x4323 +#define BCM4306_D11DUAL_ID 0x4324 +#define BCM4306_D11G_ID2 0x4325 +#define BCM4321_D11N_ID 0x4328 +#define BCM4321_D11N2G_ID 0x4329 +#define BCM4321_D11N5G_ID 0x432a +#define BCM4322_D11N_ID 0x432b +#define BCM4322_D11N2G_ID 0x432c +#define BCM4322_D11N5G_ID 0x432d +#define BCM4329_D11N_ID 0x432e +#define BCM4329_D11N2G_ID 0x432f +#define BCM4329_D11N5G_ID 0x4330 +#define BCM4315_D11DUAL_ID 0x4334 +#define BCM4315_D11G_ID 0x4335 +#define BCM4315_D11A_ID 0x4336 +#define BCM4319_D11N_ID 0x4337 +#define BCM4319_D11N2G_ID 0x4338 +#define BCM4319_D11N5G_ID 0x4339 +#define BCM43231_D11N2G_ID 0x4340 +#define BCM43221_D11N2G_ID 0x4341 +#define BCM43222_D11N_ID 0x4350 +#define BCM43222_D11N2G_ID 0x4351 +#define BCM43222_D11N5G_ID 0x4352 +#define BCM43224_D11N_ID 0x4353 +#define BCM43224_D11N_ID_VEN1 0x0576 +#define BCM43226_D11N_ID 0x4354 +#define BCM43236_D11N_ID 0x4346 +#define BCM43236_D11N2G_ID 0x4347 +#define BCM43236_D11N5G_ID 0x4348 +#define BCM43225_D11N2G_ID 0x4357 +#define BCM43421_D11N_ID 0xA99D +#define BCM4313_D11N2G_ID 0x4727 +#define BCM4330_D11N_ID 0x4360 +#define BCM4330_D11N2G_ID 0x4361 +#define BCM4330_D11N5G_ID 0x4362 +#define BCM4336_D11N_ID 0x4343 +#define BCM6362_D11N_ID 0x435f +#define BCM6362_D11N2G_ID 0x433f +#define BCM6362_D11N5G_ID 0x434f +#define BCM4331_D11N_ID 0x4331 +#define BCM4331_D11N2G_ID 0x4332 +#define BCM4331_D11N5G_ID 0x4333 +#define BCM43237_D11N_ID 0x4355 +#define BCM43237_D11N5G_ID 0x4356 +#define BCM43227_D11N2G_ID 0x4358 +#define BCM43228_D11N_ID 0x4359 +#define BCM43228_D11N5G_ID 0x435a +#define BCM43362_D11N_ID 0x4363 +#define BCM43239_D11N_ID 0x4370 +#define BCM4324_D11N_ID 0x4374 +#define BCM43217_D11N2G_ID 0x43a9 +#define BCM43131_D11N2G_ID 0x43aa +#define BCM4314_D11N2G_ID 0x4364 +#define BCM43142_D11N2G_ID 0x4365 +#define BCM43143_D11N2G_ID 0x4366 +#define BCM4334_D11N_ID 0x4380 +#define BCM4334_D11N2G_ID 0x4381 +#define BCM4334_D11N5G_ID 0x4382 +#define BCM43342_D11N_ID 0x4383 +#define BCM43342_D11N2G_ID 0x4384 +#define BCM43342_D11N5G_ID 0x4385 +#define BCM43341_D11N_ID 0x4386 +#define BCM43341_D11N2G_ID 0x4387 +#define BCM43341_D11N5G_ID 0x4388 +#define BCM4360_D11AC_ID 0x43a0 +#define BCM4360_D11AC2G_ID 0x43a1 +#define BCM4360_D11AC5G_ID 0x43a2 +#define BCM4345_D11AC_ID 0x43ab +#define BCM4345_D11AC2G_ID 0x43ac +#define BCM4345_D11AC5G_ID 0x43ad +#define BCM4335_D11AC_ID 0x43ae +#define BCM4335_D11AC2G_ID 0x43af +#define BCM4335_D11AC5G_ID 0x43b0 +#define BCM4352_D11AC_ID 0x43b1 +#define BCM4352_D11AC2G_ID 0x43b2 +#define BCM4352_D11AC5G_ID 0x43b3 +#define BCM43602_D11AC_ID 0x43ba +#define BCM43602_D11AC2G_ID 0x43bb +#define BCM43602_D11AC5G_ID 0x43bc + + +#define BCM943228HMB_SSID_VEN1 0x0607 +#define BCM94313HMGBL_SSID_VEN1 0x0608 +#define BCM94313HMG_SSID_VEN1 0x0609 +#define BCM943142HM_SSID_VEN1 0x0611 + +#define BCM43143_D11N2G_ID 0x4366 + +#define BCM43242_D11N_ID 0x4367 +#define BCM43242_D11N2G_ID 0x4368 +#define BCM43242_D11N5G_ID 0x4369 + +#define BCM4350_D11AC_ID 0x43a3 +#define BCM4350_D11AC2G_ID 0x43a4 +#define BCM4350_D11AC5G_ID 0x43a5 + +#define BCM43556_D11AC_ID 0x43b7 +#define BCM43556_D11AC2G_ID 0x43b8 +#define BCM43556_D11AC5G_ID 0x43b9 + +#define BCM43558_D11AC_ID 0x43c0 +#define BCM43558_D11AC2G_ID 0x43c1 +#define BCM43558_D11AC5G_ID 0x43c2 + +#define BCM43566_D11AC_ID 0x43d3 +#define BCM43566_D11AC2G_ID 0x43d4 +#define BCM43566_D11AC5G_ID 0x43d5 + +#define BCM43568_D11AC_ID 0x43d6 +#define BCM43568_D11AC2G_ID 0x43d7 +#define BCM43568_D11AC5G_ID 0x43d8 + +#define BCM43569_D11AC_ID 0x43d9 +#define BCM43569_D11AC2G_ID 0x43da +#define BCM43569_D11AC5G_ID 0x43db + +#define BCM4354_D11AC_ID 0x43df +#define BCM4354_D11AC2G_ID 0x43e0 +#define BCM4354_D11AC5G_ID 0x43e1 +#define BCM43430_D11N2G_ID 0x43e2 + + +#define BCM43349_D11N_ID 0x43e6 +#define BCM43349_D11N2G_ID 0x43e7 +#define BCM43349_D11N5G_ID 0x43e8 + +#define BCM4356_D11AC_ID 0x43ec +#define BCM4356_D11AC2G_ID 0x43ed +#define BCM4356_D11AC5G_ID 0x43ee + +#define BCMGPRS_UART_ID 0x4333 +#define BCMGPRS2_UART_ID 0x4344 +#define FPGA_JTAGM_ID 0x43f0 +#define BCM_JTAGM_ID 0x43f1 +#define SDIOH_FPGA_ID 0x43f2 +#define BCM_SDIOH_ID 0x43f3 +#define SDIOD_FPGA_ID 0x43f4 +#define SPIH_FPGA_ID 0x43f5 +#define BCM_SPIH_ID 0x43f6 +#define MIMO_FPGA_ID 0x43f8 +#define BCM_JTAGM2_ID 0x43f9 +#define SDHCI_FPGA_ID 0x43fa +#define BCM4402_ENET_ID 0x4402 +#define BCM4402_V90_ID 0x4403 +#define BCM4410_DEVICE_ID 0x4410 +#define BCM4412_DEVICE_ID 0x4412 +#define BCM4430_DEVICE_ID 0x4430 +#define BCM4432_DEVICE_ID 0x4432 +#define BCM4704_ENET_ID 0x4706 +#define BCM4710_DEVICE_ID 0x4710 +#define BCM47XX_AUDIO_ID 0x4711 +#define BCM47XX_V90_ID 0x4712 +#define BCM47XX_ENET_ID 0x4713 +#define BCM47XX_EXT_ID 0x4714 +#define BCM47XX_GMAC_ID 0x4715 +#define BCM47XX_USBH_ID 0x4716 +#define BCM47XX_USBD_ID 0x4717 +#define BCM47XX_IPSEC_ID 0x4718 +#define BCM47XX_ROBO_ID 0x4719 +#define BCM47XX_USB20H_ID 0x471a +#define BCM47XX_USB20D_ID 0x471b +#define BCM47XX_ATA100_ID 0x471d +#define BCM47XX_SATAXOR_ID 0x471e +#define BCM47XX_GIGETH_ID 0x471f +#define BCM4712_MIPS_ID 0x4720 +#define BCM4716_DEVICE_ID 0x4722 +#define BCM47XX_USB30H_ID 0x472a +#define BCM47XX_USB30D_ID 0x472b +#define BCM47XX_SMBUS_EMU_ID 0x47fe +#define BCM47XX_XOR_EMU_ID 0x47ff +#define EPI41210_DEVICE_ID 0xa0fa +#define EPI41230_DEVICE_ID 0xa10e +#define JINVANI_SDIOH_ID 0x4743 +#define BCM27XX_SDIOH_ID 0x2702 +#define PCIXX21_FLASHMEDIA_ID 0x803b +#define PCIXX21_SDIOH_ID 0x803c +#define R5C822_SDIOH_ID 0x0822 +#define JMICRON_SDIOH_ID 0x2381 + + +#define BCM4306_CHIP_ID 0x4306 +#define BCM4311_CHIP_ID 0x4311 +#define BCM43111_CHIP_ID 43111 +#define BCM43112_CHIP_ID 43112 +#define BCM4312_CHIP_ID 0x4312 +#define BCM4313_CHIP_ID 0x4313 +#define BCM43131_CHIP_ID 43131 +#define BCM4315_CHIP_ID 0x4315 +#define BCM4318_CHIP_ID 0x4318 +#define BCM4319_CHIP_ID 0x4319 +#define BCM4320_CHIP_ID 0x4320 +#define BCM4321_CHIP_ID 0x4321 +#define BCM43217_CHIP_ID 43217 +#define BCM4322_CHIP_ID 0x4322 +#define BCM43221_CHIP_ID 43221 +#define BCM43222_CHIP_ID 43222 +#define BCM43224_CHIP_ID 43224 +#define BCM43225_CHIP_ID 43225 +#define BCM43227_CHIP_ID 43227 +#define BCM43228_CHIP_ID 43228 +#define BCM43226_CHIP_ID 43226 +#define BCM43231_CHIP_ID 43231 +#define BCM43234_CHIP_ID 43234 +#define BCM43235_CHIP_ID 43235 +#define BCM43236_CHIP_ID 43236 +#define BCM43237_CHIP_ID 43237 +#define BCM43238_CHIP_ID 43238 +#define BCM43239_CHIP_ID 43239 +#define BCM43420_CHIP_ID 43420 +#define BCM43421_CHIP_ID 43421 +#define BCM43428_CHIP_ID 43428 +#define BCM43431_CHIP_ID 43431 +#define BCM43460_CHIP_ID 43460 +#define BCM4325_CHIP_ID 0x4325 +#define BCM4328_CHIP_ID 0x4328 +#define BCM4329_CHIP_ID 0x4329 +#define BCM4331_CHIP_ID 0x4331 +#define BCM4336_CHIP_ID 0x4336 +#define BCM43362_CHIP_ID 43362 +#define BCM4330_CHIP_ID 0x4330 +#define BCM6362_CHIP_ID 0x6362 +#define BCM4314_CHIP_ID 0x4314 +#define BCM43142_CHIP_ID 43142 +#define BCM43143_CHIP_ID 43143 +#define BCM4324_CHIP_ID 0x4324 +#define BCM43242_CHIP_ID 43242 +#define BCM43243_CHIP_ID 43243 +#define BCM4334_CHIP_ID 0x4334 +#define BCM4335_CHIP_ID 0x4335 +#define BCM4339_CHIP_ID 0x4339 +#define BCM43349_CHIP_ID 43349 +#define BCM4360_CHIP_ID 0x4360 +#define BCM4352_CHIP_ID 0x4352 +#define BCM43526_CHIP_ID 0xAA06 +#define BCM43340_CHIP_ID 43340 +#define BCM43341_CHIP_ID 43341 +#define BCM43342_CHIP_ID 43342 +#define BCM4350_CHIP_ID 0x4350 +#define BCM4354_CHIP_ID 0x4354 +#define BCM4356_CHIP_ID 0x4356 +#define BCM43556_CHIP_ID 0xAA24 +#define BCM43558_CHIP_ID 0xAA26 +#define BCM43566_CHIP_ID 0xAA2E +#define BCM43568_CHIP_ID 0xAA30 +#define BCM43569_CHIP_ID 0xAA31 +#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \ + (CHIPID(chipid) == BCM4354_CHIP_ID) || \ + (CHIPID(chipid) == BCM4356_CHIP_ID) || \ + (CHIPID(chipid) == BCM43556_CHIP_ID) || \ + (CHIPID(chipid) == BCM43558_CHIP_ID) || \ + (CHIPID(chipid) == BCM43566_CHIP_ID) || \ + (CHIPID(chipid) == BCM43568_CHIP_ID) || \ + (CHIPID(chipid) == BCM43569_CHIP_ID)) +#define BCM4345_CHIP_ID 0x4345 +#define BCM43430_CHIP_ID 43430 + +#define BCM43602_CHIP_ID 0xaa52 + +#define BCM4342_CHIP_ID 4342 +#define BCM4402_CHIP_ID 0x4402 +#define BCM4704_CHIP_ID 0x4704 +#define BCM4706_CHIP_ID 0x5300 +#define BCM4707_CHIP_ID 53010 +#define BCM53018_CHIP_ID 53018 +#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || ((chipid) == BCM53018_CHIP_ID)) +#define BCM4710_CHIP_ID 0x4710 +#define BCM4712_CHIP_ID 0x4712 +#define BCM4716_CHIP_ID 0x4716 +#define BCM47162_CHIP_ID 47162 +#define BCM4748_CHIP_ID 0x4748 +#define BCM4749_CHIP_ID 0x4749 +#define BCM4785_CHIP_ID 0x4785 +#define BCM5350_CHIP_ID 0x5350 +#define BCM5352_CHIP_ID 0x5352 +#define BCM5354_CHIP_ID 0x5354 +#define BCM5365_CHIP_ID 0x5365 +#define BCM5356_CHIP_ID 0x5356 +#define BCM5357_CHIP_ID 0x5357 +#define BCM53572_CHIP_ID 53572 + + +#define BCM4303_PKG_ID 2 +#define BCM4309_PKG_ID 1 +#define BCM4712LARGE_PKG_ID 0 +#define BCM4712SMALL_PKG_ID 1 +#define BCM4712MID_PKG_ID 2 +#define BCM4328USBD11G_PKG_ID 2 +#define BCM4328USBDUAL_PKG_ID 3 +#define BCM4328SDIOD11G_PKG_ID 4 +#define BCM4328SDIODUAL_PKG_ID 5 +#define BCM4329_289PIN_PKG_ID 0 +#define BCM4329_182PIN_PKG_ID 1 +#define BCM5354E_PKG_ID 1 +#define BCM4716_PKG_ID 8 +#define BCM4717_PKG_ID 9 +#define BCM4718_PKG_ID 10 +#define BCM5356_PKG_NONMODE 1 +#define BCM5358U_PKG_ID 8 +#define BCM5358_PKG_ID 9 +#define BCM47186_PKG_ID 10 +#define BCM5357_PKG_ID 11 +#define BCM5356U_PKG_ID 12 +#define BCM53572_PKG_ID 8 +#define BCM5357C0_PKG_ID 8 +#define BCM47188_PKG_ID 9 +#define BCM5358C0_PKG_ID 0xa +#define BCM5356C0_PKG_ID 0xb +#define BCM4331TT_PKG_ID 8 +#define BCM4331TN_PKG_ID 9 +#define BCM4331TNA0_PKG_ID 0xb +#define BCM4706L_PKG_ID 1 + +#define HDLSIM5350_PKG_ID 1 +#define HDLSIM_PKG_ID 14 +#define HWSIM_PKG_ID 15 +#define BCM43224_FAB_CSM 0x8 +#define BCM43224_FAB_SMIC 0xa +#define BCM4336_WLBGA_PKG_ID 0x8 +#define BCM4330_WLBGA_PKG_ID 0x0 +#define BCM4314PCIE_ARM_PKG_ID (8 | 0) +#define BCM4314SDIO_PKG_ID (8 | 1) +#define BCM4314PCIE_PKG_ID (8 | 2) +#define BCM4314SDIO_ARM_PKG_ID (8 | 3) +#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) +#define BCM4314DEV_PKG_ID (8 | 6) + +#define BCM4707_PKG_ID 1 +#define BCM4708_PKG_ID 2 +#define BCM4709_PKG_ID 0 + +#define PCIXX21_FLASHMEDIA0_ID 0x8033 +#define PCIXX21_SDIOH0_ID 0x8034 + +#define BCM4335_WLCSP_PKG_ID (0x0) +#define BCM4335_FCBGA_PKG_ID (0x1) +#define BCM4335_WLBGA_PKG_ID (0x2) +#define BCM4335_FCBGAD_PKG_ID (0x3) +#define BCM4335_PKG_MASK (0x3) + + +#define BFL_BTC2WIRE 0x00000001 +#define BFL_BTCOEX 0x00000001 +#define BFL_PACTRL 0x00000002 +#define BFL_AIRLINEMODE 0x00000004 +#define BFL_ADCDIV 0x00000008 +#define BFL_DIS_256QAM 0x00000008 +#define BFL_ENETROBO 0x00000010 +#define BFL_NOPLLDOWN 0x00000020 +#define BFL_CCKHIPWR 0x00000040 +#define BFL_ENETADM 0x00000080 +#define BFL_ENETVLAN 0x00000100 +#define BFL_UNUSED 0x00000200 +#define BFL_NOPCI 0x00000400 +#define BFL_FEM 0x00000800 +#define BFL_EXTLNA 0x00001000 +#define BFL_HGPA 0x00002000 +#define BFL_BTC2WIRE_ALTGPIO 0x00004000 +#define BFL_ALTIQ 0x00008000 +#define BFL_NOPA 0x00010000 +#define BFL_RSSIINV 0x00020000 +#define BFL_PAREF 0x00040000 +#define BFL_3TSWITCH 0x00080000 +#define BFL_PHASESHIFT 0x00100000 +#define BFL_BUCKBOOST 0x00200000 +#define BFL_FEM_BT 0x00400000 +#define BFL_NOCBUCK 0x00800000 +#define BFL_CCKFAVOREVM 0x01000000 +#define BFL_PALDO 0x02000000 +#define BFL_LNLDO2_2P5 0x04000000 +#define BFL_FASTPWR 0x08000000 +#define BFL_UCPWRCTL_MININDX 0x08000000 +#define BFL_EXTLNA_5GHz 0x10000000 +#define BFL_TRSW_1by2 0x20000000 +#define BFL_GAINBOOSTA01 0x20000000 +#define BFL_LO_TRSW_R_5GHz 0x40000000 +#define BFL_ELNA_GAINDEF 0x80000000 +#define BFL_EXTLNA_TX 0x20000000 + + +#define BFL2_RXBB_INT_REG_DIS 0x00000001 +#define BFL2_APLL_WAR 0x00000002 +#define BFL2_TXPWRCTRL_EN 0x00000004 +#define BFL2_2X4_DIV 0x00000008 +#define BFL2_5G_PWRGAIN 0x00000010 +#define BFL2_PCIEWAR_OVR 0x00000020 +#define BFL2_CAESERS_BRD 0x00000040 +#define BFL2_BTC3WIRE 0x00000080 +#define BFL2_BTCLEGACY 0x00000080 +#define BFL2_SKWRKFEM_BRD 0x00000100 +#define BFL2_SPUR_WAR 0x00000200 +#define BFL2_GPLL_WAR 0x00000400 +#define BFL2_TRISTATE_LED 0x00000800 +#define BFL2_SINGLEANT_CCK 0x00001000 +#define BFL2_2G_SPUR_WAR 0x00002000 +#define BFL2_BPHY_ALL_TXCORES 0x00004000 +#define BFL2_FCC_BANDEDGE_WAR 0x00008000 +#define BFL2_DAC_SPUR_IMPROVEMENT 0x00008000 +#define BFL2_GPLL_WAR2 0x00010000 +#define BFL2_IPALVLSHIFT_3P3 0x00020000 +#define BFL2_INTERNDET_TXIQCAL 0x00040000 +#define BFL2_XTALBUFOUTEN 0x00080000 + + + +#define BFL2_ANAPACTRL_2G 0x00100000 +#define BFL2_ANAPACTRL_5G 0x00200000 +#define BFL2_ELNACTRL_TRSW_2G 0x00400000 +#define BFL2_BT_SHARE_ANT0 0x00800000 +#define BFL2_TEMPSENSE_HIGHER 0x01000000 +#define BFL2_BTC3WIREONLY 0x02000000 +#define BFL2_PWR_NOMINAL 0x04000000 +#define BFL2_EXTLNA_PWRSAVE 0x08000000 + +#define BFL2_4313_RADIOREG 0x10000000 + +#define BFL2_DYNAMIC_VMID 0x10000000 + +#define BFL2_SDR_EN 0x20000000 +#define BFL2_DYNAMIC_VMID 0x10000000 +#define BFL2_LNA1BYPFORTR2G 0x40000000 +#define BFL2_LNA1BYPFORTR5G 0x80000000 + + +#define BFL_SROM11_BTCOEX 0x00000001 +#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 +#define BFL_SROM11_EXTLNA 0x00001000 +#define BFL_SROM11_EXTLNA_5GHz 0x10000000 +#define BFL_SROM11_GAINBOOSTA01 0x20000000 +#define BFL2_SROM11_APLL_WAR 0x00000002 +#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 +#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 +#define BFL2_SROM11_SINGLEANT_CCK 0x00001000 + + +#define BFL3_FEMCTRL_SUB 0x00000007 +#define BFL3_RCAL_WAR 0x00000008 +#define BFL3_TXGAINTBLID 0x00000070 +#define BFL3_TXGAINTBLID_SHIFT 0x4 +#define BFL3_TSSI_DIV_WAR 0x00000080 +#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 +#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 +#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 +#define BFL3_AGC_CFG_2G 0x00000200 +#define BFL3_AGC_CFG_5G 0x00000400 +#define BFL3_PPR_BIT_EXT 0x00000800 +#define BFL3_PPR_BIT_EXT_SHIFT 11 +#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 +#define BFL3_RCAL_OTP_VAL_EN 0x00002000 +#define BFL3_2GTXGAINTBL_BLANK 0x00004000 +#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 +#define BFL3_5GTXGAINTBL_BLANK 0x00008000 +#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 +#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 +#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 + +#define BFL3_LTECOEX_GAINTBL_EN 0x00060000 + +#define BFL3_LTECOEX_GAINTBL_EN_SHIFT 17 +#define BFL3_5G_SPUR_WAR 0x00080000 + + +#define BFL3_ACPHY_LPMODE_2G 0x00300000 +#define BFL3_ACPHY_LPMODE_2G_SHIFT 20 + +#define BFL3_ACPHY_LPMODE_5G 0x00C00000 +#define BFL3_ACPHY_LPMODE_5G_SHIFT 22 + +#define BFL3_EXT_LPO_ISCLOCK 0x02000000 +#define BFL3_FORCE_INT_LPO_SEL 0x04000000 +#define BFL3_FORCE_EXT_LPO_SEL 0x08000000 + +#define BFL3_EN_BRCM_IMPBF 0x10000000 +#define BFL3_AVVMID_FROM_NVRAM 0x40000000 +#define BFL3_VLIN_EN_FROM_NVRAM 0x80000000 + +#define BFL3_AVVMID_FROM_NVRAM_SHIFT 30 +#define BFL3_VLIN_EN_FROM_NVRAM_SHIFT 31 + + + +#define BOARD_GPIO_BTC3W_IN 0x850 +#define BOARD_GPIO_BTC3W_OUT 0x020 +#define BOARD_GPIO_BTCMOD_IN 0x010 +#define BOARD_GPIO_BTCMOD_OUT 0x020 +#define BOARD_GPIO_BTC_IN 0x080 +#define BOARD_GPIO_BTC_OUT 0x100 +#define BOARD_GPIO_PACTRL 0x200 +#define BOARD_GPIO_12 0x1000 +#define BOARD_GPIO_13 0x2000 +#define BOARD_GPIO_BTC4_IN 0x0800 +#define BOARD_GPIO_BTC4_BT 0x2000 +#define BOARD_GPIO_BTC4_STAT 0x4000 +#define BOARD_GPIO_BTC4_WLAN 0x8000 +#define BOARD_GPIO_1_WLAN_PWR 0x02 +#define BOARD_GPIO_2_WLAN_PWR 0x04 +#define BOARD_GPIO_3_WLAN_PWR 0x08 +#define BOARD_GPIO_4_WLAN_PWR 0x10 + +#define GPIO_BTC4W_OUT_4312 0x010 +#define GPIO_BTC4W_OUT_43224 0x020 +#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 +#define GPIO_BTC4W_OUT_43225 0x0e0 +#define GPIO_BTC4W_OUT_43421 0x020 +#define GPIO_BTC4W_OUT_4313 0x060 +#define GPIO_BTC4W_OUT_4331_SHARED 0x010 + +#define PCI_CFG_GPIO_SCS 0x10 +#define PCI_CFG_GPIO_HWRAD 0x20 +#define PCI_CFG_GPIO_XTAL 0x40 +#define PCI_CFG_GPIO_PLL 0x80 + + +#define PLL_DELAY 150 +#define FREF_DELAY 200 +#define MIN_SLOW_CLK 32 +#define XTAL_ON_DELAY 1000 + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +#define BU4710_BOARD 0x0400 +#define VSIM4710_BOARD 0x0401 +#define QT4710_BOARD 0x0402 + +#define BU4309_BOARD 0x040a +#define BCM94309CB_BOARD 0x040b +#define BCM94309MP_BOARD 0x040c +#define BCM4309AP_BOARD 0x040d + +#define BCM94302MP_BOARD 0x040e + +#define BU4306_BOARD 0x0416 +#define BCM94306CB_BOARD 0x0417 +#define BCM94306MP_BOARD 0x0418 + +#define BCM94710D_BOARD 0x041a +#define BCM94710R1_BOARD 0x041b +#define BCM94710R4_BOARD 0x041c +#define BCM94710AP_BOARD 0x041d + +#define BU2050_BOARD 0x041f + +#define BCM94306P50_BOARD 0x0420 + +#define BCM94309G_BOARD 0x0421 + +#define BU4704_BOARD 0x0423 +#define BU4702_BOARD 0x0424 + +#define BCM94306PC_BOARD 0x0425 + +#define MPSG4306_BOARD 0x0427 + +#define BCM94702MN_BOARD 0x0428 + + +#define BCM94702CPCI_BOARD 0x0429 + + +#define BCM95380RR_BOARD 0x042a + + +#define BCM94306CBSG_BOARD 0x042b + + +#define PCSG94306_BOARD 0x042d + + +#define BU4704SD_BOARD 0x042e + + +#define BCM94704AGR_BOARD 0x042f + + +#define BCM94308MP_BOARD 0x0430 + + +#define BCM94306GPRS_BOARD 0x0432 + + +#define BU5365_FPGA_BOARD 0x0433 + +#define BU4712_BOARD 0x0444 +#define BU4712SD_BOARD 0x045d +#define BU4712L_BOARD 0x045f + + +#define BCM94712AP_BOARD 0x0445 +#define BCM94712P_BOARD 0x0446 + + +#define BU4318_BOARD 0x0447 +#define CB4318_BOARD 0x0448 +#define MPG4318_BOARD 0x0449 +#define MP4318_BOARD 0x044a +#define SD4318_BOARD 0x044b + + +#define BCM94313BU_BOARD 0x050f +#define BCM94313HM_BOARD 0x0510 +#define BCM94313EPA_BOARD 0x0511 +#define BCM94313HMG_BOARD 0x051C + + +#define BCM96338_BOARD 0x6338 +#define BCM96348_BOARD 0x6348 +#define BCM96358_BOARD 0x6358 +#define BCM96368_BOARD 0x6368 + + +#define BCM94306P_BOARD 0x044c + + +#define BCM94303MP_BOARD 0x044e + + +#define BCM94306MPSGH_BOARD 0x044f + + +#define BCM94306MPM 0x0450 +#define BCM94306MPL 0x0453 + + +#define BCM94712AGR_BOARD 0x0451 + + +#define PC4303_BOARD 0x0454 + + +#define BCM95350K_BOARD 0x0455 + + +#define BCM95350R_BOARD 0x0456 + + +#define BCM94306MPLNA_BOARD 0x0457 + + +#define BU4320_BOARD 0x0458 +#define BU4320S_BOARD 0x0459 +#define BCM94320PH_BOARD 0x045a + + +#define BCM94306MPH_BOARD 0x045b + + +#define BCM94306PCIV_BOARD 0x045c + +#define BU4712SD_BOARD 0x045d + +#define BCM94320PFLSH_BOARD 0x045e + +#define BU4712L_BOARD 0x045f +#define BCM94712LGR_BOARD 0x0460 +#define BCM94320R_BOARD 0x0461 + +#define BU5352_BOARD 0x0462 + +#define BCM94318MPGH_BOARD 0x0463 + +#define BU4311_BOARD 0x0464 +#define BCM94311MC_BOARD 0x0465 +#define BCM94311MCAG_BOARD 0x0466 + +#define BCM95352GR_BOARD 0x0467 + + +#define BCM95351AGR_BOARD 0x0470 + + +#define BCM94704MPCB_BOARD 0x0472 + + +#define BU4785_BOARD 0x0478 + + +#define BU4321_BOARD 0x046b +#define BU4321E_BOARD 0x047c +#define MP4321_BOARD 0x046c +#define CB2_4321_BOARD 0x046d +#define CB2_4321_AG_BOARD 0x0066 +#define MC4321_BOARD 0x046e + + +#define BU4328_BOARD 0x0481 +#define BCM4328SDG_BOARD 0x0482 +#define BCM4328SDAG_BOARD 0x0483 +#define BCM4328UG_BOARD 0x0484 +#define BCM4328UAG_BOARD 0x0485 +#define BCM4328PC_BOARD 0x0486 +#define BCM4328CF_BOARD 0x0487 + + +#define BCM94325DEVBU_BOARD 0x0490 +#define BCM94325BGABU_BOARD 0x0491 + +#define BCM94325SDGWB_BOARD 0x0492 + +#define BCM94325SDGMDL_BOARD 0x04aa +#define BCM94325SDGMDL2_BOARD 0x04c6 +#define BCM94325SDGMDL3_BOARD 0x04c9 + +#define BCM94325SDABGWBA_BOARD 0x04e1 + + +#define BCM94322MC_SSID 0x04a4 +#define BCM94322USB_SSID 0x04a8 +#define BCM94322HM_SSID 0x04b0 +#define BCM94322USB2D_SSID 0x04bf + + +#define BCM4312MCGSG_BOARD 0x04b5 + + +#define BCM94315DEVBU_SSID 0x04c2 +#define BCM94315USBGP_SSID 0x04c7 +#define BCM94315BGABU_SSID 0x04ca +#define BCM94315USBGP41_SSID 0x04cb + + +#define BCM94319DEVBU_SSID 0X04e5 +#define BCM94319USB_SSID 0X04e6 +#define BCM94319SD_SSID 0X04e7 + + +#define BCM94716NR2_SSID 0x04cd + + +#define BCM94319DEVBU_SSID 0X04e5 +#define BCM94319USBNP4L_SSID 0X04e6 +#define BCM94319WLUSBN4L_SSID 0X04e7 +#define BCM94319SDG_SSID 0X04ea +#define BCM94319LCUSBSDN4L_SSID 0X04eb +#define BCM94319USBB_SSID 0x04ee +#define BCM94319LCSDN4L_SSID 0X0507 +#define BCM94319LSUSBN4L_SSID 0X0508 +#define BCM94319SDNA4L_SSID 0X0517 +#define BCM94319SDELNA4L_SSID 0X0518 +#define BCM94319SDELNA6L_SSID 0X0539 +#define BCM94319ARCADYAN_SSID 0X0546 +#define BCM94319WINDSOR_SSID 0x0561 +#define BCM94319MLAP_SSID 0x0562 +#define BCM94319SDNA_SSID 0x058b +#define BCM94319BHEMU3_SSID 0x0563 +#define BCM94319SDHMB_SSID 0x058c +#define BCM94319SDBREF_SSID 0x05a1 +#define BCM94319USBSDB_SSID 0x05a2 + + + +#define BCM94329AGB_SSID 0X04b9 +#define BCM94329TDKMDL1_SSID 0X04ba +#define BCM94329TDKMDL11_SSID 0X04fc +#define BCM94329OLYMPICN18_SSID 0X04fd +#define BCM94329OLYMPICN90_SSID 0X04fe +#define BCM94329OLYMPICN90U_SSID 0X050c +#define BCM94329OLYMPICN90M_SSID 0X050b +#define BCM94329AGBF_SSID 0X04ff +#define BCM94329OLYMPICX17_SSID 0X0504 +#define BCM94329OLYMPICX17M_SSID 0X050a +#define BCM94329OLYMPICX17U_SSID 0X0509 +#define BCM94329OLYMPICUNO_SSID 0X0564 +#define BCM94329MOTOROLA_SSID 0X0565 +#define BCM94329OLYMPICLOCO_SSID 0X0568 + +#define BCM94336SD_WLBGABU_SSID 0x0511 +#define BCM94336SD_WLBGAREF_SSID 0x0519 +#define BCM94336SDGP_SSID 0x0538 +#define BCM94336SDG_SSID 0x0519 +#define BCM94336SDGN_SSID 0x0538 +#define BCM94336SDGFC_SSID 0x056B + + +#define BCM94330SDG_SSID 0x0528 +#define BCM94330SD_FCBGABU_SSID 0x052e +#define BCM94330SD_WLBGABU_SSID 0x052f +#define BCM94330SD_FCBGA_SSID 0x0530 +#define BCM94330FCSDAGB_SSID 0x0532 +#define BCM94330OLYMPICAMG_SSID 0x0549 +#define BCM94330OLYMPICAMGEPA_SSID 0x054F +#define BCM94330OLYMPICUNO3_SSID 0x0551 +#define BCM94330WLSDAGB_SSID 0x0547 +#define BCM94330CSPSDAGBB_SSID 0x054A + + +#define BCM943224X21 0x056e +#define BCM943224X21_FCC 0x00d1 +#define BCM943224X21B 0x00e9 +#define BCM943224M93 0x008b +#define BCM943224M93A 0x0090 +#define BCM943224X16 0x0093 +#define BCM94322X9 0x008d +#define BCM94322M35e 0x008e + + +#define BCM943228BU8_SSID 0x0540 +#define BCM943228BU9_SSID 0x0541 +#define BCM943228BU_SSID 0x0542 +#define BCM943227HM4L_SSID 0x0543 +#define BCM943227HMB_SSID 0x0544 +#define BCM943228HM4L_SSID 0x0545 +#define BCM943228SD_SSID 0x0573 + + +#define BCM943239MOD_SSID 0x05ac +#define BCM943239REF_SSID 0x05aa + + +#define BCM94331X19 0x00D6 +#define BCM94331X28 0x00E4 +#define BCM94331X28B 0x010E +#define BCM94331PCIEBT3Ax_SSID BCM94331X28 +#define BCM94331X12_2G_SSID 0x00EC +#define BCM94331X12_5G_SSID 0x00ED +#define BCM94331X29B 0x00EF +#define BCM94331X29D 0x010F +#define BCM94331CSAX_SSID BCM94331X29B +#define BCM94331X19C 0x00F5 +#define BCM94331X33 0x00F4 +#define BCM94331BU_SSID 0x0523 +#define BCM94331S9BU_SSID 0x0524 +#define BCM94331MC_SSID 0x0525 +#define BCM94331MCI_SSID 0x0526 +#define BCM94331PCIEBT4_SSID 0x0527 +#define BCM94331HM_SSID 0x0574 +#define BCM94331PCIEDUAL_SSID 0x059B +#define BCM94331MCH5_SSID 0x05A9 +#define BCM94331CS_SSID 0x05C6 +#define BCM94331CD_SSID 0x05DA + + +#define BCM94314BU_SSID 0x05b1 + + +#define BCM953572BU_SSID 0x058D +#define BCM953572NR2_SSID 0x058E +#define BCM947188NR2_SSID 0x058F +#define BCM953572SDRNR2_SSID 0x0590 + + +#define BCM943236OLYMPICSULLEY_SSID 0x594 +#define BCM943236PREPROTOBLU2O3_SSID 0x5b9 +#define BCM943236USBELNA_SSID 0x5f8 + + +#define BCM94314BUSDIO_SSID 0x05c8 +#define BCM94314BGABU_SSID 0x05c9 +#define BCM94314HMEPA_SSID 0x05ca +#define BCM94314HMEPABK_SSID 0x05cb +#define BCM94314SUHMEPA_SSID 0x05cc +#define BCM94314SUHM_SSID 0x05cd +#define BCM94314HM_SSID 0x05d1 + + +#define BCM94334FCAGBI_SSID 0x05df +#define BCM94334WLAGBI_SSID 0x05dd + + +#define BCM94335X52 0x0114 + + +#define BCM94345_SSID 0x0687 + + +#define BCM94360X52C 0X0117 +#define BCM94360X52D 0X0137 +#define BCM94360X29C 0X0112 +#define BCM94360X29CP2 0X1000 +#define BCM94360X51 0x0111 +#define BCM94360X51P2 0x0129 +#define BCM94360X51A 0x0135 +#define BCM94360X51B 0x0136 +#define BCM94360CS 0x061B +#define BCM94360J28_D11AC2G 0x0c00 +#define BCM94360J28_D11AC5G 0x0c01 + + +#define BCM94350X52B 0X0116 + + +#define BCM943217BU_SSID 0x05d5 +#define BCM943217HM2L_SSID 0x05d6 +#define BCM943217HMITR2L_SSID 0x05d7 + + +#define BCM943142HM_SSID 0x05e0 +#endif + + +#define BCM943341WLABGS_SSID 0x062d + + +#define BCM943342FCAGBI_SSID 0x0641 + + +#define BCM943602RSVD1_SSID 0x06a5 +#define BCM943602RSVD2_SSID 0x06a6 + + +#define GPIO_NUMPINS 32 + + +#define RDL_RAM_BASE_4319 0x60000000 +#define RDL_RAM_BASE_4329 0x60000000 +#define RDL_RAM_SIZE_4319 0x48000 +#define RDL_RAM_SIZE_4329 0x48000 +#define RDL_RAM_SIZE_43236 0x70000 +#define RDL_RAM_BASE_43236 0x60000000 +#define RDL_RAM_SIZE_4328 0x60000 +#define RDL_RAM_BASE_4328 0x80000000 +#define RDL_RAM_SIZE_4322 0x60000 +#define RDL_RAM_BASE_4322 0x60000000 +#define RDL_RAM_SIZE_4360 0xA0000 +#define RDL_RAM_BASE_4360 0x60000000 +#define RDL_RAM_SIZE_43242 0x90000 +#define RDL_RAM_BASE_43242 0x60000000 +#define RDL_RAM_SIZE_43143 0x70000 +#define RDL_RAM_BASE_43143 0x60000000 +#define RDL_RAM_SIZE_4350 0xC0000 +#define RDL_RAM_BASE_4350 0x180800 + + +#define MUXENAB_UART 0x00000001 +#define MUXENAB_GPIO 0x00000002 +#define MUXENAB_ERCX 0x00000004 +#define MUXENAB_JTAG 0x00000008 +#define MUXENAB_HOST_WAKE 0x00000010 +#define MUXENAB_I2S_EN 0x00000020 +#define MUXENAB_I2S_MASTER 0x00000040 +#define MUXENAB_I2S_FULL 0x00000080 +#define MUXENAB_SFLASH 0x00000100 +#define MUXENAB_RFSWCTRL0 0x00000200 +#define MUXENAB_RFSWCTRL1 0x00000400 +#define MUXENAB_RFSWCTRL2 0x00000800 +#define MUXENAB_SECI 0x00001000 +#define MUXENAB_BT_LEGACY 0x00002000 +#define MUXENAB_HOST_WAKE1 0x00004000 + + +#define FLASH_KERNEL_NFLASH 0x00000001 +#define FLASH_BOOT_NFLASH 0x00000002 + +#endif
diff --git a/src/include/bcmendian.h b/src/include/bcmendian.h new file mode 100644 index 0000000..8a510d0 --- /dev/null +++ b/src/include/bcmendian.h
@@ -0,0 +1,290 @@ +/* + * Byte order utilities + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmendian.h 402715 2013-05-16 18:50:09Z $ + * + * This file by default provides proper behavior on little-endian architectures. + * On big-endian architectures, IL_BIGENDIAN should be defined. + */ + +#ifndef _BCMENDIAN_H_ +#define _BCMENDIAN_H_ + +#include <typedefs.h> + + +#define BCMSWAP16(val) \ + ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ + (((uint16)(val) & (uint16)0xff00U) >> 8))) + + +#define BCMSWAP32(val) \ + ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ + (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ + (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ + (((uint32)(val) & (uint32)0xff000000U) >> 24))) + + +#define BCMSWAP32BY16(val) \ + ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ + (((uint32)(val) & (uint32)0xffff0000U) >> 16))) + + +#define BCMSWAP64(val) \ + ((uint64)((((uint64)(val) & 0x00000000000000ffULL) << 56) | \ + (((uint64)(val) & 0x000000000000ff00ULL) << 40) | \ + (((uint64)(val) & 0x0000000000ff0000ULL) << 24) | \ + (((uint64)(val) & 0x00000000ff000000ULL) << 8) | \ + (((uint64)(val) & 0x000000ff00000000ULL) >> 8) | \ + (((uint64)(val) & 0x0000ff0000000000ULL) >> 24) | \ + (((uint64)(val) & 0x00ff000000000000ULL) >> 40) | \ + (((uint64)(val) & 0xff00000000000000ULL) >> 56))) + + +#define BCMSWAP64BY32(val) \ + ((uint64)((((uint64)(val) & 0x00000000ffffffffULL) << 32) | \ + (((uint64)(val) & 0xffffffff00000000ULL) >> 32))) + + + +#ifndef hton16 +#define HTON16(i) BCMSWAP16(i) +#define hton16(i) bcmswap16(i) +#define HTON32(i) BCMSWAP32(i) +#define hton32(i) bcmswap32(i) +#define NTOH16(i) BCMSWAP16(i) +#define ntoh16(i) bcmswap16(i) +#define NTOH32(i) BCMSWAP32(i) +#define ntoh32(i) bcmswap32(i) +#define LTOH16(i) (i) +#define ltoh16(i) (i) +#define LTOH32(i) (i) +#define ltoh32(i) (i) +#define HTOL16(i) (i) +#define htol16(i) (i) +#define HTOL32(i) (i) +#define htol32(i) (i) +#define HTOL64(i) (i) +#define htol64(i) (i) +#endif + +#define ltoh16_buf(buf, i) +#define htol16_buf(buf, i) + + +#define load32_ua(a) ltoh32_ua(a) +#define store32_ua(a, v) htol32_ua_store(v, a) +#define load16_ua(a) ltoh16_ua(a) +#define store16_ua(a, v) htol16_ua_store(v, a) + +#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) +#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) +#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) +#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) + +#define ltoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#define ntoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#ifdef __GNUC__ + + + +#define bcmswap16(val) ({ \ + uint16 _val = (val); \ + BCMSWAP16(_val); \ +}) + +#define bcmswap32(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32(_val); \ +}) + +#define bcmswap64(val) ({ \ + uint64 _val = (val); \ + BCMSWAP64(_val); \ +}) + +#define bcmswap32by16(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32BY16(_val); \ +}) + +#define bcmswap16_buf(buf, len) ({ \ + uint16 *_buf = (uint16 *)(buf); \ + uint _wds = (len) / 2; \ + while (_wds--) { \ + *_buf = bcmswap16(*_buf); \ + _buf++; \ + } \ +}) + +#define htol16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = _val >> 8; \ +}) + +#define htol32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = (_val >> 8) & 0xff; \ + _bytes[2] = (_val >> 16) & 0xff; \ + _bytes[3] = _val >> 24; \ +}) + +#define hton16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 8; \ + _bytes[1] = _val & 0xff; \ +}) + +#define hton32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 24; \ + _bytes[1] = (_val >> 16) & 0xff; \ + _bytes[2] = (_val >> 8) & 0xff; \ + _bytes[3] = _val & 0xff; \ +}) + +#define ltoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH16_UA(_bytes); \ +}) + +#define ltoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH32_UA(_bytes); \ +}) + +#define ntoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH16_UA(_bytes); \ +}) + +#define ntoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH32_UA(_bytes); \ +}) + +#else + + +static INLINE uint16 +bcmswap16(uint16 val) +{ + return BCMSWAP16(val); +} + +static INLINE uint32 +bcmswap32(uint32 val) +{ + return BCMSWAP32(val); +} + +static INLINE uint64 +bcmswap64(uint64 val) +{ + return BCMSWAP64(val); +} + +static INLINE uint32 +bcmswap32by16(uint32 val) +{ + return BCMSWAP32BY16(val); +} + + + + +static INLINE void +bcmswap16_buf(uint16 *buf, uint len) +{ + len = len / 2; + + while (len--) { + *buf = bcmswap16(*buf); + buf++; + } +} + + +static INLINE void +htol16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val & 0xff; + bytes[1] = val >> 8; +} + + +static INLINE void +htol32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val & 0xff; + bytes[1] = (val >> 8) & 0xff; + bytes[2] = (val >> 16) & 0xff; + bytes[3] = val >> 24; +} + + +static INLINE void +hton16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val >> 8; + bytes[1] = val & 0xff; +} + + +static INLINE void +hton32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val >> 24; + bytes[1] = (val >> 16) & 0xff; + bytes[2] = (val >> 8) & 0xff; + bytes[3] = val & 0xff; +} + + +static INLINE uint16 +ltoh16_ua(const void *bytes) +{ + return _LTOH16_UA((const uint8 *)bytes); +} + + +static INLINE uint32 +ltoh32_ua(const void *bytes) +{ + return _LTOH32_UA((const uint8 *)bytes); +} + + +static INLINE uint16 +ntoh16_ua(const void *bytes) +{ + return _NTOH16_UA((const uint8 *)bytes); +} + + +static INLINE uint32 +ntoh32_ua(const void *bytes) +{ + return _NTOH32_UA((const uint8 *)bytes); +} + +#endif +#endif
diff --git a/src/include/bcmnvram.h b/src/include/bcmnvram.h new file mode 100644 index 0000000..8182480 --- /dev/null +++ b/src/include/bcmnvram.h
@@ -0,0 +1,181 @@ +/* + * NVRAM variable manipulation + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmnvram.h 428512 2013-10-09 02:12:11Z $ + */ + +#ifndef _bcmnvram_h_ +#define _bcmnvram_h_ + +#ifndef _LANGUAGE_ASSEMBLY + +#include <typedefs.h> +#include <bcmdefs.h> + +struct nvram_header { + uint32 magic; + uint32 len; + uint32 crc_ver_init; + uint32 config_refresh; + uint32 config_ncdl; +}; + +struct nvram_tuple { + char *name; + char *value; + struct nvram_tuple *next; +}; + + +extern char *nvram_default_get(const char *name); + +extern void nvram_validate_all(char *prefix, bool restore); + + +extern void nvram_restore_var(char *prefix, char *name); + + +extern int nvram_init(void *sih); +extern int nvram_deinit(void *sih); + + + +extern int nvram_append(void *si, char *vars, uint varsz); + +extern void nvram_get_global_vars(char **varlst, uint *varsz); + + + +extern int nvram_reset(void *sih); + + +extern void nvram_exit(void *sih); + + +extern char * nvram_get(const char *name); + + +extern int BCMINITFN(nvram_resetgpio_init)(void *sih); + + +static INLINE char * +nvram_safe_get(const char *name) +{ + char *p = nvram_get(name); + return p ? p : ""; +} + + +static INLINE int +nvram_match(const char *name, const char *match) +{ + const char *value = nvram_get(name); + return (value && !strcmp(value, match)); +} + + +static INLINE int +nvram_invmatch(const char *name, const char *invmatch) +{ + const char *value = nvram_get(name); + return (value && strcmp(value, invmatch)); +} + + +extern int nvram_set(const char *name, const char *value); + + +extern int nvram_unset(const char *name); + + +extern int nvram_commit_internal(bool nvram_corrupt); + + +extern int nvram_commit(void); + + +extern int nvram_getall(char *nvram_buf, int count); + + +uint8 nvram_calc_crc(struct nvram_header * nvh); + +extern int nvram_space; +#endif + + +#define NVRAM_SOFTWARE_VERSION "1" + +#define NVRAM_MAGIC 0x48534C46 +#define NVRAM_CLEAR_MAGIC 0x0 +#define NVRAM_INVALID_MAGIC 0xFFFFFFFF +#define NVRAM_VERSION 1 +#define NVRAM_HEADER_SIZE 20 + +#define NVRAM_SPACE 0x8000 + +#ifndef MAX_NVRAM_SPACE +#define MAX_NVRAM_SPACE 0x10000 +#endif +#define DEF_NVRAM_SPACE 0x8000 +#define ROM_ENVRAM_SPACE 0x1000 +#define NVRAM_LZMA_MAGIC 0x4c5a4d41 + +#define NVRAM_MAX_VALUE_LEN 255 +#define NVRAM_MAX_PARAM_LEN 64 + +#define NVRAM_CRC_START_POSITION 9 +#define NVRAM_CRC_VER_MASK 0xffffff00 + + +#define NVRAM_START_COMPRESSED 0x400 +#define NVRAM_START 0x1000 + +#define BCM_JUMBO_NVRAM_DELIMIT '\n' +#define BCM_JUMBO_START "Broadcom Jumbo Nvram file" + + +#if (defined(FAILSAFE_UPGRADE) || defined(CONFIG_FAILSAFE_UPGRADE) || \ + defined(__CONFIG_FAILSAFE_UPGRADE_SUPPORT__)) +#define IMAGE_SIZE "image_size" +#define BOOTPARTITION "bootpartition" +#define IMAGE_BOOT BOOTPARTITION +#define PARTIALBOOTS "partialboots" +#define MAXPARTIALBOOTS "maxpartialboots" +#define IMAGE_1ST_FLASH_TRX "flash0.trx" +#define IMAGE_1ST_FLASH_OS "flash0.os" +#define IMAGE_2ND_FLASH_TRX "flash0.trx2" +#define IMAGE_2ND_FLASH_OS "flash0.os2" +#define IMAGE_FIRST_OFFSET "image_first_offset" +#define IMAGE_SECOND_OFFSET "image_second_offset" +#define LINUX_FIRST "linux" +#define LINUX_SECOND "linux2" +#endif + +#if (defined(DUAL_IMAGE) || defined(CONFIG_DUAL_IMAGE) || \ + defined(__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__)) + +#define IMAGE_BOOT "image_boot" +#define BOOTPARTITION IMAGE_BOOT + +#define IMAGE_1ST_FLASH_TRX "flash0.trx" +#define IMAGE_1ST_FLASH_OS "flash0.os" +#define IMAGE_2ND_FLASH_TRX "flash0.trx2" +#define IMAGE_2ND_FLASH_OS "flash0.os2" +#define IMAGE_SIZE "image_size" + + +#define IMAGE_FIRST_OFFSET "image_first_offset" +#define IMAGE_SECOND_OFFSET "image_second_offset" + + +#define LINUX_FIRST "linux" +#define LINUX_SECOND "linux2" +#define POLICY_TOGGLE "toggle" +#define LINUX_PART_TO_FLASH "linux_to_flash" +#define LINUX_FLASH_POLICY "linux_flash_policy" + +#endif + +#endif
diff --git a/src/include/bcmsrom_fmt.h b/src/include/bcmsrom_fmt.h new file mode 100644 index 0000000..d5ac414 --- /dev/null +++ b/src/include/bcmsrom_fmt.h
@@ -0,0 +1,615 @@ +/* + * SROM format definition. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmsrom_fmt.h 427005 2013-10-02 00:15:10Z $ + */ + +#ifndef _bcmsrom_fmt_h_ +#define _bcmsrom_fmt_h_ + +#define SROM_MAXREV 11 /* max revisiton supported by driver */ + +/* Maximum srom: 6 Kilobits == 768 bytes */ +#define SROM_MAX 768 +#define SROM_MAXW 384 +#define VARS_MAX 4096 + +/* PCI fields */ +#define PCI_F0DEVID 48 + + +#define SROM_WORDS 64 + +#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */ + +#define SROM_SSID 2 +#define SROM_SVID 3 + +#define SROM_WL1LHMAXP 29 + +#define SROM_WL1LPAB0 30 +#define SROM_WL1LPAB1 31 +#define SROM_WL1LPAB2 32 + +#define SROM_WL1HPAB0 33 +#define SROM_WL1HPAB1 34 +#define SROM_WL1HPAB2 35 + +#define SROM_MACHI_IL0 36 +#define SROM_MACMID_IL0 37 +#define SROM_MACLO_IL0 38 +#define SROM_MACHI_ET0 39 +#define SROM_MACMID_ET0 40 +#define SROM_MACLO_ET0 41 +#define SROM_MACHI_ET1 42 +#define SROM_MACMID_ET1 43 +#define SROM_MACLO_ET1 44 +#define SROM3_MACHI 37 +#define SROM3_MACMID 38 +#define SROM3_MACLO 39 + +#define SROM_BXARSSI2G 40 +#define SROM_BXARSSI5G 41 + +#define SROM_TRI52G 42 +#define SROM_TRI5GHL 43 + +#define SROM_RXPO52G 45 + +#define SROM2_ENETPHY 45 + +#define SROM_AABREV 46 +/* Fields in AABREV */ +#define SROM_BR_MASK 0x00ff +#define SROM_CC_MASK 0x0f00 +#define SROM_CC_SHIFT 8 +#define SROM_AA0_MASK 0x3000 +#define SROM_AA0_SHIFT 12 +#define SROM_AA1_MASK 0xc000 +#define SROM_AA1_SHIFT 14 + +#define SROM_WL0PAB0 47 +#define SROM_WL0PAB1 48 +#define SROM_WL0PAB2 49 + +#define SROM_LEDBH10 50 +#define SROM_LEDBH32 51 + +#define SROM_WL10MAXP 52 + +#define SROM_WL1PAB0 53 +#define SROM_WL1PAB1 54 +#define SROM_WL1PAB2 55 + +#define SROM_ITT 56 + +#define SROM_BFL 57 +#define SROM_BFL2 28 +#define SROM3_BFL2 61 + +#define SROM_AG10 58 + +#define SROM_CCODE 59 + +#define SROM_OPO 60 + +#define SROM3_LEDDC 62 + +#define SROM_CRCREV 63 + +/* SROM Rev 4: Reallocate the software part of the srom to accomodate + * MIMO features. It assumes up to two PCIE functions and 440 bytes + * of useable srom i.e. the useable storage in chips with OTP that + * implements hardware redundancy. + */ + +#define SROM4_WORDS 220 + +#define SROM4_SIGN 32 +#define SROM4_SIGNATURE 0x5372 + +#define SROM4_BREV 33 + +#define SROM4_BFL0 34 +#define SROM4_BFL1 35 +#define SROM4_BFL2 36 +#define SROM4_BFL3 37 +#define SROM5_BFL0 37 +#define SROM5_BFL1 38 +#define SROM5_BFL2 39 +#define SROM5_BFL3 40 + +#define SROM4_MACHI 38 +#define SROM4_MACMID 39 +#define SROM4_MACLO 40 +#define SROM5_MACHI 41 +#define SROM5_MACMID 42 +#define SROM5_MACLO 43 + +#define SROM4_CCODE 41 +#define SROM4_REGREV 42 +#define SROM5_CCODE 34 +#define SROM5_REGREV 35 + +#define SROM4_LEDBH10 43 +#define SROM4_LEDBH32 44 +#define SROM5_LEDBH10 59 +#define SROM5_LEDBH32 60 + +#define SROM4_LEDDC 45 +#define SROM5_LEDDC 45 + +#define SROM4_AA 46 +#define SROM4_AA2G_MASK 0x00ff +#define SROM4_AA2G_SHIFT 0 +#define SROM4_AA5G_MASK 0xff00 +#define SROM4_AA5G_SHIFT 8 + +#define SROM4_AG10 47 +#define SROM4_AG32 48 + +#define SROM4_TXPID2G 49 +#define SROM4_TXPID5G 51 +#define SROM4_TXPID5GL 53 +#define SROM4_TXPID5GH 55 + +#define SROM4_TXRXC 61 +#define SROM4_TXCHAIN_MASK 0x000f +#define SROM4_TXCHAIN_SHIFT 0 +#define SROM4_RXCHAIN_MASK 0x00f0 +#define SROM4_RXCHAIN_SHIFT 4 +#define SROM4_SWITCH_MASK 0xff00 +#define SROM4_SWITCH_SHIFT 8 + + +/* Per-path fields */ +#define MAX_PATH_SROM 4 +#define SROM4_PATH0 64 +#define SROM4_PATH1 87 +#define SROM4_PATH2 110 +#define SROM4_PATH3 133 + +#define SROM4_2G_ITT_MAXP 0 +#define SROM4_2G_PA 1 +#define SROM4_5G_ITT_MAXP 5 +#define SROM4_5GLH_MAXP 6 +#define SROM4_5G_PA 7 +#define SROM4_5GL_PA 11 +#define SROM4_5GH_PA 15 + +/* Fields in the ITT_MAXP and 5GLH_MAXP words */ +#define B2G_MAXP_MASK 0xff +#define B2G_ITT_SHIFT 8 +#define B5G_MAXP_MASK 0xff +#define B5G_ITT_SHIFT 8 +#define B5GH_MAXP_MASK 0xff +#define B5GL_MAXP_SHIFT 8 + +/* All the miriad power offsets */ +#define SROM4_2G_CCKPO 156 +#define SROM4_2G_OFDMPO 157 +#define SROM4_5G_OFDMPO 159 +#define SROM4_5GL_OFDMPO 161 +#define SROM4_5GH_OFDMPO 163 +#define SROM4_2G_MCSPO 165 +#define SROM4_5G_MCSPO 173 +#define SROM4_5GL_MCSPO 181 +#define SROM4_5GH_MCSPO 189 +#define SROM4_CDDPO 197 +#define SROM4_STBCPO 198 +#define SROM4_BW40PO 199 +#define SROM4_BWDUPPO 200 + +#define SROM4_CRCREV 219 + + +/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6. + * This is acombined srom for both MIMO and SISO boards, usable in + * the .130 4Kilobit OTP with hardware redundancy. + */ + +#define SROM8_SIGN 64 + +#define SROM8_BREV 65 + +#define SROM8_BFL0 66 +#define SROM8_BFL1 67 +#define SROM8_BFL2 68 +#define SROM8_BFL3 69 + +#define SROM8_MACHI 70 +#define SROM8_MACMID 71 +#define SROM8_MACLO 72 + +#define SROM8_CCODE 73 +#define SROM8_REGREV 74 + +#define SROM8_LEDBH10 75 +#define SROM8_LEDBH32 76 + +#define SROM8_LEDDC 77 + +#define SROM8_AA 78 + +#define SROM8_AG10 79 +#define SROM8_AG32 80 + +#define SROM8_TXRXC 81 + +#define SROM8_BXARSSI2G 82 +#define SROM8_BXARSSI5G 83 +#define SROM8_TRI52G 84 +#define SROM8_TRI5GHL 85 +#define SROM8_RXPO52G 86 + +#define SROM8_FEM2G 87 +#define SROM8_FEM5G 88 +#define SROM8_FEM_ANTSWLUT_MASK 0xf800 +#define SROM8_FEM_ANTSWLUT_SHIFT 11 +#define SROM8_FEM_TR_ISO_MASK 0x0700 +#define SROM8_FEM_TR_ISO_SHIFT 8 +#define SROM8_FEM_PDET_RANGE_MASK 0x00f8 +#define SROM8_FEM_PDET_RANGE_SHIFT 3 +#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006 +#define SROM8_FEM_EXTPA_GAIN_SHIFT 1 +#define SROM8_FEM_TSSIPOS_MASK 0x0001 +#define SROM8_FEM_TSSIPOS_SHIFT 0 + +#define SROM8_THERMAL 89 + +/* Temp sense related entries */ +#define SROM8_MPWR_RAWTS 90 +#define SROM8_TS_SLP_OPT_CORRX 91 +/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */ +#define SROM8_FOC_HWIQ_IQSWP 92 + +#define SROM8_EXTLNAGAIN 93 + +/* Temperature delta for PHY calibration */ +#define SROM8_PHYCAL_TEMPDELTA 94 + +/* Measured power 1 & 2, 0-13 bits at offset 95, MSB 2 bits are unused for now. */ +#define SROM8_MPWR_1_AND_2 95 + + +/* Per-path offsets & fields */ +#define SROM8_PATH0 96 +#define SROM8_PATH1 112 +#define SROM8_PATH2 128 +#define SROM8_PATH3 144 + +#define SROM8_2G_ITT_MAXP 0 +#define SROM8_2G_PA 1 +#define SROM8_5G_ITT_MAXP 4 +#define SROM8_5GLH_MAXP 5 +#define SROM8_5G_PA 6 +#define SROM8_5GL_PA 9 +#define SROM8_5GH_PA 12 + +/* All the miriad power offsets */ +#define SROM8_2G_CCKPO 160 + +#define SROM8_2G_OFDMPO 161 +#define SROM8_5G_OFDMPO 163 +#define SROM8_5GL_OFDMPO 165 +#define SROM8_5GH_OFDMPO 167 + +#define SROM8_2G_MCSPO 169 +#define SROM8_5G_MCSPO 177 +#define SROM8_5GL_MCSPO 185 +#define SROM8_5GH_MCSPO 193 + +#define SROM8_CDDPO 201 +#define SROM8_STBCPO 202 +#define SROM8_BW40PO 203 +#define SROM8_BWDUPPO 204 + +/* SISO PA parameters are in the path0 spaces */ +#define SROM8_SISO 96 + +/* Legacy names for SISO PA paramters */ +#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP) +#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA) +#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1) +#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2) +#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP) +#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP) +#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA) +#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1) +#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2) +#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA) +#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1) +#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2) +#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA) +#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1) +#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2) + +#define SROM8_CRCREV 219 + +/* SROM REV 9 */ +#define SROM9_2GPO_CCKBW20 160 +#define SROM9_2GPO_CCKBW20UL 161 +#define SROM9_2GPO_LOFDMBW20 162 +#define SROM9_2GPO_LOFDMBW20UL 164 + +#define SROM9_5GLPO_LOFDMBW20 166 +#define SROM9_5GLPO_LOFDMBW20UL 168 +#define SROM9_5GMPO_LOFDMBW20 170 +#define SROM9_5GMPO_LOFDMBW20UL 172 +#define SROM9_5GHPO_LOFDMBW20 174 +#define SROM9_5GHPO_LOFDMBW20UL 176 + +#define SROM9_2GPO_MCSBW20 178 +#define SROM9_2GPO_MCSBW20UL 180 +#define SROM9_2GPO_MCSBW40 182 + +#define SROM9_5GLPO_MCSBW20 184 +#define SROM9_5GLPO_MCSBW20UL 186 +#define SROM9_5GLPO_MCSBW40 188 +#define SROM9_5GMPO_MCSBW20 190 +#define SROM9_5GMPO_MCSBW20UL 192 +#define SROM9_5GMPO_MCSBW40 194 +#define SROM9_5GHPO_MCSBW20 196 +#define SROM9_5GHPO_MCSBW20UL 198 +#define SROM9_5GHPO_MCSBW40 200 + +#define SROM9_PO_MCS32 202 +#define SROM9_PO_LOFDM40DUP 203 +#define SROM8_RXGAINERR_2G 205 +#define SROM8_RXGAINERR_5GL 206 +#define SROM8_RXGAINERR_5GM 207 +#define SROM8_RXGAINERR_5GH 208 +#define SROM8_RXGAINERR_5GU 209 +#define SROM8_SUBBAND_PPR 210 +#define SROM8_PCIEINGRESS_WAR 211 +#define SROM9_SAR 212 + +#define SROM8_NOISELVL_2G 213 +#define SROM8_NOISELVL_5GL 214 +#define SROM8_NOISELVL_5GM 215 +#define SROM8_NOISELVL_5GH 216 +#define SROM8_NOISELVL_5GU 217 +#define SROM8_NOISECALOFFSET 218 + +#define SROM9_REV_CRC 219 + +#define SROM10_CCKPWROFFSET 218 +#define SROM10_SIGN 219 +#define SROM10_SWCTRLMAP_2G 220 +#define SROM10_CRCREV 229 + +#define SROM10_WORDS 230 +#define SROM10_SIGNATURE SROM4_SIGNATURE + + +/* SROM REV 11 */ +#define SROM11_BREV 65 + +#define SROM11_BFL0 66 +#define SROM11_BFL1 67 +#define SROM11_BFL2 68 +#define SROM11_BFL3 69 +#define SROM11_BFL4 70 +#define SROM11_BFL5 71 + +#define SROM11_MACHI 72 +#define SROM11_MACMID 73 +#define SROM11_MACLO 74 + +#define SROM11_CCODE 75 +#define SROM11_REGREV 76 + +#define SROM11_LEDBH10 77 +#define SROM11_LEDBH32 78 + +#define SROM11_LEDDC 79 + +#define SROM11_AA 80 + +#define SROM11_AGBG10 81 +#define SROM11_AGBG2A0 82 +#define SROM11_AGA21 83 + +#define SROM11_TXRXC 84 + +#define SROM11_FEM_CFG1 85 +#define SROM11_FEM_CFG2 86 + +/* Masks and offsets for FEM_CFG */ +#define SROM11_FEMCTRL_MASK 0xf800 +#define SROM11_FEMCTRL_SHIFT 11 +#define SROM11_PAPDCAP_MASK 0x0400 +#define SROM11_PAPDCAP_SHIFT 10 +#define SROM11_TWORANGETSSI_MASK 0x0200 +#define SROM11_TWORANGETSSI_SHIFT 9 +#define SROM11_PDGAIN_MASK 0x01f0 +#define SROM11_PDGAIN_SHIFT 4 +#define SROM11_EPAGAIN_MASK 0x000e +#define SROM11_EPAGAIN_SHIFT 1 +#define SROM11_TSSIPOSSLOPE_MASK 0x0001 +#define SROM11_TSSIPOSSLOPE_SHIFT 0 +#define SROM11_GAINCTRLSPH_MASK 0xf800 +#define SROM11_GAINCTRLSPH_SHIFT 11 + +#define SROM11_THERMAL 87 +#define SROM11_MPWR_RAWTS 88 +#define SROM11_TS_SLP_OPT_CORRX 89 +#define SROM11_XTAL_FREQ 90 +#define SROM11_5GB0_4080_W0_A1 91 +#define SROM11_PHYCAL_TEMPDELTA 92 +#define SROM11_MPWR_1_AND_2 93 +#define SROM11_5GB0_4080_W1_A1 94 +#define SROM11_TSSIFLOOR_2G 95 +#define SROM11_TSSIFLOOR_5GL 96 +#define SROM11_TSSIFLOOR_5GM 97 +#define SROM11_TSSIFLOOR_5GH 98 +#define SROM11_TSSIFLOOR_5GU 99 + +/* Masks and offsets for Terrmal parameters */ +#define SROM11_TEMPS_PERIOD_MASK 0xf0 +#define SROM11_TEMPS_PERIOD_SHIFT 4 +#define SROM11_TEMPS_HYSTERESIS_MASK 0x0f +#define SROM11_TEMPS_HYSTERESIS_SHIFT 0 +#define SROM11_TEMPCORRX_MASK 0xfc +#define SROM11_TEMPCORRX_SHIFT 2 +#define SROM11_TEMPSENSE_OPTION_MASK 0x3 +#define SROM11_TEMPSENSE_OPTION_SHIFT 0 + +#define SROM11_PDOFF_2G_40M_A0_MASK 0x000f +#define SROM11_PDOFF_2G_40M_A0_SHIFT 0 +#define SROM11_PDOFF_2G_40M_A1_MASK 0x00f0 +#define SROM11_PDOFF_2G_40M_A1_SHIFT 4 +#define SROM11_PDOFF_2G_40M_A2_MASK 0x0f00 +#define SROM11_PDOFF_2G_40M_A2_SHIFT 8 +#define SROM11_PDOFF_2G_40M_VALID_MASK 0x8000 +#define SROM11_PDOFF_2G_40M_VALID_SHIFT 15 + +#define SROM11_PDOFF_2G_40M 100 +#define SROM11_PDOFF_40M_A0 101 +#define SROM11_PDOFF_40M_A1 102 +#define SROM11_PDOFF_40M_A2 103 +#define SROM11_5GB0_4080_W2_A1 103 +#define SROM11_PDOFF_80M_A0 104 +#define SROM11_PDOFF_80M_A1 105 +#define SROM11_PDOFF_80M_A2 106 +#define SROM11_5GB1_4080_W0_A1 106 + +#define SROM11_SUBBAND5GVER 107 + +/* Per-path fields and offset */ +#define MAX_PATH_SROM_11 3 +#define SROM11_PATH0 108 +#define SROM11_PATH1 128 +#define SROM11_PATH2 148 + +#define SROM11_2G_MAXP 0 +#define SROM11_5GB1_4080_PA 0 +#define SROM11_2G_PA 1 +#define SROM11_5GB2_4080_PA 2 +#define SROM11_RXGAINS1 4 +#define SROM11_RXGAINS 5 +#define SROM11_5GB3_4080_PA 5 +#define SROM11_5GB1B0_MAXP 6 +#define SROM11_5GB3B2_MAXP 7 +#define SROM11_5GB0_PA 8 +#define SROM11_5GB1_PA 11 +#define SROM11_5GB2_PA 14 +#define SROM11_5GB3_PA 17 + +/* Masks and offsets for rxgains */ +#define SROM11_RXGAINS5GTRELNABYPA_MASK 0x8000 +#define SROM11_RXGAINS5GTRELNABYPA_SHIFT 15 +#define SROM11_RXGAINS5GTRISOA_MASK 0x7800 +#define SROM11_RXGAINS5GTRISOA_SHIFT 11 +#define SROM11_RXGAINS5GELNAGAINA_MASK 0x0700 +#define SROM11_RXGAINS5GELNAGAINA_SHIFT 8 +#define SROM11_RXGAINS2GTRELNABYPA_MASK 0x0080 +#define SROM11_RXGAINS2GTRELNABYPA_SHIFT 7 +#define SROM11_RXGAINS2GTRISOA_MASK 0x0078 +#define SROM11_RXGAINS2GTRISOA_SHIFT 3 +#define SROM11_RXGAINS2GELNAGAINA_MASK 0x0007 +#define SROM11_RXGAINS2GELNAGAINA_SHIFT 0 +#define SROM11_RXGAINS5GHTRELNABYPA_MASK 0x8000 +#define SROM11_RXGAINS5GHTRELNABYPA_SHIFT 15 +#define SROM11_RXGAINS5GHTRISOA_MASK 0x7800 +#define SROM11_RXGAINS5GHTRISOA_SHIFT 11 +#define SROM11_RXGAINS5GHELNAGAINA_MASK 0x0700 +#define SROM11_RXGAINS5GHELNAGAINA_SHIFT 8 +#define SROM11_RXGAINS5GMTRELNABYPA_MASK 0x0080 +#define SROM11_RXGAINS5GMTRELNABYPA_SHIFT 7 +#define SROM11_RXGAINS5GMTRISOA_MASK 0x0078 +#define SROM11_RXGAINS5GMTRISOA_SHIFT 3 +#define SROM11_RXGAINS5GMELNAGAINA_MASK 0x0007 +#define SROM11_RXGAINS5GMELNAGAINA_SHIFT 0 + +/* Power per rate */ +#define SROM11_CCKBW202GPO 168 +#define SROM11_CCKBW20UL2GPO 169 +#define SROM11_MCSBW202GPO 170 +#define SROM11_MCSBW202GPO_1 171 +#define SROM11_MCSBW402GPO 172 +#define SROM11_MCSBW402GPO_1 173 +#define SROM11_DOT11AGOFDMHRBW202GPO 174 +#define SROM11_OFDMLRBW202GPO 175 + +#define SROM11_MCSBW205GLPO 176 +#define SROM11_MCSBW205GLPO_1 177 +#define SROM11_MCSBW405GLPO 178 +#define SROM11_MCSBW405GLPO_1 179 +#define SROM11_MCSBW805GLPO 180 +#define SROM11_MCSBW805GLPO_1 181 +#define SROM11_RPCAL_2G 182 +#define SROM11_RPCAL_5GL 183 +#define SROM11_MCSBW205GMPO 184 +#define SROM11_MCSBW205GMPO_1 185 +#define SROM11_MCSBW405GMPO 186 +#define SROM11_MCSBW405GMPO_1 187 +#define SROM11_MCSBW805GMPO 188 +#define SROM11_MCSBW805GMPO_1 189 +#define SROM11_RPCAL_5GM 190 +#define SROM11_RPCAL_5GH 191 +#define SROM11_MCSBW205GHPO 192 +#define SROM11_MCSBW205GHPO_1 193 +#define SROM11_MCSBW405GHPO 194 +#define SROM11_MCSBW405GHPO_1 195 +#define SROM11_MCSBW805GHPO 196 +#define SROM11_MCSBW805GHPO_1 197 +#define SROM11_RPCAL_5GU 198 +#define SROM11_PDOFF_2G_CCK 199 +#define SROM11_MCSLR5GLPO 200 +#define SROM11_MCSLR5GMPO 201 +#define SROM11_MCSLR5GHPO 202 + +#define SROM11_SB20IN40HRPO 203 +#define SROM11_SB20IN80AND160HR5GLPO 204 +#define SROM11_SB40AND80HR5GLPO 205 +#define SROM11_SB20IN80AND160HR5GMPO 206 +#define SROM11_SB40AND80HR5GMPO 207 +#define SROM11_SB20IN80AND160HR5GHPO 208 +#define SROM11_SB40AND80HR5GHPO 209 +#define SROM11_SB20IN40LRPO 210 +#define SROM11_SB20IN80AND160LR5GLPO 211 +#define SROM11_SB40AND80LR5GLPO 212 +#define SROM11_TXIDXCAP2G 212 +#define SROM11_SB20IN80AND160LR5GMPO 213 +#define SROM11_SB40AND80LR5GMPO 214 +#define SROM11_TXIDXCAP5G 214 +#define SROM11_SB20IN80AND160LR5GHPO 215 +#define SROM11_SB40AND80LR5GHPO 216 + +#define SROM11_DOT11AGDUPHRPO 217 +#define SROM11_DOT11AGDUPLRPO 218 + +/* MISC */ +#define SROM11_PCIEINGRESS_WAR 220 +#define SROM11_SAR 221 + +#define SROM11_NOISELVL_2G 222 +#define SROM11_NOISELVL_5GL 223 +#define SROM11_NOISELVL_5GM 224 +#define SROM11_NOISELVL_5GH 225 +#define SROM11_NOISELVL_5GU 226 + +#define SROM11_RXGAINERR_2G 227 +#define SROM11_RXGAINERR_5GL 228 +#define SROM11_RXGAINERR_5GM 229 +#define SROM11_RXGAINERR_5GH 230 +#define SROM11_RXGAINERR_5GU 231 + +#define SROM11_SIGN 64 +#define SROM11_CRCREV 233 + +#define SROM11_WORDS 234 +#define SROM11_SIGNATURE 0x0634 + +typedef struct { + uint8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */ + uint8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ + uint8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */ + uint8 triso; /* TR switch isolation */ + uint8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */ +} srom_fem_t; + +#endif /* _bcmsrom_fmt_h_ */
diff --git a/src/include/bcmsrom_tbl.h b/src/include/bcmsrom_tbl.h new file mode 100644 index 0000000..37067fd --- /dev/null +++ b/src/include/bcmsrom_tbl.h
@@ -0,0 +1,996 @@ +/* + * Table that encodes the srom formats for PCI/PCIe NICs. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmsrom_tbl.h 427005 2013-10-02 00:15:10Z $ + */ + +#ifndef _bcmsrom_tbl_h_ +#define _bcmsrom_tbl_h_ + +#include "sbpcmcia.h" +#include "wlioctl.h" + +typedef struct { + const char *name; + uint32 revmask; + uint32 flags; + uint16 off; + uint16 mask; +} sromvar_t; + +#define SRFL_MORE 1 /* value continues as described by the next entry */ +#define SRFL_NOFFS 2 /* value bits can't be all one's */ +#define SRFL_PRHEX 4 /* value is in hexdecimal format */ +#define SRFL_PRSIGN 8 /* value is in signed decimal format */ +#define SRFL_CCODE 0x10 /* value is in country code format */ +#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */ +#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */ +#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */ +#define SRFL_ARRAY 0x100 /* value is in an array. All elements EXCEPT FOR THE LAST + * ONE in the array should have this flag set. + */ + + +#define SROM_DEVID_PCIE 48 + +/* Assumptions: + * - Ethernet address spans across 3 consective words + * + * Table rules: + * - Add multiple entries next to each other if a value spans across multiple words + * (even multiple fields in the same word) with each entry except the last having + * it's SRFL_MORE bit set. + * - Ethernet address entry does not follow above rule and must not have SRFL_MORE + * bit set. Its SRFL_ETHADDR bit implies it takes multiple words. + * - The last entry's name field must be NULL to indicate the end of the table. Other + * entries must have non-NULL name. + */ + +static const sromvar_t BCMATTACHDATA(pci_sromvars)[] = { +#if defined(CABLECPE) + {"devid", 0xffffff00, SRFL_PRHEX, PCI_F0DEVID, 0xffff}, +#elif defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED) + {"devid", 0xffffff00, SRFL_PRHEX, SROM_DEVID_PCIE, 0xffff}, +#else + {"devid", 0xffffff00, SRFL_PRHEX|SRFL_NOVAR, PCI_F0DEVID, 0xffff}, +#endif + {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, + {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, + {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, + {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, + {"boardflags", 0x00000004, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM_BFL2, 0xffff}, + {"boardflags", 0x00000008, SRFL_PRHEX|SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM3_BFL2, 0xffff}, + {"boardflags", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL0, 0xffff}, + {"", 0, 0, SROM4_BFL1, 0xffff}, + {"boardflags", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL0, 0xffff}, + {"", 0, 0, SROM5_BFL1, 0xffff}, + {"boardflags", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL0, 0xffff}, + {"", 0, 0, SROM8_BFL1, 0xffff}, + {"boardflags2", 0x00000010, SRFL_PRHEX|SRFL_MORE, SROM4_BFL2, 0xffff}, + {"", 0, 0, SROM4_BFL3, 0xffff}, + {"boardflags2", 0x000000e0, SRFL_PRHEX|SRFL_MORE, SROM5_BFL2, 0xffff}, + {"", 0, 0, SROM5_BFL3, 0xffff}, + {"boardflags2", 0xffffff00, SRFL_PRHEX|SRFL_MORE, SROM8_BFL2, 0xffff}, + {"", 0, 0, SROM8_BFL3, 0xffff}, + {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, + {"subvid", 0xfffffffc, SRFL_PRHEX, SROM_SVID, 0xffff}, + {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, + {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, + {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, + {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, + {"boardnum", 0x00000700, 0, SROM8_MACLO, 0xffff}, + {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, + {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, + {"regrev", 0x00000010, 0, SROM4_REGREV, 0x00ff}, + {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff}, + {"regrev", 0x00000700, 0, SROM8_REGREV, 0x00ff}, + {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff}, + {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, + {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff}, + {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, + {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff}, + {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, + {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff}, + {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, + {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff}, + {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, + {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff}, + {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, + {"ledbh0", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, + {"ledbh1", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, + {"ledbh2", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, + {"ledbh3", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, + {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, + {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, + {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, + {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff}, + {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, + {"pa0b0", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, + {"pa0b1", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, + {"pa0b2", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, + {"pa0itssit", 0x00000700, 0, SROM8_W0_ITTMAXP, 0xff00}, + {"pa0maxpwr", 0x00000700, 0, SROM8_W0_ITTMAXP, 0x00ff}, + {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff}, + {"opo", 0x00000700, 0, SROM8_2G_OFDMPO, 0x00ff}, + {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, + {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff}, + {"aa2g", 0x00000700, 0, SROM8_AA, 0x00ff}, + {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, + {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, + {"aa5g", 0x00000700, 0, SROM8_AA, 0xff00}, + {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff}, + {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, + {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff}, + {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, + {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff}, + {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, + {"ag0", 0x00000700, 0, SROM8_AG10, 0x00ff}, + {"ag1", 0x00000700, 0, SROM8_AG10, 0xff00}, + {"ag2", 0x00000700, 0, SROM8_AG32, 0x00ff}, + {"ag3", 0x00000700, 0, SROM8_AG32, 0xff00}, + {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, + {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, + {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, + {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, + {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, + {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, + {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, + {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, + {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, + {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, + {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, + {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, + {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, + {"pa1b0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, + {"pa1b1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, + {"pa1b2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, + {"pa1lob0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, + {"pa1lob1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, + {"pa1lob2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, + {"pa1hib0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, + {"pa1hib1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, + {"pa1hib2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, + {"pa1itssit", 0x00000700, 0, SROM8_W1_ITTMAXP, 0xff00}, + {"pa1maxpwr", 0x00000700, 0, SROM8_W1_ITTMAXP, 0x00ff}, + {"pa1lomaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0xff00}, + {"pa1himaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, + {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, + {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, + {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, + {"bxa2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x1800}, + {"rssisav2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x0700}, + {"rssismc2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x000f}, + {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, + {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, + {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, + {"bxa5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x1800}, + {"rssisav5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x0700}, + {"rssismc5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x000f}, + {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff}, + {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, + {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, + {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, + {"tri2g", 0x00000700, 0, SROM8_TRI52G, 0x00ff}, + {"tri5g", 0x00000700, 0, SROM8_TRI52G, 0xff00}, + {"tri5gl", 0x00000700, 0, SROM8_TRI5GHL, 0x00ff}, + {"tri5gh", 0x00000700, 0, SROM8_TRI5GHL, 0xff00}, + {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, + {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, + {"rxpo2g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, + {"rxpo5g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, + {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, + {"txchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, + {"tssipos2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK}, + {"extpagain2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK}, + {"pdetrange2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK}, + {"triso2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, + {"antswctl2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK}, + {"tssipos5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK}, + {"extpagain5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK}, + {"pdetrange5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK}, + {"triso5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, + {"antswctl5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK}, + {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, + {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, + {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff}, + {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, + {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, + {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, + {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff}, + {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, + {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, + {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, + {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff}, + {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, + {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, + {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, + {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff}, + {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, + + {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, + {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, + {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, + {"ccode", 0x00000700, SRFL_CCODE, SROM8_CCODE, 0xffff}, + {"macaddr", 0x00000700, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, + {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, + {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, + {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, + {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, + {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, + {"leddc", 0x00000700, SRFL_NOFFS|SRFL_LEDDC, SROM8_LEDDC, 0xffff}, + {"leddc", 0x000000e0, SRFL_NOFFS|SRFL_LEDDC, SROM5_LEDDC, 0xffff}, + {"leddc", 0x00000010, SRFL_NOFFS|SRFL_LEDDC, SROM4_LEDDC, 0xffff}, + {"leddc", 0x00000008, SRFL_NOFFS|SRFL_LEDDC, SROM3_LEDDC, 0xffff}, + + {"tempthresh", 0x00000700, 0, SROM8_THERMAL, 0xff00}, + {"tempoffset", 0x00000700, 0, SROM8_THERMAL, 0x00ff}, + {"rawtempsense", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff}, + {"measpower", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00}, + {"tempsense_slope", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff}, + {"tempcorrx", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00}, + {"tempsense_option", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300}, + {"freqoffset_corr", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f}, + {"iqcal_swp_dis", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010}, + {"hw_iqcal_en", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020}, + {"elna2g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0x00ff}, + {"elna5g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0xff00}, + {"phycal_tempdelta", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff}, + {"temps_period", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x0f00}, + {"temps_hysteresis", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0xf000}, + {"measpower1", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x007f}, + {"measpower2", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x3f80}, + + {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, + {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, + {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, + {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, + {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, + {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, + {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, + {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, + {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, + {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, + {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, + {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, + {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, + {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, + {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, + {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, + {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, + {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, + {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, + {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, + {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, + {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, + {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, + {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, + {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, + {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, + {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, + {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, + {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, + {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, + {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, + {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, + {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, + {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, + {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, + {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, + {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, + {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, + {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, + {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, + {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, + {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, + {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, + {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, + {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, + {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, + {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, + {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, + {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, + {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, + {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, + {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, + {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, + {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, + {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, + {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, + {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, + {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, + {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, + {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, + {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, + {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, + {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, + {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, + {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, + {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, + {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, + {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, + {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, + {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, + {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff}, + {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff}, + {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff}, + {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, + + /* power per rate from sromrev 9 */ + {"cckbw202gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20, 0xffff}, + {"cckbw20ul2gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, + {"legofdmbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, + {"legofdmbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, + {"legofdmbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, + {"mcsbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw402gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, + {"mcsbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, + {"mcsbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, + {"mcsbw405ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, + {"mcs32po", 0x00000600, 0, SROM9_PO_MCS32, 0xffff}, + {"legofdm40duppo", 0x00000600, 0, SROM9_PO_LOFDM40DUP, 0xffff}, + {"pcieingress_war", 0x00000700, 0, SROM8_PCIEINGRESS_WAR, 0xf}, + {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, + {"rxgainerr2ga1", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x07c0}, + {"rxgainerr2ga2", 0x00000700, 0, SROM8_RXGAINERR_2G, 0xf800}, + {"rxgainerr5gla0", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x003f}, + {"rxgainerr5gla1", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x07c0}, + {"rxgainerr5gla2", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0xf800}, + {"rxgainerr5gma0", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x003f}, + {"rxgainerr5gma1", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x07c0}, + {"rxgainerr5gma2", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0xf800}, + {"rxgainerr5gha0", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x003f}, + {"rxgainerr5gha1", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x07c0}, + {"rxgainerr5gha2", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0xf800}, + {"rxgainerr5gua0", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x003f}, + {"rxgainerr5gua1", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x07c0}, + {"rxgainerr5gua2", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0xf800}, + {"sar2g", 0x00000600, 0, SROM9_SAR, 0x00ff}, + {"sar5g", 0x00000600, 0, SROM9_SAR, 0xff00}, + {"noiselvl2ga0", 0x00000700, 0, SROM8_NOISELVL_2G, 0x001f}, + {"noiselvl2ga1", 0x00000700, 0, SROM8_NOISELVL_2G, 0x03e0}, + {"noiselvl2ga2", 0x00000700, 0, SROM8_NOISELVL_2G, 0x7c00}, + {"noiselvl5gla0", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x001f}, + {"noiselvl5gla1", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x03e0}, + {"noiselvl5gla2", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x7c00}, + {"noiselvl5gma0", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x001f}, + {"noiselvl5gma1", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x03e0}, + {"noiselvl5gma2", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x7c00}, + {"noiselvl5gha0", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x001f}, + {"noiselvl5gha1", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x03e0}, + {"noiselvl5gha2", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x7c00}, + {"noiselvl5gua0", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x001f}, + {"noiselvl5gua1", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x03e0}, + {"noiselvl5gua2", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x7c00}, + {"noisecaloffset", 0x00000300, 0, SROM8_NOISECALOFFSET, 0x00ff}, + {"noisecaloffset5g", 0x00000300, 0, SROM8_NOISECALOFFSET, 0xff00}, + {"subband5gver", 0x00000700, 0, SROM8_SUBBAND_PPR, 0x7}, + + {"cckPwrOffset", 0x00000400, 0, SROM10_CCKPWROFFSET, 0xffff}, + /* swctrlmap_2g array, note that the last element doesn't have SRFL_ARRAY flag set */ + {"swctrlmap_2g", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 1, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 2, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 3, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 4, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 5, 0xffff}, + {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 6, 0xffff}, + {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 7, 0xffff}, + {"", 0x00000400, SRFL_PRHEX, SROM10_SWCTRLMAP_2G + 8, 0xffff}, + + /* sromrev 11 */ + {"boardflags3", 0xfffff800, SRFL_PRHEX|SRFL_MORE, SROM11_BFL4, 0xffff}, + {"", 0, 0, SROM11_BFL5, 0xffff}, + {"boardnum", 0xfffff800, 0, SROM11_MACLO, 0xffff}, + {"macaddr", 0xfffff800, SRFL_ETHADDR, SROM11_MACHI, 0xffff}, + {"ccode", 0xfffff800, SRFL_CCODE, SROM11_CCODE, 0xffff}, + {"regrev", 0xfffff800, 0, SROM11_REGREV, 0x00ff}, + {"ledbh0", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0x00ff}, + {"ledbh1", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0xff00}, + {"ledbh2", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0x00ff}, + {"ledbh3", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0xff00}, + {"leddc", 0xfffff800, SRFL_NOFFS|SRFL_LEDDC, SROM11_LEDDC, 0xffff}, + {"aa2g", 0xfffff800, 0, SROM11_AA, 0x00ff}, + {"aa5g", 0xfffff800, 0, SROM11_AA, 0xff00}, + {"agbg0", 0xfffff800, 0, SROM11_AGBG10, 0xff00}, + {"agbg1", 0xfffff800, 0, SROM11_AGBG10, 0x00ff}, + {"agbg2", 0xfffff800, 0, SROM11_AGBG2A0, 0xff00}, + {"aga0", 0xfffff800, 0, SROM11_AGBG2A0, 0x00ff}, + {"aga1", 0xfffff800, 0, SROM11_AGA21, 0xff00}, + {"aga2", 0xfffff800, 0, SROM11_AGA21, 0x00ff}, + {"txchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_SWITCH_MASK}, + + {"tssiposslope2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0001}, + {"epagain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x000e}, + {"pdgain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x01f0}, + {"tworangetssi2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0200}, + {"papdcap2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0400}, + {"femctrl", 0xfffff800, 0, SROM11_FEM_CFG1, 0xf800}, + + {"tssiposslope5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0001}, + {"epagain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x000e}, + {"pdgain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x01f0}, + {"tworangetssi5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0200}, + {"papdcap5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0400}, + {"gainctrlsph", 0xfffff800, 0, SROM11_FEM_CFG2, 0xf800}, + + {"tempthresh", 0xfffff800, 0, SROM11_THERMAL, 0xff00}, + {"tempoffset", 0xfffff800, 0, SROM11_THERMAL, 0x00ff}, + {"rawtempsense", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0x01ff}, + {"measpower", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0xfe00}, + {"tempsense_slope", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x00ff}, + {"tempcorrx", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0xfc00}, + {"tempsense_option", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x0300}, + {"xtalfreq", 0xfffff800, 0, SROM11_XTAL_FREQ, 0xffff}, + /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #1 */ + {"pa5gbw4080a1", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W0_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W1_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W2_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_4080_W0_A1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_4080_PA + 2, 0xffff}, + {"phycal_tempdelta", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x00ff}, + {"temps_period", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x0f00}, + {"temps_hysteresis", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0xf000}, + {"measpower1", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x007f}, + {"measpower2", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x3f80}, + {"tssifloor2g", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_2G, 0x03ff}, + {"tssifloor5g", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GL, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GM, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GH, 0x03ff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_5GU, 0x03ff}, + {"pdoffset2g40ma0", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x000f}, + {"pdoffset2g40ma1", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x00f0}, + {"pdoffset2g40ma2", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x0f00}, + {"pdoffset2g40mvalid", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x8000}, + {"pdoffset40ma0", 0xfffff800, 0, SROM11_PDOFF_40M_A0, 0xffff}, + {"pdoffset40ma1", 0xfffff800, 0, SROM11_PDOFF_40M_A1, 0xffff}, + {"pdoffset40ma2", 0xfffff800, 0, SROM11_PDOFF_40M_A2, 0xffff}, + {"pdoffset80ma0", 0xfffff800, 0, SROM11_PDOFF_80M_A0, 0xffff}, + {"pdoffset80ma1", 0xfffff800, 0, SROM11_PDOFF_80M_A1, 0xffff}, + {"pdoffset80ma2", 0xfffff800, 0, SROM11_PDOFF_80M_A2, 0xffff}, + + {"subband5gver", 0xfffff800, SRFL_PRHEX, SROM11_SUBBAND5GVER, 0xffff}, + {"paparambwver", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0xf000}, + /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #0 */ + {"pa5gbw4080a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 +SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 5G Band, 40 MHz BW */ + {"pa5gbw40a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 5G Band, 80 MHz BW */ + {"pa5gbw80a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, + /* Special PA Params for 4335 2G Band, CCK */ + {"pa2gccka0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_2G_PA + 2, 0xffff}, + + /* power per rate */ + {"cckbw202gpo", 0xfffff800, 0, SROM11_CCKBW202GPO, 0xffff}, + {"cckbw20ul2gpo", 0xfffff800, 0, SROM11_CCKBW20UL2GPO, 0xffff}, + {"mcsbw202gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW202GPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW202GPO_1, 0xffff}, + {"mcsbw402gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW402GPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW402GPO_1, 0xffff}, + {"dot11agofdmhrbw202gpo", 0xfffff800, 0, SROM11_DOT11AGOFDMHRBW202GPO, 0xffff}, + {"ofdmlrbw202gpo", 0xfffff800, 0, SROM11_OFDMLRBW202GPO, 0xffff}, + {"mcsbw205glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GLPO_1, 0xffff}, + {"mcsbw405glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GLPO_1, 0xffff}, + {"mcsbw805glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GLPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GLPO_1, 0xffff}, + {"mcsbw205gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GMPO_1, 0xffff}, + {"mcsbw405gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GMPO_1, 0xffff}, + {"mcsbw805gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GMPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GMPO_1, 0xffff}, + {"mcsbw205ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW205GHPO_1, 0xffff}, + {"mcsbw405ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW405GHPO_1, 0xffff}, + {"mcsbw805ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GHPO, 0xffff}, + {"", 0xfffff800, 0, SROM11_MCSBW805GHPO_1, 0xffff}, + {"mcslr5glpo", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0x0fff}, + {"mcslr5gmpo", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0xffff}, + {"mcslr5ghpo", 0xfffff800, 0, SROM11_MCSLR5GHPO, 0xffff}, + {"sb20in40hrpo", 0xfffff800, 0, SROM11_SB20IN40HRPO, 0xffff}, + {"sb20in80and160hr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GLPO, 0xffff}, + {"sb40and80hr5glpo", 0xfffff800, 0, SROM11_SB40AND80HR5GLPO, 0xffff}, + {"sb20in80and160hr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GMPO, 0xffff}, + {"sb40and80hr5gmpo", 0xfffff800, 0, SROM11_SB40AND80HR5GMPO, 0xffff}, + {"sb20in80and160hr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GHPO, 0xffff}, + {"sb40and80hr5ghpo", 0xfffff800, 0, SROM11_SB40AND80HR5GHPO, 0xffff}, + {"sb20in40lrpo", 0xfffff800, 0, SROM11_SB20IN40LRPO, 0xffff}, + {"sb20in80and160lr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GLPO, 0xffff}, + {"sb40and80lr5glpo", 0xfffff800, 0, SROM11_SB40AND80LR5GLPO, 0xffff}, + {"sb20in80and160lr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GMPO, 0xffff}, + {"sb40and80lr5gmpo", 0xfffff800, 0, SROM11_SB40AND80LR5GMPO, 0xffff}, + {"sb20in80and160lr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GHPO, 0xffff}, + {"sb40and80lr5ghpo", 0xfffff800, 0, SROM11_SB40AND80LR5GHPO, 0xffff}, + {"dot11agduphrpo", 0xfffff800, 0, SROM11_DOT11AGDUPHRPO, 0xffff}, + {"dot11agduplrpo", 0xfffff800, 0, SROM11_DOT11AGDUPLRPO, 0xffff}, + + /* Misc */ + {"sar2g", 0xfffff800, 0, SROM11_SAR, 0x00ff}, + {"sar5g", 0xfffff800, 0, SROM11_SAR, 0xff00}, + + {"noiselvl2ga0", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x001f}, + {"noiselvl2ga1", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x03e0}, + {"noiselvl2ga2", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x7c00}, + {"noiselvl5ga0", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x001f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x001f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x001f}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x001f}, + {"noiselvl5ga1", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x03e0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x03e0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x03e0}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x03e0}, + {"noiselvl5ga2", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x7c00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x7c00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x7c00}, + {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x7c00}, + + {"rxgainerr2ga0", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x003f}, + {"rxgainerr2ga1", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x07c0}, + {"rxgainerr2ga2", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0xf800}, + {"rxgainerr5ga0", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x003f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x003f}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x003f}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x003f}, + {"rxgainerr5ga1", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x07c0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x07c0}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x07c0}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x07c0}, + {"rxgainerr5ga2", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0xf800}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0xf800}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0xf800}, + {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0xf800}, + {"rpcal2g", 0xfffff800, 0, SROM11_RPCAL_2G, 0xffff}, + {"rpcal5gb0", 0xfffff800, 0, SROM11_RPCAL_5GL, 0xffff}, + {"rpcal5gb1", 0xfffff800, 0, SROM11_RPCAL_5GM, 0xffff}, + {"rpcal5gb2", 0xfffff800, 0, SROM11_RPCAL_5GH, 0xffff}, + {"rpcal5gb3", 0xfffff800, 0, SROM11_RPCAL_5GU, 0xffff}, + {"txidxcap2g", 0xfffff800, 0, SROM11_TXIDXCAP2G, 0x0ff0}, + {"txidxcap5g", 0xfffff800, 0, SROM11_TXIDXCAP5G, 0x0ff0}, + {"pdoffsetcckma0", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x000f}, + {"pdoffsetcckma1", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x00f0}, + {"pdoffsetcckma2", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x0f00}, + {NULL, 0, 0, 0, 0} +}; + +static const sromvar_t perpath_pci_sromvars[] = { + {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, + {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, + {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, + {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, + {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, + {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, + {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, + {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, + {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, + {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, + {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, + {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, + {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff}, + {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff}, + {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff}, + {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, + {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff}, + {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff}, + {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff}, + {"maxp2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0x00ff}, + {"itt2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, + {"pa2gw1a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, + {"pa2gw2a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, + {"maxp5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0x00ff}, + {"maxp5gha", 0x00000700, 0, SROM8_5GLH_MAXP, 0x00ff}, + {"maxp5gla", 0x00000700, 0, SROM8_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, + {"pa5gw1a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, + {"pa5gw2a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, + {"pa5glw0a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, + {"pa5glw1a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, + {"pa5glw2a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, + {"pa5ghw0a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, + {"pa5ghw1a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, + {"pa5ghw2a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, + + /* sromrev 11 */ + {"maxp2ga", 0xfffff800, 0, SROM11_2G_MAXP, 0x00ff}, + {"pa2ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff}, + {"rxgains5gmelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0007}, + {"rxgains5gmtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0078}, + {"rxgains5gmtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0080}, + {"rxgains5ghelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0700}, + {"rxgains5ghtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x7800}, + {"rxgains5ghtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x8000}, + {"rxgains2gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0007}, + {"rxgains2gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x0078}, + {"rxgains2gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x0080}, + {"rxgains5gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0700}, + {"rxgains5gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x7800}, + {"rxgains5gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x8000}, + {"maxp5ga", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00}, + {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff}, + {"", 0xfffff800, 0, SROM11_5GB3B2_MAXP, 0xff00}, + {"pa5ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff}, + {"", 0xfffff800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff}, + + {NULL, 0, 0, 0, 0} +}; + +#if !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) +#define PHY_TYPE_HT 7 /* HT-Phy value */ +#define PHY_TYPE_N 4 /* N-Phy value */ +#define PHY_TYPE_LP 5 /* LP-Phy value */ +#endif /* !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) */ +#if !defined(PHY_TYPE_AC) +#define PHY_TYPE_AC 11 /* AC-Phy value */ +#endif /* !defined(PHY_TYPE_AC) */ +#if !defined(PHY_TYPE_NULL) +#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ +#endif /* !defined(PHY_TYPE_NULL) */ + +typedef struct { + uint16 phy_type; + uint16 bandrange; + uint16 chain; + const char *vars; +} pavars_t; + +static const pavars_t pavars[] = { + /* HTPHY */ + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gw0a2 pa2gw1a2 pa2gw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 2, "pa5glw0a2 pa5glw1a2 pa5glw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 2, "pa5gw0a2 pa5gw1a2 pa5gw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 2, "pa5ghw0a2 pa5ghw1a2 pa5ghw2a2"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 0, "pa5gw0a3 pa5gw1a3 pa5gw2a3"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 1, "pa5glw0a3 pa5glw1a3 pa5glw2a3"}, + {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 2, "pa5ghw0a3 pa5ghw1a3 pa5ghw2a3"}, + /* NPHY */ + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, + /* LPPHY */ + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_2G, 0, "pa0b0 pa0b1 pa0b2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GL, 0, "pa1lob0 pa1lob1 pa1lob2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GM, 0, "pa1b0 pa1b1 pa1b2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GH, 0, "pa1hib0 pa1hib1 pa1hib2"}, + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5ga2"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +/* pavars table when paparambwver is 1 */ +static const pavars_t pavars_bwver_1[] = { + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gccka0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga2"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5gbw40a0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw80a0"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +/* pavars table when paparambwver is 2 */ +static const pavars_t pavars_bwver_2[] = { + /* ACPHY */ + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"}, + {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +typedef struct { + uint16 phy_type; + uint16 bandrange; + const char *vars; +} povars_t; + +static const povars_t povars[] = { + /* NPHY */ + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, "mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 " + "mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, "mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 " + "mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, "mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 " + "mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, "mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 " + "mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"}, + {PHY_TYPE_NULL, 0, ""} +}; + +typedef struct { + uint8 tag; /* Broadcom subtag name */ + uint32 revmask; /* Supported cis_sromrev */ + uint8 len; /* Length field of the tuple, note that it includes the + * subtag name (1 byte): 1 + tuple content length + */ + const char *params; +} cis_tuple_t; + +#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */ +#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */ +#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */ +#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */ + +static const cis_tuple_t cis_hnbuvars[] = { + {OTP_RAW1, 0xffffffff, 0, ""}, /* special case */ + {OTP_VERS_1, 0xffffffff, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */ + {OTP_MANFID, 0xffffffff, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */ + /* Unified OTP: tupple to embed USB manfid inside SDIO CIS */ + {HNBU_UMANFID, 0xffffffff, 8, "8usbmanfid"}, + {HNBU_SROMREV, 0xffffffff, 2, "1sromrev"}, + /* NOTE: subdevid is also written to boardtype. + * Need to write HNBU_BOARDTYPE to change it if it is different. + */ + {HNBU_CHIPID, 0xffffffff, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"}, + {HNBU_BOARDREV, 0xffffffff, 3, "2boardrev"}, + {HNBU_PAPARMS, 0xffffffff, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"}, + {HNBU_AA, 0xffffffff, 3, "1aa2g 1aa5g"}, + {HNBU_AA, 0xffffffff, 3, "1aa0 1aa1"}, /* backward compatibility */ + {HNBU_AG, 0xffffffff, 5, "1ag0 1ag1 1ag2 1ag3"}, + {HNBU_BOARDFLAGS, 0xffffffff, 13, "4boardflags 4boardflags2 4boardflags3"}, + {HNBU_LEDS, 0xffffffff, 17, "1ledbh0 1ledbh1 1ledbh2 1ledbh3 1ledbh4 1ledbh5 " + "1ledbh6 1ledbh7 1ledbh8 1ledbh9 1ledbh10 1ledbh11 1ledbh12 1ledbh13 1ledbh14 1ledbh15"}, + {HNBU_CCODE, 0xffffffff, 4, "2ccode 1cctl"}, + {HNBU_CCKPO, 0xffffffff, 3, "2cckpo"}, + {HNBU_OFDMPO, 0xffffffff, 5, "4ofdmpo"}, + {HNBU_PAPARMS5G, 0xffffffff, 23, "2pa1b0 2pa1b1 2pa1b2 2pa1lob0 2pa1lob1 2pa1lob2 " + "2pa1hib0 2pa1hib1 2pa1hib2 1pa1itssit " + "1pa1maxpwr 1pa1lomaxpwr 1pa1himaxpwr"}, + {HNBU_RDLID, 0xffffffff, 3, "2rdlid"}, + {HNBU_RSSISMBXA2G, 0xffffffff, 3, "0rssismf2g 0rssismc2g " + "0rssisav2g 0bxa2g"}, /* special case */ + {HNBU_RSSISMBXA5G, 0xffffffff, 3, "0rssismf5g 0rssismc5g " + "0rssisav5g 0bxa5g"}, /* special case */ + {HNBU_XTALFREQ, 0xffffffff, 5, "4xtalfreq"}, + {HNBU_TRI2G, 0xffffffff, 2, "1tri2g"}, + {HNBU_TRI5G, 0xffffffff, 4, "1tri5gl 1tri5g 1tri5gh"}, + {HNBU_RXPO2G, 0xffffffff, 2, "1rxpo2g"}, + {HNBU_RXPO5G, 0xffffffff, 2, "1rxpo5g"}, + {HNBU_BOARDNUM, 0xffffffff, 3, "2boardnum"}, + {HNBU_MACADDR, 0xffffffff, 7, "6macaddr"}, /* special case */ + {HNBU_RDLSN, 0xffffffff, 3, "2rdlsn"}, + {HNBU_BOARDTYPE, 0xffffffff, 3, "2boardtype"}, + {HNBU_LEDDC, 0xffffffff, 3, "2leddc"}, + {HNBU_RDLRNDIS, 0xffffffff, 2, "1rdlndis"}, + {HNBU_CHAINSWITCH, 0xffffffff, 5, "1txchain 1rxchain 2antswitch"}, + {HNBU_REGREV, 0xffffffff, 2, "1regrev"}, + {HNBU_FEM, 0x000007fe, 5, "0antswctl2g 0triso2g 0pdetrange2g 0extpagain2g " + "0tssipos2g 0antswctl5g 0triso5g 0pdetrange5g 0extpagain5g 0tssipos5g"}, /* special case */ + {HNBU_PAPARMS_C0, 0x000007fe, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 " + "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 2pa5gw1a0 2pa5gw2a0 " + "2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 2pa5ghw1a0 2pa5ghw2a0"}, + {HNBU_PAPARMS_C1, 0x000007fe, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 " + "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 2pa5gw1a1 2pa5gw2a1 " + "2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 2pa5ghw1a1 2pa5ghw2a1"}, + {HNBU_PO_CCKOFDM, 0xffffffff, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo " + "4ofdm5ghpo"}, + {HNBU_PO_MCS2G, 0xffffffff, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 " + "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"}, + {HNBU_PO_MCS5GM, 0xffffffff, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 " + "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"}, + {HNBU_PO_MCS5GLH, 0xffffffff, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 " + "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 " + "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 " + "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"}, + {HNBU_CCKFILTTYPE, 0xffffffff, 2, "1cckdigfilttype"}, + {HNBU_PO_CDD, 0xffffffff, 3, "2cddpo"}, + {HNBU_PO_STBC, 0xffffffff, 3, "2stbcpo"}, + {HNBU_PO_40M, 0xffffffff, 3, "2bw40po"}, + {HNBU_PO_40MDUP, 0xffffffff, 3, "2bwduppo"}, + {HNBU_RDLRWU, 0xffffffff, 2, "1rdlrwu"}, + {HNBU_WPS, 0xffffffff, 3, "1wpsgpio 1wpsled"}, + {HNBU_USBFS, 0xffffffff, 2, "1usbfs"}, + {HNBU_ELNA2G, 0xffffffff, 2, "1elna2g"}, + {HNBU_ELNA5G, 0xffffffff, 2, "1elna5g"}, + {HNBU_CUSTOM1, 0xffffffff, 5, "4customvar1"}, + {OTP_RAW, 0xffffffff, 0, ""}, /* special case */ + {HNBU_OFDMPO5G, 0xffffffff, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"}, + {HNBU_USBEPNUM, 0xffffffff, 3, "2usbepnum"}, + {HNBU_CCKBW202GPO, 0xffffffff, 5, "2cckbw202gpo 2cckbw20ul2gpo"}, + {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"}, + {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo " + "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"}, + {HNBU_MCS2GPO, 0xffffffff, 13, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo"}, + {HNBU_MCS5GLPO, 0xffffffff, 13, "4mcsbw205glpo 4mcsbw20ul5glpo 4mcsbw405glpo"}, + {HNBU_MCS5GMPO, 0xffffffff, 13, "4mcsbw205gmpo 4mcsbw20ul5gmpo 4mcsbw405gmpo"}, + {HNBU_MCS5GHPO, 0xffffffff, 13, "4mcsbw205ghpo 4mcsbw20ul5ghpo 4mcsbw405ghpo"}, + {HNBU_MCS32PO, 0xffffffff, 3, "2mcs32po"}, + {HNBU_LEG40DUPPO, 0xffffffff, 3, "2legofdm40duppo"}, + {HNBU_TEMPTHRESH, 0xffffffff, 7, "1tempthresh 0temps_period 0temps_hysteresis " + "1tempoffset 1tempsense_slope 0tempcorrx 0tempsense_option " + "1phycal_tempdelta"}, /* special case */ + {HNBU_MUXENAB, 0xffffffff, 2, "1muxenab"}, + {HNBU_FEM_CFG, 0xfffff800, 5, "0femctrl 0papdcap2g 0tworangetssi2g 0pdgain2g " + "0epagain2g 0tssiposslope2g 0gainctrlsph 0papdcap5g 0tworangetssi5g 0pdgain5g 0epagain5g " + "0tssiposslope5g"}, /* special case */ + {HNBU_ACPA_C0, 0xfffff800, 39, "2subband5gver 2maxp2ga0 2*3pa2ga0 " + "1*4maxp5ga0 2*12pa5ga0"}, + {HNBU_ACPA_C1, 0xfffff800, 37, "2maxp2ga1 2*3pa2ga1 1*4maxp5ga1 2*12pa5ga1"}, + {HNBU_ACPA_C2, 0xfffff800, 37, "2maxp2ga2 2*3pa2ga2 1*4maxp5ga2 2*12pa5ga2"}, + {HNBU_MEAS_PWR, 0xfffff800, 5, "1measpower 1measpower1 1measpower2 2rawtempsense"}, + {HNBU_PDOFF, 0xfffff800, 13, "2pdoffset40ma0 2pdoffset40ma1 2pdoffset40ma2 " + "2pdoffset80ma0 2pdoffset80ma1 2pdoffset80ma2"}, + {HNBU_ACPPR_2GPO, 0xfffff800, 5, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo"}, + {HNBU_ACPPR_5GPO, 0xfffff800, 31, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo " + "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo"}, + {HNBU_ACPPR_SBPO, 0xfffff800, 33, "2sb20in40hrpo 2sb20in80and160hr5glpo " + "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo " + "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo " + "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo " + "2dot11agduphrpo 2dot11agduplrpo"}, + {HNBU_NOISELVL, 0xfffff800, 16, "1noiselvl2ga0 1noiselvl2ga1 1noiselvl2ga2 " + "1*4noiselvl5ga0 1*4noiselvl5ga1 1*4noiselvl5ga2"}, + {HNBU_RXGAIN_ERR, 0xfffff800, 16, "1rxgainerr2ga0 1rxgainerr2ga1 1rxgainerr2ga2 " + "1*4rxgainerr5ga0 1*4rxgainerr5ga1 1*4rxgainerr5ga2"}, + {HNBU_AGBGA, 0xfffff800, 7, "1agbg0 1agbg1 1agbg2 1aga0 1aga1 1aga2"}, + {HNBU_UUID, 0xffffffff, 17, "16uuid"}, + {HNBU_WOWLGPIO, 0xffffffff, 2, "1wowl_gpio"}, + {HNBU_ACRXGAINS_C0, 0xfffff800, 5, "0rxgains5gtrelnabypa0 0rxgains5gtrisoa0 " + "0rxgains5gelnagaina0 0rxgains2gtrelnabypa0 0rxgains2gtrisoa0 0rxgains2gelnagaina0 " + "0rxgains5ghtrelnabypa0 0rxgains5ghtrisoa0 0rxgains5ghelnagaina0 0rxgains5gmtrelnabypa0 " + "0rxgains5gmtrisoa0 0rxgains5gmelnagaina0"}, /* special case */ + {HNBU_ACRXGAINS_C1, 0xfffff800, 5, "0rxgains5gtrelnabypa1 0rxgains5gtrisoa1 " + "0rxgains5gelnagaina1 0rxgains2gtrelnabypa1 0rxgains2gtrisoa1 0rxgains2gelnagaina1 " + "0rxgains5ghtrelnabypa1 0rxgains5ghtrisoa1 0rxgains5ghelnagaina1 0rxgains5gmtrelnabypa1 " + "0rxgains5gmtrisoa1 0rxgains5gmelnagaina1"}, /* special case */ + {HNBU_ACRXGAINS_C2, 0xfffff800, 5, "0rxgains5gtrelnabypa2 0rxgains5gtrisoa2 " + "0rxgains5gelnagaina2 0rxgains2gtrelnabypa2 0rxgains2gtrisoa2 0rxgains2gelnagaina2 " + "0rxgains5ghtrelnabypa2 0rxgains5ghtrisoa2 0rxgains5ghelnagaina2 0rxgains5gmtrelnabypa2 " + "0rxgains5gmtrisoa2 0rxgains5gmelnagaina2"}, /* special case */ + {HNBU_TXDUTY, 0xfffff800, 9, "2tx_duty_cycle_ofdm_40_5g " + "2tx_duty_cycle_thresh_40_5g 2tx_duty_cycle_ofdm_80_5g 2tx_duty_cycle_thresh_80_5g"}, + {HNBU_PDOFF_2G, 0xfffff800, 3, "0pdoffset2g40ma0 0pdoffset2g40ma1 " + "0pdoffset2g40ma2 0pdoffset2g40mvalid"}, + {HNBU_ACPA_CCK, 0xfffff800, 7, "2*3pa2gccka0"}, + {HNBU_ACPA_40, 0xfffff800, 25, "2*12pa5gbw40a0"}, + {HNBU_ACPA_80, 0xfffff800, 25, "2*12pa5gbw80a0"}, + {HNBU_ACPA_4080, 0xfffff800, 49, "2*12pa5gbw4080a0 2*12pa5gbw4080a1"}, + {HNBU_SUBBAND5GVER, 0xfffff800, 3, "2subband5gver"}, + {HNBU_PAPARAMBWVER, 0xfffff800, 2, "1paparambwver"}, + {0xFF, 0xffffffff, 0, ""} +}; + +#endif /* _bcmsrom_tbl_h_ */
diff --git a/src/include/bcmutils.h b/src/include/bcmutils.h new file mode 100644 index 0000000..82f3cde --- /dev/null +++ b/src/include/bcmutils.h
@@ -0,0 +1,1075 @@ +/* + * Misc useful os-independent macros and functions. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmutils.h 457888 2014-02-25 03:34:39Z $ + */ + +#ifndef _bcmutils_h_ +#define _bcmutils_h_ + +#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) +#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) +#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PKTQ_LOG +#include <wlioctl.h> +#endif + + +#define _BCM_U 0x01 +#define _BCM_L 0x02 +#define _BCM_D 0x04 +#define _BCM_C 0x08 +#define _BCM_P 0x10 +#define _BCM_S 0x20 +#define _BCM_X 0x40 +#define _BCM_SP 0x80 + +extern const unsigned char bcm_ctype[]; +#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) + +#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) +#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) +#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) +#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) +#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) +#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) +#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) +#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) +#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) +#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) +#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) +#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) + + + +struct bcmstrbuf { + char *buf; + unsigned int size; + char *origbuf; + unsigned int origsize; +}; + + +#ifdef BCMDRIVER +#include <osl.h> + +#define GPIO_PIN_NOTDEFINED 0x20 + + +#ifndef SPINWAIT_POLL_PERIOD +#define SPINWAIT_POLL_PERIOD 10 +#endif + +#define SPINWAIT(exp, us) { \ + uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1); \ + while ((exp) && (countdown >= SPINWAIT_POLL_PERIOD)) { \ + OSL_DELAY(SPINWAIT_POLL_PERIOD); \ + countdown -= SPINWAIT_POLL_PERIOD; \ + } \ +} + + +#define PKTQ_LEN_MAX 0xFFFF +#ifndef PKTQ_LEN_DEFAULT +#define PKTQ_LEN_DEFAULT 128 +#endif +#ifndef PKTQ_MAX_PREC +#define PKTQ_MAX_PREC 16 +#endif + +typedef struct pktq_prec { + void *head; + void *tail; + uint16 len; + uint16 max; +} pktq_prec_t; + +#ifdef PKTQ_LOG +typedef struct { + uint32 requested; + uint32 stored; + uint32 saved; + uint32 selfsaved; + uint32 full_dropped; + uint32 dropped; + uint32 sacrificed; + uint32 busy; + uint32 retry; + uint32 ps_retry; + uint32 suppress; + uint32 retry_drop; + uint32 max_avail; + uint32 max_used; + uint32 queue_capacity; + uint32 rtsfail; + uint32 acked; + uint32 txrate_succ; + uint32 txrate_main; + uint32 throughput; + uint32 airtime; + uint32 _logtime; +} pktq_counters_t; + +typedef struct { + uint32 _prec_log; + pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; +} pktq_log_t; +#endif + + +#define PKTQ_COMMON \ + uint16 num_prec; \ + uint16 hi_prec; \ + uint16 max; \ + uint16 len; + + +struct pktq { + PKTQ_COMMON + + struct pktq_prec q[PKTQ_MAX_PREC]; +#ifdef PKTQ_LOG + pktq_log_t* pktqlog; +#endif +}; + + +struct spktq { + PKTQ_COMMON + + struct pktq_prec q[1]; +}; + +#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) + + +typedef bool (*ifpkt_cb_t)(void*, int); + +#ifdef BCMPKTPOOL +#define POOL_ENAB(pool) ((pool) && (pool)->inited) +#if defined(BCM4329C0) +#define SHARED_POOL (pktpool_shared_ptr) +#else +#define SHARED_POOL (pktpool_shared) +#endif +#else +#define POOL_ENAB(bus) 0 +#define SHARED_POOL ((struct pktpool *)NULL) +#endif + +#ifdef BCMFRAGPOOL +#define SHARED_FRAG_POOL (pktpool_shared_lfrag) +#endif +#define SHARED_RXFRAG_POOL (pktpool_shared_rxlfrag) + + +#ifndef PKTPOOL_LEN_MAX +#define PKTPOOL_LEN_MAX 40 +#endif +#define PKTPOOL_CB_MAX 3 + +struct pktpool; +typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); +typedef struct { + pktpool_cb_t cb; + void *arg; +} pktpool_cbinfo_t; + +typedef int (*pktpool_cb_extn_t)(struct pktpool *pool, void *arg, void* pkt); +typedef struct { + pktpool_cb_extn_t cb; + void *arg; +} pktpool_cbextn_info_t; + + +#ifdef BCMDBG_POOL + +#define POOL_IDLE 0 +#define POOL_RXFILL 1 +#define POOL_RXDH 2 +#define POOL_RXD11 3 +#define POOL_TXDH 4 +#define POOL_TXD11 5 +#define POOL_AMPDU 6 +#define POOL_TXENQ 7 + +typedef struct { + void *p; + uint32 cycles; + uint32 dur; +} pktpool_dbg_t; + +typedef struct { + uint8 txdh; + uint8 txd11; + uint8 enq; + uint8 rxdh; + uint8 rxd11; + uint8 rxfill; + uint8 idle; +} pktpool_stats_t; +#endif + +typedef struct pktpool { + bool inited; + uint8 type; + uint8 id; + bool istx; + + void * freelist; + uint16 avail; + uint16 len; + uint16 maxlen; + uint16 plen; + + bool empty; + uint8 cbtoggle; + uint8 cbcnt; + uint8 ecbcnt; + bool emptycb_disable; + pktpool_cbinfo_t *availcb_excl; + pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; + pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; + pktpool_cbextn_info_t cbext; +#ifdef BCMDBG_POOL + uint8 dbg_cbcnt; + pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; + uint16 dbg_qlen; + pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; +#endif +} pktpool_t; + +#if defined(BCM4329C0) +extern pktpool_t *pktpool_shared_ptr; +#else +extern pktpool_t *pktpool_shared; +#ifdef BCMFRAGPOOL +extern pktpool_t *pktpool_shared_lfrag; +#endif +extern pktpool_t *pktpool_shared_rxlfrag; +#endif + + +extern int pktpool_attach(osl_t *osh, uint32 total_pools); +extern int pktpool_dettach(osl_t *osh); + +extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx, uint8 type); +extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); +extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); +extern void* pktpool_get(pktpool_t *pktp); +extern void pktpool_free(pktpool_t *pktp, void *p); +extern int pktpool_add(pktpool_t *pktp, void *p); +extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); +extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); +extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); +extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); +extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); +extern bool pktpool_emptycb_disabled(pktpool_t *pktp); +int pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg); +#define POOLPTR(pp) ((pktpool_t *)(pp)) +#define POOLID(pp) (POOLPTR(pp)->id) + +#define POOLSETID(pp, ppid) (POOLPTR(pp)->id = (ppid)) + +#define pktpool_len(pp) (POOLPTR(pp)->len) +#define pktpool_avail(pp) (POOLPTR(pp)->avail) +#define pktpool_plen(pp) (POOLPTR(pp)->plen) +#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) + + + +#define PKTPOOL_INVALID_ID (0) +#define PKTPOOL_MAXIMUM_ID (15) + + +extern pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; + + +#define PKTPOOL_ID2PTR(id) (pktpools_registry[id]) +#define PKTPOOL_PTR2ID(pp) (POOLID(pp)) + + +#ifdef BCMDBG_POOL +extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_start_trigger(pktpool_t *pktp, void *p); +extern int pktpool_dbg_dump(pktpool_t *pktp); +extern int pktpool_dbg_notify(pktpool_t *pktp); +extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); +#endif + + + +struct ether_addr; + +extern int ether_isbcast(const void *ea); +extern int ether_isnulladdr(const void *ea); + + + +#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) +#define pktq_pmax(pq, prec) ((pq)->q[prec].max) +#define pktq_plen(pq, prec) ((pq)->q[prec].len) +#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) +#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) +#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) + +#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) +#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) + +extern void *pktq_penq(struct pktq *pq, int prec, void *p); +extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); +extern void *pktq_pdeq(struct pktq *pq, int prec); +extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); +extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); +extern void *pktq_pdeq_tail(struct pktq *pq, int prec); + +extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, + ifpkt_cb_t fn, int arg); + +extern bool pktq_pdel(struct pktq *pq, void *p, int prec); + + + +extern int pktq_mlen(struct pktq *pq, uint prec_bmp); +extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); +extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); + + + +#define pktq_len(pq) ((int)(pq)->len) +#define pktq_max(pq) ((int)(pq)->max) +#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) +#define pktq_full(pq) ((pq)->len >= (pq)->max) +#define pktq_empty(pq) ((pq)->len == 0) + + +#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) +#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) +#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) +#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) +#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) + +extern void pktq_init(struct pktq *pq, int num_prec, int max_len); +extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); + + +extern void *pktq_deq(struct pktq *pq, int *prec_out); +extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); +extern void *pktq_peek(struct pktq *pq, int *prec_out); +extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); +extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); + + + +extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pkttotlen(osl_t *osh, void *p); +extern void *pktlast(osl_t *osh, void *p); +extern uint pktsegcnt(osl_t *osh, void *p); +extern uint pktsegcnt_war(osl_t *osh, void *p); +extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); +extern void *pktoffset(osl_t *osh, void *p, uint offset); + + +#define PKTPRIO_VDSCP 0x100 +#define PKTPRIO_VLAN 0x200 +#define PKTPRIO_UPD 0x400 +#define PKTPRIO_DSCP 0x800 + + + +#define DSCP_AF11 0x0A +#define DSCP_AF12 0x0C +#define DSCP_AF13 0x0E + +#define DSCP_AF21 0x12 +#define DSCP_AF22 0x14 +#define DSCP_AF23 0x16 + +#define DSCP_AF31 0x1A +#define DSCP_AF32 0x1C +#define DSCP_AF33 0x1E + +#define DSCP_EF 0x2E + +extern uint pktsetprio(void *pkt, bool update_vtag); + + +extern int BCMROMFN(bcm_atoi)(const char *s); +extern ulong BCMROMFN(bcm_strtoul)(const char *cp, char **endp, uint base); +extern char *BCMROMFN(bcmstrstr)(const char *haystack, const char *needle); +extern char *BCMROMFN(bcmstrcat)(char *dest, const char *src); +extern char *BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size); +extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); +char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); +int bcmstricmp(const char *s1, const char *s2); +int bcmstrnicmp(const char* s1, const char* s2, int cnt); + + + +extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); +extern int BCMROMFN(bcm_ether_atoe)(const char *p, struct ether_addr *ea); + + +struct ipv4_addr; +extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); +extern char *bcm_ipv6_ntoa(void *ipv6, char *buf); +extern int BCMROMFN(bcm_atoipv4)(const char *p, struct ipv4_addr *ip); + + +extern void bcm_mdelay(uint ms); + +#define NVRAM_RECLAIM_CHECK(name) + +extern char *getvar(char *vars, const char *name); +extern int getintvar(char *vars, const char *name); +extern int getintvararray(char *vars, const char *name, int index); +extern int getintvararraysize(char *vars, const char *name); +extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); +#define bcm_perf_enable() +#define bcmstats(fmt) +#define bcmlog(fmt, a1, a2) +#define bcmdumplog(buf, size) *buf = '\0' +#define bcmdumplogent(buf, idx) -1 + +#define TSF_TICKS_PER_MS 1000 + +#define bcmtslog(tstamp, fmt, a1, a2) +#define bcmprinttslogs() +#define bcmprinttstamp(us) +#define bcmdumptslog(buf, size) + +extern char *bcm_nvram_vars(uint *length); +extern int bcm_nvram_cache(void *sih); + + + + +typedef struct bcm_iovar { + const char *name; + uint16 varid; + uint16 flags; + uint16 type; + uint16 minlen; +} bcm_iovar_t; + + + + +#define IOV_GET 0 +#define IOV_SET 1 + + +#define IOV_GVAL(id) ((id) * 2) +#define IOV_SVAL(id) ((id) * 2 + IOV_SET) +#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) +#define IOV_ID(actionid) (actionid >> 1) + + + +extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); +extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); +#endif +#endif + + +#define IOVT_VOID 0 +#define IOVT_BOOL 1 +#define IOVT_INT8 2 +#define IOVT_UINT8 3 +#define IOVT_INT16 4 +#define IOVT_UINT16 5 +#define IOVT_INT32 6 +#define IOVT_UINT32 7 +#define IOVT_BUFFER 8 +#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) + + +#define BCM_IOV_TYPE_INIT { \ + "void", \ + "bool", \ + "int8", \ + "uint8", \ + "int16", \ + "uint16", \ + "int32", \ + "uint32", \ + "buffer", \ + "" } + +#define BCM_IOVT_IS_INT(type) (\ + (type == IOVT_BOOL) || \ + (type == IOVT_INT8) || \ + (type == IOVT_UINT8) || \ + (type == IOVT_INT16) || \ + (type == IOVT_UINT16) || \ + (type == IOVT_INT32) || \ + (type == IOVT_UINT32)) + + + +#define BCME_STRLEN 64 +#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) + + + + +#define BCME_OK 0 +#define BCME_ERROR -1 +#define BCME_BADARG -2 +#define BCME_BADOPTION -3 +#define BCME_NOTUP -4 +#define BCME_NOTDOWN -5 +#define BCME_NOTAP -6 +#define BCME_NOTSTA -7 +#define BCME_BADKEYIDX -8 +#define BCME_RADIOOFF -9 +#define BCME_NOTBANDLOCKED -10 +#define BCME_NOCLK -11 +#define BCME_BADRATESET -12 +#define BCME_BADBAND -13 +#define BCME_BUFTOOSHORT -14 +#define BCME_BUFTOOLONG -15 +#define BCME_BUSY -16 +#define BCME_NOTASSOCIATED -17 +#define BCME_BADSSIDLEN -18 +#define BCME_OUTOFRANGECHAN -19 +#define BCME_BADCHAN -20 +#define BCME_BADADDR -21 +#define BCME_NORESOURCE -22 +#define BCME_UNSUPPORTED -23 +#define BCME_BADLEN -24 +#define BCME_NOTREADY -25 +#define BCME_EPERM -26 +#define BCME_NOMEM -27 +#define BCME_ASSOCIATED -28 +#define BCME_RANGE -29 +#define BCME_NOTFOUND -30 +#define BCME_WME_NOT_ENABLED -31 +#define BCME_TSPEC_NOTFOUND -32 +#define BCME_ACM_NOTSUPPORTED -33 +#define BCME_NOT_WME_ASSOCIATION -34 +#define BCME_SDIO_ERROR -35 +#define BCME_DONGLE_DOWN -36 +#define BCME_VERSION -37 +#define BCME_TXFAIL -38 +#define BCME_RXFAIL -39 +#define BCME_NODEVICE -40 +#define BCME_NMODE_DISABLED -41 +#define BCME_NONRESIDENT -42 +#define BCME_SCANREJECT -43 +#define BCME_USAGE_ERROR -44 +#define BCME_IOCTL_ERROR -45 +#define BCME_SERIAL_PORT_ERR -46 +#define BCME_DISABLED -47 +#define BCME_DECERR -48 +#define BCME_ENCERR -49 +#define BCME_MICERR -50 +#define BCME_REPLAY -51 +#define BCME_IE_NOTFOUND -52 +#define BCME_LAST BCME_IE_NOTFOUND + +#define BCME_NOTENABLED BCME_DISABLED + + +#define BCMERRSTRINGTABLE { \ + "OK", \ + "Undefined error", \ + "Bad Argument", \ + "Bad Option", \ + "Not up", \ + "Not down", \ + "Not AP", \ + "Not STA", \ + "Bad Key Index", \ + "Radio Off", \ + "Not band locked", \ + "No clock", \ + "Bad Rate valueset", \ + "Bad Band", \ + "Buffer too short", \ + "Buffer too long", \ + "Busy", \ + "Not Associated", \ + "Bad SSID len", \ + "Out of Range Channel", \ + "Bad Channel", \ + "Bad Address", \ + "Not Enough Resources", \ + "Unsupported", \ + "Bad length", \ + "Not Ready", \ + "Not Permitted", \ + "No Memory", \ + "Associated", \ + "Not In Range", \ + "Not Found", \ + "WME Not Enabled", \ + "TSPEC Not Found", \ + "ACM Not Supported", \ + "Not WME Association", \ + "SDIO Bus Error", \ + "Dongle Not Accessible", \ + "Incorrect version", \ + "TX Failure", \ + "RX Failure", \ + "Device Not Present", \ + "NMODE Disabled", \ + "Nonresident overlay access", \ + "Scan Rejected", \ + "WLCMD usage error", \ + "WLCMD ioctl error", \ + "RWL serial port error", \ + "Disabled", \ + "Decrypt error", \ + "Encrypt error", \ + "MIC error", \ + "Replay", \ + "IE not found", \ +} + +#ifndef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + + +#ifndef LIMIT_TO_RANGE +#define LIMIT_TO_RANGE(x, min, max) \ + ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) +#endif + + +#ifndef LIMIT_TO_MAX +#define LIMIT_TO_MAX(x, max) \ + (((x) > (max) ? (max) : (x))) +#endif + + +#ifndef LIMIT_TO_MIN +#define LIMIT_TO_MIN(x, min) \ + (((x) < (min) ? (min) : (x))) +#endif + +#define DELTA(curr, prev) ((curr) > (prev) ? ((curr) - (prev)) : \ + (0xffffffff - (prev) + (curr) + 1)) +#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) +#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#define ROUNDDN(p, align) ((p) & ~((align) - 1)) +#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) +#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ + & ~((boundary) - 1)) +#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ + & ~((boundary) - 1)) +#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) +#define VALID_MASK(mask) !((mask) & ((mask) + 1)) + +#ifndef OFFSETOF +#ifdef __ARMCC_VERSION + +#include <stddef.h> +#define OFFSETOF(type, member) offsetof(type, member) +#else +# if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 8)) + +# define OFFSETOF(type, member) __builtin_offsetof(type, member) +# else +# define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) +# endif +#endif +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + +#ifndef ARRAYLAST +#define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1]) +#endif + + +extern void *_bcmutils_dummy_fn; +#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) + + +#ifndef setbit +#ifndef NBBY +#define NBBY 8 +#endif +#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS +extern void setbit(void *array, uint bit); +extern void clrbit(void *array, uint bit); +extern bool isset(const void *array, uint bit); +extern bool isclr(const void *array, uint bit); +#else +#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) +#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) +#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) +#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) +#endif +#endif + +#define isbitset(a, i) (((a) & (1 << (i))) != 0) + +#define NBITS(type) (sizeof(type) * 8) +#define NBITVAL(nbits) (1 << (nbits)) +#define MAXBITVAL(nbits) ((1 << (nbits)) - 1) +#define NBITMASK(nbits) MAXBITVAL(nbits) +#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) + +extern void bcm_bitprint32(const uint32 u32); + + + +#define DECLARE_MAP_API(NB, RSH, LSH, OFF, MSK) \ +static INLINE void setbit##NB(void *ptr, uint32 ix, uint32 val) \ +{ \ + uint32 *addr = (uint32 *)ptr; \ + uint32 *a = addr + (ix >> RSH); \ + uint32 pos = (ix & OFF) << LSH; \ + uint32 mask = (MSK << pos); \ + uint32 tmp = *a & ~mask; \ + *a = tmp | (val << pos); \ +} \ +static INLINE uint32 getbit##NB(void *ptr, uint32 ix) \ +{ \ + uint32 *addr = (uint32 *)ptr; \ + uint32 *a = addr + (ix >> RSH); \ + uint32 pos = (ix & OFF) << LSH; \ + return ((*a >> pos) & MSK); \ +} + +DECLARE_MAP_API(2, 4, 1, 15U, 0x0003) +DECLARE_MAP_API(4, 3, 2, 7U, 0x000F) + + + +#define MUX(pred, true, false) ((pred) ? (true) : (false)) + + +#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1) +#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) + + +#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) +#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) + + +#define MODADD(x, y, bound) \ + MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) +#define MODSUB(x, y, bound) \ + MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) + + +#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) +#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) + + +#define CRC8_INIT_VALUE 0xff +#define CRC8_GOOD_VALUE 0x9f +#define CRC16_INIT_VALUE 0xffff +#define CRC16_GOOD_VALUE 0xf0b8 +#define CRC32_INIT_VALUE 0xffffffff +#define CRC32_GOOD_VALUE 0xdebb20e3 + + +#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" +#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ + ((struct ether_addr *) (ea))->octet[1], \ + ((struct ether_addr *) (ea))->octet[2], \ + ((struct ether_addr *) (ea))->octet[3], \ + ((struct ether_addr *) (ea))->octet[4], \ + ((struct ether_addr *) (ea))->octet[5] + +#define ETHER_TO_MACF(ea) (ea).octet[0], \ + (ea).octet[1], \ + (ea).octet[2], \ + (ea).octet[3], \ + (ea).octet[4], \ + (ea).octet[5] +#if !defined(SIMPLE_MAC_PRINT) +#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] +#else +#define MACDBG "%02x:%02x:%02x" +#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] +#endif + + +typedef struct bcm_bit_desc { + uint32 bit; + const char* name; +} bcm_bit_desc_t; + + +typedef struct bcm_bit_desc_ex { + uint32 mask; + const bcm_bit_desc_t *bitfield; +} bcm_bit_desc_ex_t; + + +#define ETHER_ADDR_STR_LEN 18 + + + +static INLINE void +xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) +{ + if ( +#ifdef __i386__ + 1 || +#endif + (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { + + + ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; + ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; + ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; + ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; + } else { + + int k; + for (k = 0; k < 16; k++) + dst[k] = src1[k] ^ src2[k]; + } +} + + + +extern uint8 BCMROMFN(hndcrc8)(uint8 *p, uint nbytes, uint8 crc); +extern uint16 BCMROMFN(hndcrc16)(uint8 *p, uint nbytes, uint16 crc); +extern uint32 BCMROMFN(hndcrc32)(uint8 *p, uint nbytes, uint32 crc); + + +#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ + defined(WLMSG_ASSOC) + +extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); + +extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); +#endif + +#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ + defined(WLMSG_ASSOC) || defined(WLMEDIA_PEAKRATE) +extern int bcm_format_hex(char *str, const void *bytes, int len); +#endif + +extern const char *bcm_crypto_algo_name(uint algo); +extern char *bcm_chipname(uint chipid, char *buf, uint len); +extern char *bcm_brev_str(uint32 brev, char *buf); +extern void printbig(char *buf); +extern void prhex(const char *msg, uchar *buf, uint len); + + + + +typedef struct bcm_tlv { + uint8 id; + uint8 len; + uint8 data[1]; +} bcm_tlv_t; + +#define BCM_TLV_MAX_DATA_SIZE (255) + +#define BCM_TLV_HDR_SIZE (OFFSETOF(bcm_tlv_t, data)) + + +#define bcm_valid_tlv(elt, buflen) (\ + ((int)(buflen) >= (int)BCM_TLV_HDR_SIZE) && \ + ((int)(buflen) >= (int)(BCM_TLV_HDR_SIZE + (elt)->len))) + +extern bcm_tlv_t *BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen); +extern bcm_tlv_t *BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key); +extern bcm_tlv_t *BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key); + +extern bcm_tlv_t *bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, + int type_len); + +extern uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst); +extern uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, + int dst_maxlen); + +extern uint8 *bcm_copy_tlv(const void *src, uint8 *dst); +extern uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen); + + +extern const char *bcmerrorstr(int bcmerror); + + +typedef uint32 mbool; +#define mboolset(mb, bit) ((mb) |= (bit)) +#define mboolclr(mb, bit) ((mb) &= ~(bit)) +#define mboolisset(mb, bit) (((mb) & (bit)) != 0) +#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) + + +struct fielddesc { + const char *nameandfmt; + uint32 offset; + uint32 len; +}; + +extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); +extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); + +extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); +extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); +extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); + +typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); +extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, + char *buf, uint32 bufsize); +extern uint BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint bytelength); + +extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); + + +extern uint16 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm); +extern uint8 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw); +extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); + +unsigned int process_nvram_vars(char *varbuf, unsigned int len); + + +extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); + +extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); + + + + + +static const uint8 +_CSBTBL[256] = +{ +# define B2(n) n, n + 1, n + 1, n + 2 +# define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2) +# define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2) + B6(0), B6(0 + 1), B6(0 + 1), B6(0 + 2) +}; + +static INLINE uint32 +bcm_cntsetbits(const uint32 u32) +{ + + const uint8 * p = (const uint8 *)&u32; + return (_CSBTBL[p[0]] + _CSBTBL[p[1]] + _CSBTBL[p[2]] + _CSBTBL[p[3]]); +} + + +static INLINE int +C_bcm_count_leading_zeros(uint32 u32) +{ + int shifts = 0; + while (u32) { + shifts++; u32 >>= 1; + } + return (32U - shifts); +} + +#ifdef BCMDRIVER + + +#if defined(__arm__) + +#if defined(__ARM_ARCH_7M__) +#define __USE_ASM_CLZ__ +#endif + +#if defined(__ARM_ARCH_7R__) +#define __USE_ASM_CLZ__ +#endif + +#endif + +static INLINE int +bcm_count_leading_zeros(uint32 u32) +{ +#if defined(__USE_ASM_CLZ__) + int zeros; + __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32)); + return zeros; +#else + return C_bcm_count_leading_zeros(u32); +#endif +} + + +struct bcm_mwbmap; + +#define BCM_MWBMAP_INVALID_HDL ((struct bcm_mwbmap *)NULL) +#define BCM_MWBMAP_INVALID_IDX ((uint32)(~0U)) + + +extern struct bcm_mwbmap * bcm_mwbmap_init(osl_t * osh, uint32 items_max); + + +extern void bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl); + + +extern uint32 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl); + + +extern void bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + + +extern void bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + + +extern uint32 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl); + + +extern bool bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); + + +extern void bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl); + +extern void bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl); + +#endif + +extern void bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b); + +void bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset); +void bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset); + +#ifdef __cplusplus + } +#endif + +#ifdef DEBUG_COUNTER +#define CNTR_TBL_MAX 10 +typedef struct _counter_tbl_t { + char name[16]; + uint32 prev_log_print; + uint log_print_interval; + uint needed_cnt; + uint32 cnt[CNTR_TBL_MAX]; + bool enabled; +} counter_tbl_t; + + +void counter_printlog(counter_tbl_t *ctr_tbl); +#endif + +#endif
diff --git a/src/include/brcm_nl80211.h b/src/include/brcm_nl80211.h new file mode 100644 index 0000000..f804fb9 --- /dev/null +++ b/src/include/brcm_nl80211.h
@@ -0,0 +1,38 @@ +/* + * Definitions for nl80211 testmode access to host driver + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: brcm_nl80211.h 454792 2014-02-11 20:40:19Z $ + * + */ + +#ifndef _brcm_nl80211_h_ +#define _brcm_nl80211_h_ + +struct bcm_nlmsg_hdr { + uint cmd; /* common ioctl definition */ + uint len; /* attached buffer length */ + uint offset; /* user buffer offset */ + uint set; /* get or set request optional */ + uint magic; /* magic number for verification */ +}; + +enum bcmnl_attrs { + BCM_NLATTR_UNSPEC, + + BCM_NLATTR_LEN, + BCM_NLATTR_DATA, + + __BCM_NLATTR_AFTER_LAST, + BCM_NLATTR_MAX = __BCM_NLATTR_AFTER_LAST - 1 +}; + +struct nl_prv_data { + int err; /* return result */ + void *data; /* ioctl return buffer pointer */ + uint len; /* ioctl return buffer length */ + struct bcm_nlmsg_hdr *nlioc; /* bcm_nlmsg_hdr header pointer */ +}; + +#endif /* _brcm_nl80211_h_ */
diff --git a/src/include/dhdioctl.h b/src/include/dhdioctl.h new file mode 100644 index 0000000..89bf3de --- /dev/null +++ b/src/include/dhdioctl.h
@@ -0,0 +1,121 @@ +/* + * Definitions for ioctls to access DHD iovars. + * Based on wlioctl.h (for Broadcom 802.11abg driver). + * (Moves towards generic ioctls for BCM drivers/iovars.) + * + * Definitions subject to change without notice. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: dhdioctl.h 454792 2014-02-11 20:40:19Z $ + */ + +#ifndef _dhdioctl_h_ +#define _dhdioctl_h_ + +#include <typedefs.h> + + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include <packed_section_start.h> + + +/* Linux network driver ioctl encoding */ +typedef struct dhd_ioctl { + uint cmd; /* common ioctl definition */ + void *buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + bool set; /* get or set request (optional) */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ + uint driver; /* to identify target driver */ +} dhd_ioctl_t; + +/* Underlying BUS definition */ +enum { + BUS_TYPE_USB = 0, /* for USB dongles */ + BUS_TYPE_SDIO, /* for SDIO dongles */ + BUS_TYPE_PCIE /* for PCIE dongles */ +}; + +/* per-driver magic numbers */ +#define DHD_IOCTL_MAGIC 0x00444944 + +/* bump this number if you change the ioctl interface */ +#define DHD_IOCTL_VERSION 1 + +#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ +#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ + +/* common ioctl definitions */ +#define DHD_GET_MAGIC 0 +#define DHD_GET_VERSION 1 +#define DHD_GET_VAR 2 +#define DHD_SET_VAR 3 + +/* message levels */ +#define DHD_ERROR_VAL 0x0001 +#define DHD_TRACE_VAL 0x0002 +#define DHD_INFO_VAL 0x0004 +#define DHD_DATA_VAL 0x0008 +#define DHD_CTL_VAL 0x0010 +#define DHD_TIMER_VAL 0x0020 +#define DHD_HDRS_VAL 0x0040 +#define DHD_BYTES_VAL 0x0080 +#define DHD_INTR_VAL 0x0100 +#define DHD_LOG_VAL 0x0200 +#define DHD_GLOM_VAL 0x0400 +#define DHD_EVENT_VAL 0x0800 +#define DHD_BTA_VAL 0x1000 +#if 0 && (NDISVER >= 0x0630) && 1 +#define DHD_SCAN_VAL 0x2000 +#else +#define DHD_ISCAN_VAL 0x2000 +#endif +#define DHD_ARPOE_VAL 0x4000 +#define DHD_REORDER_VAL 0x8000 +#define DHD_WL_VAL 0x10000 +#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */ +#define DHD_WL_VAL2 0x40000 +#define DHD_PNO_VAL 0x80000 + +#ifdef SDTEST +/* For pktgen iovar */ +typedef struct dhd_pktgen { + uint version; /* To allow structure change tracking */ + uint freq; /* Max ticks between tx/rx attempts */ + uint count; /* Test packets to send/rcv each attempt */ + uint print; /* Print counts every <print> attempts */ + uint total; /* Total packets (or bursts) */ + uint minlen; /* Minimum length of packets to send */ + uint maxlen; /* Maximum length of packets to send */ + uint numsent; /* Count of test packets sent */ + uint numrcvd; /* Count of test packets received */ + uint numfail; /* Count of test send failures */ + uint mode; /* Test mode (type of test packets) */ + uint stop; /* Stop after this many tx failures */ +} dhd_pktgen_t; + +/* Version in case structure changes */ +#define DHD_PKTGEN_VERSION 2 + +/* Type of test packets to use */ +#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ +#define DHD_PKTGEN_SEND 2 /* Send discard packets */ +#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ +#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ +#endif /* SDTEST */ + +/* Enter idle immediately (no timeout) */ +#define DHD_IDLE_IMMEDIATE (-1) + +/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ +#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ +#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ + + +/* require default structure packing */ +#include <packed_section_end.h> + +#endif /* _dhdioctl_h_ */
diff --git a/src/include/epivers.h b/src/include/epivers.h new file mode 100644 index 0000000..fd26ef5 --- /dev/null +++ b/src/include/epivers.h
@@ -0,0 +1,30 @@ +/* + * $Copyright Open Broadcom Corporation$ + * + * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ + * +*/ + +#ifndef _epivers_h_ +#define _epivers_h_ + +#define EPI_MAJOR_VERSION 1 + +#define EPI_MINOR_VERSION 141 + +#define EPI_RC_NUMBER 66 + +#define EPI_INCREMENTAL_NUMBER 4 + +#define EPI_BUILD_NUMBER 1 + +#define EPI_VERSION 1, 141, 66, 4 + +#define EPI_VERSION_NUM 0x018d4204 + +#define EPI_VERSION_DEV 1.141.66 + + +#define EPI_VERSION_STR "1.141.66.4 (r655085)" + +#endif
diff --git a/src/include/event_log.h b/src/include/event_log.h new file mode 100644 index 0000000..35c2ba7 --- /dev/null +++ b/src/include/event_log.h
@@ -0,0 +1,279 @@ +/* + * EVENT_LOG system definitions + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: event_log.h 241182 2011-02-17 21:50:03Z $ + */ + +#ifndef _EVENT_LOG_H_ +#define _EVENT_LOG_H_ + + +/* Set a maximum number of sets here. It is not dynamic for + * efficiency of the EVENT_LOG calls. + */ +#define NUM_EVENT_LOG_SETS 4 +#define EVENT_LOG_SET_BUS 0 +#define EVENT_LOG_SET_WL 1 +#define EVENT_LOG_SET_PSM 2 + +/* Define new event log tags here */ +#define EVENT_LOG_TAG_NULL 0 /* Special null tag */ +#define EVENT_LOG_TAG_TS 1 /* Special timestamp tag */ +#define EVENT_LOG_TAG_BUS_OOB 2 +#define EVENT_LOG_TAG_BUS_STATE 3 +#define EVENT_LOG_TAG_BUS_PROTO 4 +#define EVENT_LOG_TAG_BUS_CTL 5 +#define EVENT_LOG_TAG_BUS_EVENT 6 +#define EVENT_LOG_TAG_BUS_PKT 7 +#define EVENT_LOG_TAG_BUS_FRAME 8 +#define EVENT_LOG_TAG_BUS_DESC 9 +#define EVENT_LOG_TAG_BUS_SETUP 10 +#define EVENT_LOG_TAG_BUS_MISC 11 +#define EVENT_LOG_TAG_AWDL_ERR 12 +#define EVENT_LOG_TAG_AWDL_WARN 13 +#define EVENT_LOG_TAG_AWDL_INFO 14 +#define EVENT_LOG_TAG_AWDL_DEBUG 15 +#define EVENT_LOG_TAG_AWDL_TRACE_TIMER 16 +#define EVENT_LOG_TAG_AWDL_TRACE_SYNC 17 +#define EVENT_LOG_TAG_AWDL_TRACE_CHAN 18 +#define EVENT_LOG_TAG_AWDL_TRACE_DP 19 +#define EVENT_LOG_TAG_AWDL_TRACE_MISC 20 +#define EVENT_LOG_TAG_AWDL_TEST 21 +#define EVENT_LOG_TAG_SRSCAN 22 +#define EVENT_LOG_TAG_PWRSTATS_INFO 23 +#define EVENT_LOG_TAG_AWDL_TRACE_CHANSW 24 +#define EVENT_LOG_TAG_AWDL_TRACE_PEER_OPENCLOSE 25 +#define EVENT_LOG_TAG_UCODE_WATCHDOG 26 +#define EVENT_LOG_TAG_UCODE_FIFO 27 +#define EVENT_LOG_TAG_SCAN_TRACE_LOW 28 +#define EVENT_LOG_TAG_SCAN_TRACE_HIGH 29 +#define EVENT_LOG_TAG_SCAN_ERROR 30 +#define EVENT_LOG_TAG_SCAN_WARN 31 +#define EVENT_LOG_TAG_MPF_ERR 32 +#define EVENT_LOG_TAG_MPF_WARN 33 +#define EVENT_LOG_TAG_MPF_INFO 34 +#define EVENT_LOG_TAG_MPF_DEBUG 35 +#define EVENT_LOG_TAG_MAX 35 + +/* Flags for tag control */ +#define EVENT_LOG_TAG_FLAG_NONE 0 +#define EVENT_LOG_TAG_FLAG_LOG 0x80 +#define EVENT_LOG_TAG_FLAG_PRINT 0x40 +#define EVENT_LOG_TAG_FLAG_MASK 0x3f + +/* logstrs header */ +#define LOGSTRS_MAGIC 0x4C4F4753 +#define LOGSTRS_VERSION 0x1 + +/* We make sure that the block size will fit in a single packet + * (allowing for a bit of overhead on each packet + */ +#define EVENT_LOG_MAX_BLOCK_SIZE 1400 +#define EVENT_LOG_PSM_BLOCK 0x200 + +/* + * There are multiple levels of objects define here: + * event_log_set - a set of buffers + * event log groups - every event log call is part of just one. All + * event log calls in a group are handled the + * same way. Each event log group is associated + * with an event log set or is off. + */ + +#ifndef __ASSEMBLER__ + +/* On the external system where the dumper is we need to make sure + * that these types are the same size as they are on the ARM the + * produced them + */ +#ifdef EVENT_LOG_DUMPER +#define _EL_BLOCK_PTR uint32 +#define _EL_TYPE_PTR uint32 +#define _EL_SET_PTR uint32 +#define _EL_TOP_PTR uint32 +#else +#define _EL_BLOCK_PTR struct event_log_block * +#define _EL_TYPE_PTR uint32 * +#define _EL_SET_PTR struct event_log_set ** +#define _EL_TOP_PTR struct event_log_top * +#endif /* EVENT_LOG_DUMPER */ + +/* Each event log entry has a type. The type is the LAST word of the + * event log. The printing code walks the event entries in reverse + * order to find the first entry. + */ +typedef union event_log_hdr { + struct { + uint8 tag; /* Event_log entry tag */ + uint8 count; /* Count of 4-byte entries */ + uint16 fmt_num; /* Format number */ + }; + uint32 t; /* Type cheat */ +} event_log_hdr_t; + +/* Event log sets (a logical circurlar buffer) consist of one or more + * event_log_blocks. The blocks themselves form a logical circular + * list. The log entries are placed in each event_log_block until it + * is full. Logging continues with the next event_log_block in the + * event_set until the last event_log_block is reached and then + * logging starts over with the first event_log_block in the + * event_set. + */ +typedef struct event_log_block { + _EL_BLOCK_PTR next_block; + _EL_BLOCK_PTR prev_block; + _EL_TYPE_PTR end_ptr; + + /* Start of packet sent for log tracing */ + uint16 pktlen; /* Size of rest of block */ + uint16 count; /* Logtrace counter */ + uint32 timestamp; /* Timestamp at start of use */ + uint32 event_logs; +} event_log_block_t; + +/* There can be multiple event_sets with each logging a set of + * associated events (i.e, "fast" and "slow" events). + */ +typedef struct event_log_set { + _EL_BLOCK_PTR first_block; /* Pointer to first event_log block */ + _EL_BLOCK_PTR last_block; /* Pointer to last event_log block */ + _EL_BLOCK_PTR logtrace_block; /* next block traced */ + _EL_BLOCK_PTR cur_block; /* Pointer to current event_log block */ + _EL_TYPE_PTR cur_ptr; /* Current event_log pointer */ + uint32 blockcount; /* Number of blocks */ + uint16 logtrace_count; /* Last count for logtrace */ + uint16 blockfill_count; /* Fill count for logtrace */ + uint32 timestamp; /* Last timestamp event */ + uint32 cyclecount; /* Cycles at last timestamp event */ +} event_log_set_t; + +/* Top data structure for access to everything else */ +typedef struct event_log_top { + uint32 magic; +#define EVENT_LOG_TOP_MAGIC 0x474C8669 /* 'EVLG' */ + uint32 version; +#define EVENT_LOG_VERSION 1 + uint32 num_sets; + uint32 logstrs_size; /* Size of lognums + logstrs area */ + uint32 timestamp; /* Last timestamp event */ + uint32 cyclecount; /* Cycles at last timestamp event */ + _EL_SET_PTR sets; /* Ptr to array of <num_sets> set ptrs */ +} event_log_top_t; + +/* Data structure of Keeping the Header from logstrs.bin */ +typedef struct { + uint32 logstrs_size; /* Size of the file */ + uint32 rom_lognums_offset; /* Offset to the ROM lognum */ + uint32 ram_lognums_offset; /* Offset to the RAM lognum */ + uint32 rom_logstrs_offset; /* Offset to the ROM logstr */ + uint32 ram_logstrs_offset; /* Offset to the RAM logstr */ + /* Keep version and magic last since "header" is appended to the end of logstrs file. */ + uint32 version; /* Header version */ + uint32 log_magic; /* MAGIC number for verification 'LOGS' */ +} logstr_header_t; + + +#ifndef EVENT_LOG_DUMPER + +#ifndef EVENT_LOG_COMPILE + +/* Null define if no tracing */ +#define EVENT_LOG(format, ...) + +#else /* EVENT_LOG_COMPILE */ + +/* The first few are special because they can be done more efficiently + * this way and they are the common case. Once there are too many + * parameters the code size starts to be an issue and a loop is better + */ +#define _EVENT_LOG0(tag, fmt_num) \ + event_log0(tag, fmt_num) +#define _EVENT_LOG1(tag, fmt_num, t1) \ + event_log1(tag, fmt_num, t1) +#define _EVENT_LOG2(tag, fmt_num, t1, t2) \ + event_log2(tag, fmt_num, t1, t2) +#define _EVENT_LOG3(tag, fmt_num, t1, t2, t3) \ + event_log3(tag, fmt_num, t1, t2, t3) +#define _EVENT_LOG4(tag, fmt_num, t1, t2, t3, t4) \ + event_log4(tag, fmt_num, t1, t2, t3, t4) + +/* The rest call the generic routine that takes a count */ +#define _EVENT_LOG5(tag, fmt_num, ...) event_logn(5, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOG6(tag, fmt_num, ...) event_logn(6, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOG7(tag, fmt_num, ...) event_logn(7, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOG8(tag, fmt_num, ...) event_logn(8, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOG9(tag, fmt_num, ...) event_logn(9, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOGA(tag, fmt_num, ...) event_logn(10, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOGB(tag, fmt_num, ...) event_logn(11, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOGC(tag, fmt_num, ...) event_logn(12, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOGD(tag, fmt_num, ...) event_logn(13, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOGE(tag, fmt_num, ...) event_logn(14, tag, fmt_num, __VA_ARGS__) +#define _EVENT_LOGF(tag, fmt_num, ...) event_logn(15, tag, fmt_num, __VA_ARGS__) + +/* Hack to make the proper routine call when variadic macros get + * passed. Note the max of 15 arguments. More than that can't be + * handled by the event_log entries anyways so best to catch it at compile + * time + */ + +#define _EVENT_LOG_VA_NUM_ARGS(F, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _A, _B, _C, _D, _E, _F, N, ...) F ## N + +#define _EVENT_LOG(tag, fmt, ...) \ + static char logstr[] __attribute__ ((section(".logstrs"))) = fmt; \ + static uint32 fmtnum __attribute__ ((section(".lognums"))) = (uint32) &logstr; \ + _EVENT_LOG_VA_NUM_ARGS(_EVENT_LOG, ##__VA_ARGS__, \ + F, E, D, C, B, A, 9, 8, \ + 7, 6, 5, 4, 3, 2, 1, 0) \ + (tag, (int) &fmtnum , ## __VA_ARGS__); \ + + +#define EVENT_LOG_FAST(tag, fmt, ...) \ + if (event_log_tag_sets != NULL) { \ + uint8 tag_flag = *(event_log_tag_sets + tag); \ + if (tag_flag != 0) { \ + _EVENT_LOG(tag, fmt , ## __VA_ARGS__); \ + } \ + } + +#define EVENT_LOG_COMPACT(tag, fmt, ...) \ + if (1) { \ + _EVENT_LOG(tag, fmt , ## __VA_ARGS__); \ + } + +#define EVENT_LOG(tag, fmt, ...) EVENT_LOG_COMPACT(tag, fmt , ## __VA_ARGS__) + +#define EVENT_LOG_IS_LOG_ON(tag) (*(event_log_tag_sets + (tag)) & EVENT_LOG_TAG_FLAG_LOG) + +#define EVENT_DUMP event_log_buffer + +extern uint8 *event_log_tag_sets; + +extern int event_log_init(si_t *sih); +extern int event_log_set_init(si_t *sih, int set_num, int size); +extern int event_log_set_expand(si_t *sih, int set_num, int size); +extern int event_log_set_shrink(si_t *sih, int set_num, int size); +extern int event_log_tag_start(int tag, int set_num, int flags); +extern int event_log_tag_stop(int tag); +extern int event_log_get(int set_num, int buflen, void *buf); +extern uint8 * event_log_next_logtrace(int set_num); + +extern void event_log0(int tag, int fmtNum); +extern void event_log1(int tag, int fmtNum, uint32 t1); +extern void event_log2(int tag, int fmtNum, uint32 t1, uint32 t2); +extern void event_log3(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3); +extern void event_log4(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3, uint32 t4); +extern void event_logn(int num_args, int tag, int fmtNum, ...); + +extern void event_log_time_sync(void); +extern void event_log_buffer(int tag, uint8 *buf, int size); + +#endif /* EVENT_LOG_DUMPER */ + +#endif /* EVENT_LOG_COMPILE */ + +#endif /* __ASSEMBLER__ */ + +#endif /* _EVENT_LOG_H */
diff --git a/src/include/hndrte_armtrap.h b/src/include/hndrte_armtrap.h new file mode 100644 index 0000000..83adf38 --- /dev/null +++ b/src/include/hndrte_armtrap.h
@@ -0,0 +1,70 @@ +/* + * HNDRTE arm trap handling. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: hndrte_armtrap.h 261365 2011-05-24 20:42:23Z $ + */ + +#ifndef _hndrte_armtrap_h +#define _hndrte_armtrap_h + + +/* ARM trap handling */ + +/* Trap types defined by ARM (see arminc.h) */ + +/* Trap locations in lo memory */ +#define TRAP_STRIDE 4 +#define FIRST_TRAP TR_RST +#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) + +#if defined(__ARM_ARCH_4T__) +#define MAX_TRAP_TYPE (TR_FIQ + 1) +#elif defined(__ARM_ARCH_7M__) +#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) +#endif /* __ARM_ARCH_7M__ */ + +/* The trap structure is defined here as offsets for assembly */ +#define TR_TYPE 0x00 +#define TR_EPC 0x04 +#define TR_CPSR 0x08 +#define TR_SPSR 0x0c +#define TR_REGS 0x10 +#define TR_REG(n) (TR_REGS + (n) * 4) +#define TR_SP TR_REG(13) +#define TR_LR TR_REG(14) +#define TR_PC TR_REG(15) + +#define TRAP_T_SIZE 80 + +#ifndef _LANGUAGE_ASSEMBLY + +#include <typedefs.h> + +typedef struct _trap_struct { + uint32 type; + uint32 epc; + uint32 cpsr; + uint32 spsr; + uint32 r0; /* a1 */ + uint32 r1; /* a2 */ + uint32 r2; /* a3 */ + uint32 r3; /* a4 */ + uint32 r4; /* v1 */ + uint32 r5; /* v2 */ + uint32 r6; /* v3 */ + uint32 r7; /* v4 */ + uint32 r8; /* v5 */ + uint32 r9; /* sb/v6 */ + uint32 r10; /* sl/v7 */ + uint32 r11; /* fp/v8 */ + uint32 r12; /* ip */ + uint32 r13; /* sp */ + uint32 r14; /* lr */ + uint32 pc; /* r15 */ +} trap_t; + +#endif /* !_LANGUAGE_ASSEMBLY */ + +#endif /* _hndrte_armtrap_h */
diff --git a/src/include/hndrte_cons.h b/src/include/hndrte_cons.h new file mode 100644 index 0000000..33a6cd8 --- /dev/null +++ b/src/include/hndrte_cons.h
@@ -0,0 +1,60 @@ +/* + * Console support for hndrte. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: hndrte_cons.h 427140 2013-10-02 18:07:07Z $ + */ +#ifndef _HNDRTE_CONS_H +#define _HNDRTE_CONS_H + +#include <typedefs.h> + +#if defined(RWL_DONGLE) || defined(UART_REFLECTOR) +/* For Dongle uart tranport max cmd len is 256 bytes + header length (16 bytes) + * In case of ASD commands we are not sure about how much is the command size + * To be on the safe side, input buf len CBUF_LEN is increased to max (512) bytes. + */ +#define RWL_MAX_DATA_LEN (512 + 8) /* allow some extra bytes for '/n' termination */ +#define CBUF_LEN (RWL_MAX_DATA_LEN + 64) /* allow 64 bytes for header ("rwl...") */ +#else +#define CBUF_LEN (128) +#endif /* RWL_DONGLE || UART_REFLECTOR */ + +#define LOG_BUF_LEN 1024 + +typedef struct { + uint32 buf; /* Can't be pointer on (64-bit) hosts */ + uint buf_size; + uint idx; + uint out_idx; /* output index */ +} hndrte_log_t; + +typedef struct { + /* Virtual UART + * When there is no UART (e.g. Quickturn), the host should write a complete + * input line directly into cbuf and then write the length into vcons_in. + * This may also be used when there is a real UART (at risk of conflicting with + * the real UART). vcons_out is currently unused. + */ + volatile uint vcons_in; + volatile uint vcons_out; + + /* Output (logging) buffer + * Console output is written to a ring buffer log_buf at index log_idx. + * The host may read the output when it sees log_idx advance. + * Output will be lost if the output wraps around faster than the host polls. + */ + hndrte_log_t log; + + /* Console input line buffer + * Characters are read one at a time into cbuf until <CR> is received, then + * the buffer is processed as a command line. Also used for virtual UART. + */ + uint cbuf_idx; + char cbuf[CBUF_LEN]; +} hndrte_cons_t; + +hndrte_cons_t *hndrte_get_active_cons_state(void); + +#endif /* _HNDRTE_CONS_H */
diff --git a/src/include/hndrte_debug.h b/src/include/hndrte_debug.h new file mode 100644 index 0000000..c305f7e --- /dev/null +++ b/src/include/hndrte_debug.h
@@ -0,0 +1,99 @@ +/* + * HND Run Time Environment debug info area + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: hndrte_debug.h 342211 2012-07-02 02:23:04Z $ + */ + +#ifndef _HNDRTE_DEBUG_H +#define _HNDRTE_DEBUG_H + +/* Magic number at a magic location to find HNDRTE_DEBUG pointers */ +#define HNDRTE_DEBUG_PTR_PTR_MAGIC 0x50504244 /* DBPP */ + +#ifndef _LANGUAGE_ASSEMBLY + +/* Includes only when building dongle code */ + + +#define NUM_EVENT_LOG_SETS 4 + +/* We use explicit sizes here since this gets included from different + * systems. The sizes must be the size of the creating system + * (currently 32 bit ARM) since this is gleaned from dump. + */ + +#ifdef FWID +extern uint32 gFWID; +#endif + +/* Define pointers for use on other systems */ +#define _HD_EVLOG_P uint32 +#define _HD_CONS_P uint32 +#define _HD_TRAP_P uint32 + +typedef struct hndrte_debug { + uint32 magic; +#define HNDRTE_DEBUG_MAGIC 0x47424544 /* 'DEBG' */ + + uint32 version; /* Debug struct version */ +#define HNDRTE_DEBUG_VERSION 1 + + uint32 fwid; /* 4 bytes of fw info */ + char epivers[32]; + + _HD_TRAP_P trap_ptr; /* trap_t data struct */ + _HD_CONS_P console; /* Console */ + + uint32 ram_base; + uint32 ram_size; + + uint32 rom_base; + uint32 rom_size; + + _HD_EVLOG_P event_log_top; + +} hndrte_debug_t; + +/* + * timeval_t and prstatus_t are copies of the Linux structures. + * Included here because we need the definitions for the target processor + * (32 bits) and not the definition on the host this is running on + * (which could be 64 bits). + */ + +typedef struct { /* Time value with microsecond resolution */ + uint32 tv_sec; /* Seconds */ + uint32 tv_usec; /* Microseconds */ +} timeval_t; + + +/* Linux/ARM 32 prstatus for notes section */ +typedef struct prstatus { + int32 si_signo; /* Signal number */ + int32 si_code; /* Extra code */ + int32 si_errno; /* Errno */ + uint16 pr_cursig; /* Current signal. */ + uint16 unused; + uint32 pr_sigpend; /* Set of pending signals. */ + uint32 pr_sighold; /* Set of held signals. */ + uint32 pr_pid; + uint32 pr_ppid; + uint32 pr_pgrp; + uint32 pr_sid; + timeval_t pr_utime; /* User time. */ + timeval_t pr_stime; /* System time. */ + timeval_t pr_cutime; /* Cumulative user time. */ + timeval_t pr_cstime; /* Cumulative system time. */ + uint32 uregs[18]; + int32 pr_fpvalid; /* True if math copro being used. */ +} prstatus_t; + +#ifdef __GNUC__ +extern hndrte_debug_t hndrte_debug_info; +#endif /* __GNUC__ */ + +#endif /* !LANGUAGE_ASSEMBLY */ + +#endif /* _HNDRTE_DEBUG_H */
diff --git a/src/include/miniopt.h b/src/include/miniopt.h new file mode 100644 index 0000000..6c13070 --- /dev/null +++ b/src/include/miniopt.h
@@ -0,0 +1,59 @@ +/* + * Command line options parser. + * + * $Copyright Open Broadcom Corporation$ + * $Id: miniopt.h 241182 2011-02-17 21:50:03Z $ + */ + + +#ifndef MINI_OPT_H +#define MINI_OPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---- Include Files ---------------------------------------------------- */ +/* ---- Constants and Types ---------------------------------------------- */ + +#define MINIOPT_MAXKEY 128 /* Max options */ +typedef struct miniopt { + + /* These are persistent after miniopt_init() */ + const char* name; /* name for prompt in error strings */ + const char* flags; /* option chars that take no args */ + bool longflags; /* long options may be flags */ + bool opt_end; /* at end of options (passed a "--") */ + + /* These are per-call to miniopt() */ + + int consumed; /* number of argv entries cosumed in + * the most recent call to miniopt() + */ + bool positional; + bool good_int; /* 'val' member is the result of a sucessful + * strtol conversion of the option value + */ + char opt; + char key[MINIOPT_MAXKEY]; + char* valstr; /* positional param, or value for the option, + * or null if the option had + * no accompanying value + */ + uint uval; /* strtol translation of valstr */ + int val; /* strtol translation of valstr */ +} miniopt_t; + +void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); +int miniopt(miniopt_t *t, char **argv); + + +/* ---- Variable Externs ------------------------------------------------- */ +/* ---- Function Prototypes ---------------------------------------------- */ + + +#ifdef __cplusplus + } +#endif + +#endif /* MINI_OPT_H */
diff --git a/src/include/packed_section_end.h b/src/include/packed_section_end.h new file mode 100644 index 0000000..761838c --- /dev/null +++ b/src/include/packed_section_end.h
@@ -0,0 +1,35 @@ +/* + * Declare directives for structure packing. No padding will be provided + * between the members of packed structures, and therefore, there is no + * guarantee that structure members will be aligned. + * + * Declaring packed structures is compiler specific. In order to handle all + * cases, packed structures should be delared as: + * + * #include <packed_section_start.h> + * + * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { + * some_struct_members; + * } BWL_POST_PACKED_STRUCT foobar_t; + * + * #include <packed_section_end.h> + * + * + * $Copyright Open Broadcom Corporation$ + * $Id: packed_section_end.h 241182 2011-02-17 21:50:03Z $ + */ + + + +#ifdef BWL_PACKED_SECTION + #undef BWL_PACKED_SECTION +#else + #error "BWL_PACKED_SECTION is NOT defined!" +#endif + + + + + +#undef BWL_PRE_PACKED_STRUCT +#undef BWL_POST_PACKED_STRUCT
diff --git a/src/include/packed_section_start.h b/src/include/packed_section_start.h new file mode 100644 index 0000000..ba00dbd --- /dev/null +++ b/src/include/packed_section_start.h
@@ -0,0 +1,42 @@ +/* + * Declare directives for structure packing. No padding will be provided + * between the members of packed structures, and therefore, there is no + * guarantee that structure members will be aligned. + * + * Declaring packed structures is compiler specific. In order to handle all + * cases, packed structures should be delared as: + * + * #include <packed_section_start.h> + * + * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { + * some_struct_members; + * } BWL_POST_PACKED_STRUCT foobar_t; + * + * #include <packed_section_end.h> + * + * + * $Copyright Open Broadcom Corporation$ + * $Id: packed_section_start.h 286783 2011-09-29 06:18:57Z $ + */ + + + +#ifdef BWL_PACKED_SECTION + #error "BWL_PACKED_SECTION is already defined!" +#else + #define BWL_PACKED_SECTION +#endif + + + + + +#if defined(__GNUC__) || defined(__lint) + #define BWL_PRE_PACKED_STRUCT + #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) +#elif defined(__CC_ARM) + #define BWL_PRE_PACKED_STRUCT __packed + #define BWL_POST_PACKED_STRUCT +#else + #error "Unknown compiler!" +#endif
diff --git a/src/include/rwl_wifi.h b/src/include/rwl_wifi.h new file mode 100644 index 0000000..6fd8902 --- /dev/null +++ b/src/include/rwl_wifi.h
@@ -0,0 +1,95 @@ +/* + * RWL definitions of + * Broadcom 802.11bang Networking Device Driver + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: rwl_wifi.h 393462 2013-03-27 19:48:39Z $ + * + */ + +#ifndef _rwl_wifi_h_ +#define _rwl_wifi_h_ + +#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR) || defined(RFAWARE) + +#define RWL_ACTION_WIFI_CATEGORY 127 /* Vendor-specific category value for WiFi */ +#define RWL_WIFI_OUI_BYTE0 0x00 /* BRCM-specific public OUI */ +#define RWL_WIFI_OUI_BYTE1 0x90 +#define RWL_WIFI_OUI_BYTE2 0x4c +#define RWL_WIFI_ACTION_FRAME_SIZE sizeof(struct dot11_action_wifi_vendor_specific) + +/* + * Information about the action frame data fields in the dot11_action_wifi_vendor_specific + * cdc structure (1 to 16). This does not include the status flag. Since this + * is not directly visible to the driver code, we can't use sizeof(struct cdc_ioctl). + * Hence Ref MAC address offset starts from byte 17. + * REF MAC ADDR (6 bytes (MAC Address len) from byte 17 to 22) + * DUT MAC ADDR (6 bytes after the REF MAC Address byte 23 to 28) + * unused (byte 29 to 49) + * REF/Client Channel offset (50) + * DUT/Server channel offset (51) + * --------------------------------------------------------------------------------------- + * cdc struct|REF MAC ADDR|DUT_MAC_ADDR|un used|REF Channel|DUT channel|Action frame Data| + * 1---------17-----------23-------------------50----------51----------52----------------1040 + * REF MAC addr after CDC struct without status flag (status flag not used by wifi) + */ + +#define RWL_REF_MAC_ADDRESS_OFFSET 17 +#define RWL_DUT_MAC_ADDRESS_OFFSET 23 +#define RWL_WIFI_CLIENT_CHANNEL_OFFSET 50 +#define RWL_WIFI_SERVER_CHANNEL_OFFSET 51 + +#ifdef WIFI_REFLECTOR +#include <bcmcdc.h> +#define REMOTE_FINDSERVER_CMD 16 +#define RWL_WIFI_ACTION_CMD "wifiaction" +#define RWL_WIFI_ACTION_CMD_LEN 11 /* With the NULL terminator */ +#define REMOTE_SET_CMD 1 +#define REMOTE_GET_CMD 2 +#define REMOTE_REPLY 4 +#define RWL_WIFI_DEFAULT_TYPE 0x00 +#define RWL_WIFI_DEFAULT_SUBTYPE 0x00 +#define RWL_ACTION_FRAME_DATA_SIZE 1024 /* fixed size for the wifi frame data */ +#define RWL_WIFI_CDC_HEADER_OFFSET 0 +#define RWL_WIFI_FRAG_DATA_SIZE 960 /* max size of the frag data */ +#define RWL_DEFAULT_WIFI_FRAG_COUNT 127 /* maximum fragment count */ +#define RWL_WIFI_RETRY 5 /* CMD retry count for wifi */ +#define RWL_WIFI_SEND 5 /* WIFI frame sent count */ +#define RWL_WIFI_SEND_DELAY 100 /* delay between two frames */ +#define MICROSEC_CONVERTOR_VAL 1000 +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +typedef struct rem_packet { + rem_ioctl_t rem_cdc; + uchar message [RWL_ACTION_FRAME_DATA_SIZE]; +} rem_packet_t; + +#include <packed_section_start.h> +struct BWL_PRE_PACKED_STRUCT send_packet { + char command [RWL_WIFI_ACTION_CMD_LEN]; + dot11_action_wifi_vendor_specific_t response; +} BWL_POST_PACKED_STRUCT; +#include <packed_section_end.h> + +typedef struct send_packet send_packet_t; + +#define REMOTE_SIZE sizeof(rem_ioctl_t) +#endif /* WIFI_REFLECTOR */ + +typedef struct rwl_request { + struct rwl_request* next_request; + struct dot11_action_wifi_vendor_specific action_frame; +} rwl_request_t; + + +#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */ +#endif /* _rwl_wifi_h_ */
diff --git a/src/include/sbpcmcia.h b/src/include/sbpcmcia.h new file mode 100644 index 0000000..122687c --- /dev/null +++ b/src/include/sbpcmcia.h
@@ -0,0 +1,276 @@ +/* + * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: sbpcmcia.h 427964 2013-10-07 07:13:33Z $ + */ + +#ifndef _SBPCMCIA_H +#define _SBPCMCIA_H + + + + +#define PCMCIA_FCR (0x700 / 2) + +#define FCR0_OFF 0 +#define FCR1_OFF (0x40 / 2) +#define FCR2_OFF (0x80 / 2) +#define FCR3_OFF (0xc0 / 2) + +#define PCMCIA_FCR0 (0x700 / 2) +#define PCMCIA_FCR1 (0x740 / 2) +#define PCMCIA_FCR2 (0x780 / 2) +#define PCMCIA_FCR3 (0x7c0 / 2) + + + +#define PCMCIA_COR 0 + +#define COR_RST 0x80 +#define COR_LEV 0x40 +#define COR_IRQEN 0x04 +#define COR_BLREN 0x01 +#define COR_FUNEN 0x01 + + +#define PCICIA_FCSR (2 / 2) +#define PCICIA_PRR (4 / 2) +#define PCICIA_SCR (6 / 2) +#define PCICIA_ESR (8 / 2) + + +#define PCM_MEMOFF 0x0000 +#define F0_MEMOFF 0x1000 +#define F1_MEMOFF 0x2000 +#define F2_MEMOFF 0x3000 +#define F3_MEMOFF 0x4000 + + +#define MEM_ADDR0 (0x728 / 2) +#define MEM_ADDR1 (0x72a / 2) +#define MEM_ADDR2 (0x72c / 2) + + +#define PCMCIA_ADDR0 (0x072e / 2) +#define PCMCIA_ADDR1 (0x0730 / 2) +#define PCMCIA_ADDR2 (0x0732 / 2) + +#define MEM_SEG (0x0734 / 2) +#define SROM_CS (0x0736 / 2) +#define SROM_DATAL (0x0738 / 2) +#define SROM_DATAH (0x073a / 2) +#define SROM_ADDRL (0x073c / 2) +#define SROM_ADDRH (0x073e / 2) +#define SROM_INFO2 (0x0772 / 2) +#define SROM_INFO (0x07be / 2) + + +#define SROM_IDLE 0 +#define SROM_WRITE 1 +#define SROM_READ 2 +#define SROM_WEN 4 +#define SROM_WDS 7 +#define SROM_DONE 8 + + +#define SRI_SZ_MASK 0x03 +#define SRI_BLANK 0x04 +#define SRI_OTP 0x80 + +#if !defined(LINUX_POSTMOGRIFY_REMOVAL) + + + +#define CIS_SIZE PCMCIA_FCR + + +#define CIS_TUPLE_LEN_MAX 0xff + + + +#define CISTPL_NULL 0x00 +#define CISTPL_VERS_1 0x15 +#define CISTPL_MANFID 0x20 +#define CISTPL_FUNCID 0x21 +#define CISTPL_FUNCE 0x22 +#define CISTPL_CFTABLE 0x1b +#define CISTPL_END 0xff + + +#define CISTPL_FID_SDIO 0x0c + + +#define LAN_TECH 1 +#define LAN_SPEED 2 +#define LAN_MEDIA 3 +#define LAN_NID 4 +#define LAN_CONN 5 + + + +#define CFTABLE_REGWIN_2K 0x08 +#define CFTABLE_REGWIN_4K 0x10 +#define CFTABLE_REGWIN_8K 0x20 + + + +#define CISTPL_BRCM_HNBU 0x80 + + + +#define HNBU_SROMREV 0x00 +#define HNBU_CHIPID 0x01 +#define HNBU_BOARDREV 0x02 +#define HNBU_PAPARMS 0x03 +#define HNBU_OEM 0x04 +#define HNBU_CC 0x05 +#define HNBU_AA 0x06 +#define HNBU_AG 0x07 +#define HNBU_BOARDFLAGS 0x08 +#define HNBU_LEDS 0x09 +#define HNBU_CCODE 0x0a +#define HNBU_CCKPO 0x0b +#define HNBU_OFDMPO 0x0c +#define HNBU_GPIOTIMER 0x0d +#define HNBU_PAPARMS5G 0x0e +#define HNBU_ANT5G 0x0f +#define HNBU_RDLID 0x10 +#define HNBU_RSSISMBXA2G 0x11 +#define HNBU_RSSISMBXA5G 0x12 +#define HNBU_XTALFREQ 0x13 +#define HNBU_TRI2G 0x14 +#define HNBU_TRI5G 0x15 +#define HNBU_RXPO2G 0x16 +#define HNBU_RXPO5G 0x17 +#define HNBU_BOARDNUM 0x18 +#define HNBU_MACADDR 0x19 +#define HNBU_RDLSN 0x1a +#define HNBU_BOARDTYPE 0x1b +#define HNBU_LEDDC 0x1c +#define HNBU_HNBUCIS 0x1d +#define HNBU_PAPARMS_SSLPNPHY 0x1e +#define HNBU_RSSISMBXA2G_SSLPNPHY 0x1f +#define HNBU_RDLRNDIS 0x20 +#define HNBU_CHAINSWITCH 0x21 +#define HNBU_REGREV 0x22 +#define HNBU_FEM 0x23 +#define HNBU_PAPARMS_C0 0x24 +#define HNBU_PAPARMS_C1 0x25 +#define HNBU_PAPARMS_C2 0x26 +#define HNBU_PAPARMS_C3 0x27 +#define HNBU_PO_CCKOFDM 0x28 +#define HNBU_PO_MCS2G 0x29 +#define HNBU_PO_MCS5GM 0x2a +#define HNBU_PO_MCS5GLH 0x2b +#define HNBU_PO_CDD 0x2c +#define HNBU_PO_STBC 0x2d +#define HNBU_PO_40M 0x2e +#define HNBU_PO_40MDUP 0x2f + +#define HNBU_RDLRWU 0x30 +#define HNBU_WPS 0x31 +#define HNBU_USBFS 0x32 +#define HNBU_BRMIN 0x33 +#define HNBU_BRMAX 0x34 +#define HNBU_PATCH 0x35 +#define HNBU_CCKFILTTYPE 0x36 +#define HNBU_OFDMPO5G 0x37 +#define HNBU_ELNA2G 0x38 +#define HNBU_ELNA5G 0x39 +#define HNBU_TEMPTHRESH 0x3A +#define HNBU_UUID 0x3B + +#define HNBU_USBEPNUM 0x40 + + +#define HNBU_CCKBW202GPO 0x41 + +#define HNBU_LEGOFDMBW202GPO 0x42 + +#define HNBU_LEGOFDMBW205GPO 0x43 + +#define HNBU_MCS2GPO 0x44 +#define HNBU_MCS5GLPO 0x45 +#define HNBU_MCS5GMPO 0x46 +#define HNBU_MCS5GHPO 0x47 +#define HNBU_MCS32PO 0x48 +#define HNBU_LEG40DUPPO 0x49 + +#define HNBU_PMUREGS 0x4a + +#define HNBU_PATCH2 0x4b + +#define HNBU_USBRDY 0x4c + +#define HNBU_USBREGS 0x4d + +#define HNBU_BLDR_TIMEOUT 0x4e +#define HNBU_USBFLAGS 0x4f +#define HNBU_PATCH_AUTOINC 0x50 +#define HNBU_MDIO_REGLIST 0x51 +#define HNBU_MDIOEX_REGLIST 0x52 + +#define HNBU_UMANFID 0x53 +#define HNBU_PUBKEY 0x54 +#define HNBU_WOWLGPIO 0x55 +#define HNBU_MUXENAB 0x56 +#define HNBU_GCI_CCR 0x57 + +#define HNBU_FEM_CFG 0x58 +#define HNBU_ACPA_C0 0x59 +#define HNBU_ACPA_C1 0x5a +#define HNBU_ACPA_C2 0x5b +#define HNBU_MEAS_PWR 0x5c +#define HNBU_PDOFF 0x5d +#define HNBU_ACPPR_2GPO 0x5e +#define HNBU_ACPPR_5GPO 0x5f +#define HNBU_ACPPR_SBPO 0x60 +#define HNBU_NOISELVL 0x61 +#define HNBU_RXGAIN_ERR 0x62 +#define HNBU_AGBGA 0x63 +#define HNBU_USBDESC_COMPOSITE 0x64 +#define HNBU_PATCH_AUTOINC8 0x65 +#define HNBU_PATCH8 0x66 +#define HNBU_ACRXGAINS_C0 0x67 +#define HNBU_ACRXGAINS_C1 0x68 +#define HNBU_ACRXGAINS_C2 0x69 +#define HNBU_TXDUTY 0x6a +#define HNBU_USBUTMI_CTL 0x6b +#define HNBU_PDOFF_2G 0x6c +#define HNBU_USBSSPHY_UTMI_CTL0 0x6d +#define HNBU_USBSSPHY_UTMI_CTL1 0x6e +#define HNBU_USBSSPHY_UTMI_CTL2 0x6f +#define HNBU_USBSSPHY_SLEEP0 0x70 +#define HNBU_USBSSPHY_SLEEP1 0x71 +#define HNBU_USBSSPHY_SLEEP2 0x72 +#define HNBU_USBSSPHY_SLEEP3 0x73 +#define HNBU_USBSSPHY_MDIO 0x74 +#define HNBU_USB30PHY_NOSS 0x75 +#define HNBU_USB30PHY_U1U2 0x76 +#define HNBU_USB30PHY_REGS 0x77 + +#define HNBU_SROM3SWRGN 0x80 +#define HNBU_RESERVED 0x81 +#define HNBU_CUSTOM1 0x82 +#define HNBU_CUSTOM2 0x83 +#define HNBU_ACPAPARAM 0x84 +#define HNBU_ACPA_CCK 0x86 +#define HNBU_ACPA_40 0x87 +#define HNBU_ACPA_80 0x88 +#define HNBU_ACPA_4080 0x89 +#define HNBU_SUBBAND5GVER 0x8a +#define HNBU_PAPARAMBWVER 0x8b + + +#endif + + +#define SBTML_INT_ACK 0x40000 +#define SBTML_INT_EN 0x20000 + + +#define SBTMH_INT_STATUS 0x40000 + +#endif
diff --git a/src/include/sdiovar.h b/src/include/sdiovar.h new file mode 100644 index 0000000..285ec0b --- /dev/null +++ b/src/include/sdiovar.h
@@ -0,0 +1,63 @@ +/* + * Structure used by apps whose drivers access SDIO drivers. + * Pulled out separately so dhdu and wlu can both use it. + * + * $ Copyright Open Broadcom Corporation $ + * + * $Id: sdiovar.h 241182 2011-02-17 21:50:03Z $ + */ + +#ifndef _sdiovar_h_ +#define _sdiovar_h_ + +#include <typedefs.h> + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include <packed_section_start.h> + +typedef struct sdreg { + int func; + int offset; + int value; +} sdreg_t; + +/* Common msglevel constants */ +#define SDH_ERROR_VAL 0x0001 /* Error */ +#define SDH_TRACE_VAL 0x0002 /* Trace */ +#define SDH_INFO_VAL 0x0004 /* Info */ +#define SDH_DEBUG_VAL 0x0008 /* Debug */ +#define SDH_DATA_VAL 0x0010 /* Data */ +#define SDH_CTRL_VAL 0x0020 /* Control Regs */ +#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ +#define SDH_DMA_VAL 0x0080 /* DMA */ + +#define NUM_PREV_TRANSACTIONS 16 + +#ifdef BCMSPI +/* Error statistics for gSPI */ +struct spierrstats_t { + uint32 dna; /* The requested data is not available. */ + uint32 rdunderflow; /* FIFO underflow happened due to current (F2, F3) rd command */ + uint32 wroverflow; /* FIFO underflow happened due to current (F1, F2, F3) wr command */ + + uint32 f2interrupt; /* OR of all F2 related intr status bits. */ + uint32 f3interrupt; /* OR of all F3 related intr status bits. */ + + uint32 f2rxnotready; /* F2 FIFO is not ready to receive data (FIFO empty) */ + uint32 f3rxnotready; /* F3 FIFO is not ready to receive data (FIFO empty) */ + + uint32 hostcmddataerr; /* Error in command or host data, detected by CRC/checksum + * (optional) + */ + uint32 f2pktavailable; /* Packet is available in F2 TX FIFO */ + uint32 f3pktavailable; /* Packet is available in F2 TX FIFO */ + + uint32 dstatus[NUM_PREV_TRANSACTIONS]; /* dstatus bits of last 16 gSPI transactions */ + uint32 spicmd[NUM_PREV_TRANSACTIONS]; +}; +#endif /* BCMSPI */ + +#include <packed_section_end.h> + +#endif /* _sdiovar_h_ */
diff --git a/src/include/trxhdr.h b/src/include/trxhdr.h new file mode 100644 index 0000000..249527c --- /dev/null +++ b/src/include/trxhdr.h
@@ -0,0 +1,74 @@ +/* + * TRX image file header format. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: trxhdr.h 349211 2012-08-07 09:45:24Z $ + */ + +#ifndef _TRX_HDR_H +#define _TRX_HDR_H + +#include <typedefs.h> + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ +#define TRX_MAX_LEN 0x3B0000 /* Max length */ +#define TRX_NO_HEADER 1 /* Do not write TRX header */ +#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ +#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ +#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ +#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ +#define TRX_BOOTLOADER 0x40 /* the image is a bootloader */ + +#define TRX_V1 1 +#define TRX_V1_MAX_OFFSETS 3 /* V1: Max number of individual files */ + +#ifndef BCMTRXV2 +#define TRX_VERSION TRX_V1 /* Version 1 */ +#define TRX_MAX_OFFSET TRX_V1_MAX_OFFSETS +#endif + +/* BMAC Host driver/application like bcmdl need to support both Ver 1 as well as + * Ver 2 of trx header. To make it generic, trx_header is structure is modified + * as below where size of "offsets" field will vary as per the TRX version. + * Currently, BMAC host driver and bcmdl are modified to support TRXV2 as well. + * To make sure, other applications like "dhdl" which are yet to be enhanced to support + * TRXV2 are not broken, new macro and structure defintion take effect only when BCMTRXV2 + * is defined. + */ +struct trx_header { + uint32 magic; /* "HDR0" */ + uint32 len; /* Length of file including header */ + uint32 crc32; /* 32-bit CRC from flag_version to end of file */ + uint32 flag_version; /* 0:15 flags, 16:31 version */ +#ifndef BCMTRXV2 + uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ +#else + uint32 offsets[1]; /* Offsets of partitions from start of header */ +#endif +}; + +#ifdef BCMTRXV2 +#define TRX_VERSION TRX_V2 /* Version 2 */ +#define TRX_MAX_OFFSET TRX_V2_MAX_OFFSETS + +#define TRX_V2 2 +/* V2: Max number of individual files + * To support SDR signature + Config data region + */ +#define TRX_V2_MAX_OFFSETS 5 +#define SIZEOF_TRXHDR_V1 (sizeof(struct trx_header)+(TRX_V1_MAX_OFFSETS-1)*sizeof(uint32)) +#define SIZEOF_TRXHDR_V2 (sizeof(struct trx_header)+(TRX_V2_MAX_OFFSETS-1)*sizeof(uint32)) +#define TRX_VER(trx) (trx->flag_version>>16) +#define ISTRX_V1(trx) (TRX_VER(trx) == TRX_V1) +#define ISTRX_V2(trx) (TRX_VER(trx) == TRX_V2) +/* For V2, return size of V2 size: others, return V1 size */ +#define SIZEOF_TRX(trx) (ISTRX_V2(trx) ? SIZEOF_TRXHDR_V2: SIZEOF_TRXHDR_V1) +#else +#define SIZEOF_TRX(trx) (sizeof(struct trx_header)) +#endif /* BCMTRXV2 */ + +/* Compatibility */ +typedef struct trx_header TRXHDR, *PTRXHDR; + +#endif /* _TRX_HDR_H */
diff --git a/src/include/typedefs.h b/src/include/typedefs.h new file mode 100644 index 0000000..f4aad17 --- /dev/null +++ b/src/include/typedefs.h
@@ -0,0 +1,293 @@ +/* + * $Copyright Open Broadcom Corporation$ + * $Id: typedefs.h 453696 2014-02-06 01:10:20Z $ + */ + +#ifndef _TYPEDEFS_H_ +#define _TYPEDEFS_H_ + +#ifdef SITE_TYPEDEFS + + + +#include "site_typedefs.h" + +#else + + + +#ifdef __cplusplus + +#define TYPEDEF_BOOL +#ifndef FALSE +#define FALSE false +#endif +#ifndef TRUE +#define TRUE true +#endif + +#else + + +#endif + +#if defined(__LP64__) +#define TYPEDEF_UINTPTR +typedef unsigned long long int uintptr; +#endif + + + + + +#if defined(_NEED_SIZE_T_) +typedef long unsigned int size_t; +#endif + + + + + +#if defined(__sparc__) +#define TYPEDEF_ULONG +#endif + + + +#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) +#define TYPEDEF_UINT +#ifndef TARGETENV_android +#define TYPEDEF_USHORT +#define TYPEDEF_ULONG +#endif +#ifdef __KERNEL__ +#include <linux/version.h> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) +#define TYPEDEF_BOOL +#endif + +#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) +#include <linux/compiler.h> +#ifdef noinline_for_stack +#define TYPEDEF_BOOL +#endif +#endif +#endif +#endif + + + + + +#if defined(__GNUC__) && defined(__STRICT_ANSI__) +#define TYPEDEF_INT64 +#define TYPEDEF_UINT64 +#endif + + +#if defined(__ICL) + +#define TYPEDEF_INT64 + +#if defined(__STDC__) +#define TYPEDEF_UINT64 +#endif + +#endif + +#if !defined(__DJGPP__) + + +#if defined(__KERNEL__) + + +#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) +#include <linux/types.h> +#endif + +#else + + +#include <sys/types.h> + +#endif + +#endif + + + + +#define USE_TYPEDEF_DEFAULTS + +#endif + + + + +#ifdef USE_TYPEDEF_DEFAULTS +#undef USE_TYPEDEF_DEFAULTS + +#ifndef TYPEDEF_BOOL +typedef unsigned char bool; +#endif + + + +#ifndef TYPEDEF_UCHAR +typedef unsigned char uchar; +#endif + +#ifndef TYPEDEF_USHORT +typedef unsigned short ushort; +#endif + +#ifndef TYPEDEF_UINT +typedef unsigned int uint; +#endif + +#ifndef TYPEDEF_ULONG +typedef unsigned long ulong; +#endif + + + +#ifndef TYPEDEF_UINT8 +typedef unsigned char uint8; +#endif + +#ifndef TYPEDEF_UINT16 +typedef unsigned short uint16; +#endif + +#ifndef TYPEDEF_UINT32 +typedef unsigned int uint32; +#endif + +#ifndef TYPEDEF_UINT64 +typedef unsigned long long uint64; +#endif + +#ifndef TYPEDEF_UINTPTR +typedef unsigned int uintptr; +#endif + +#ifndef TYPEDEF_INT8 +typedef signed char int8; +#endif + +#ifndef TYPEDEF_INT16 +typedef signed short int16; +#endif + +#ifndef TYPEDEF_INT32 +typedef signed int int32; +#endif + +#ifndef TYPEDEF_INT64 +typedef signed long long int64; +#endif + + + +#ifndef TYPEDEF_FLOAT32 +typedef float float32; +#endif + +#ifndef TYPEDEF_FLOAT64 +typedef double float64; +#endif + + + +#ifndef TYPEDEF_FLOAT_T + +#if defined(FLOAT32) +typedef float32 float_t; +#else +typedef float64 float_t; +#endif + +#endif + + + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef OFF +#define OFF 0 +#endif + +#ifndef ON +#define ON 1 +#endif + +#define AUTO (-1) + + + +#ifndef PTRSZ +#define PTRSZ sizeof(char*) +#endif + + + +#if defined(__GNUC__) || defined(__lint) + #define BWL_COMPILER_GNU +#elif defined(__CC_ARM) && __CC_ARM + #define BWL_COMPILER_ARMCC +#else + #error "Unknown compiler!" +#endif + + +#ifndef INLINE + #if defined(BWL_COMPILER_MICROSOFT) + #define INLINE __inline + #elif defined(BWL_COMPILER_GNU) + #define INLINE __inline__ + #elif defined(BWL_COMPILER_ARMCC) + #define INLINE __inline + #else + #define INLINE + #endif +#endif + +#undef TYPEDEF_BOOL +#undef TYPEDEF_UCHAR +#undef TYPEDEF_USHORT +#undef TYPEDEF_UINT +#undef TYPEDEF_ULONG +#undef TYPEDEF_UINT8 +#undef TYPEDEF_UINT16 +#undef TYPEDEF_UINT32 +#undef TYPEDEF_UINT64 +#undef TYPEDEF_UINTPTR +#undef TYPEDEF_INT8 +#undef TYPEDEF_INT16 +#undef TYPEDEF_INT32 +#undef TYPEDEF_INT64 +#undef TYPEDEF_FLOAT32 +#undef TYPEDEF_FLOAT64 +#undef TYPEDEF_FLOAT_T + +#endif + + +#define UNUSED_PARAMETER(x) (void)(x) + + +#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) + + +#include <bcmdefs.h> +#endif
diff --git a/src/include/usbrdl.h b/src/include/usbrdl.h new file mode 100644 index 0000000..5ceed33 --- /dev/null +++ b/src/include/usbrdl.h
@@ -0,0 +1,212 @@ +/* + * Broadcom USB remote download definitions + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: usbrdl.h 412875 2013-07-16 23:54:25Z $ + */ + +#ifndef _USB_RDL_H +#define _USB_RDL_H + +/* Control messages: bRequest values */ +#define DL_GETSTATE 0 /* returns the rdl_state_t struct */ +#define DL_CHECK_CRC 1 /* currently unused */ +#define DL_GO 2 /* execute downloaded image */ +#define DL_START 3 /* initialize dl state */ +#define DL_REBOOT 4 /* reboot the device in 2 seconds */ +#define DL_GETVER 5 /* returns the bootrom_id_t struct */ +#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset event + * to occur in 2 seconds. It is the responsibility + * of the downloaded code to clear this event + */ +#define DL_EXEC 7 /* jump to a supplied address */ +#define DL_RESETCFG 8 /* To support single enum on dongle + * - Not used by bootloader + */ +#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup + * if resp unavailable + */ +#define DL_CHGSPD 0x0A + +#define DL_HWCMD_MASK 0xfc /* Mask for hardware read commands: */ +#define DL_RDHW 0x10 /* Read a hardware address (Ctl-in) */ +#define DL_RDHW32 0x10 /* Read a 32 bit word */ +#define DL_RDHW16 0x11 /* Read 16 bits */ +#define DL_RDHW8 0x12 /* Read an 8 bit byte */ +#define DL_WRHW 0x14 /* Write a hardware address (Ctl-out) */ +#define DL_WRHW_BLK 0x13 /* Block write to hardware access */ + +#define DL_CMD_RDHW 1 /* read data from a backplane address */ +#define DL_CMD_WRHW 2 /* write data to a backplane address */ + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +#define DL_JTCONF 0x15 /* Get JTAG configuration (Ctl_in) + * Set JTAG configuration (Ctl-out) + */ +#define DL_JTON 0x16 /* Turn on jtag master (Ctl-in) */ +#define DL_JTOFF 0x17 /* Turn on jtag master (Ctl-in) */ +#define DL_RDRJT 0x18 /* Read a JTAG register (Ctl-in) */ +#define DL_WRJT 0x19 /* Write a hardware address over JTAG (Ctl/Bulk-out) */ +#define DL_WRRJT 0x1a /* Write a JTAG register (Ctl/Bulk-out) */ +#define DL_JTRST 0x1b /* Reset jtag fsm on jtag DUT (Ctl-in) */ + +#define DL_RDJT 0x1c /* Read a hardware address over JTAG (Ctl-in) */ +#define DL_RDJT32 0x1c /* Read 32 bits */ +#define DL_RDJT16 0x1e /* Read 16 bits (sz = 4 - low bits) */ +#define DL_RDJT8 0x1f /* Read 8 bits */ + +#define DL_MRDJT 0x20 /* Multiple read over JTAG (Ctl-out+Bulk-in) */ +#define DL_MRDJT32 0x20 /* M-read 32 bits */ +#define DL_MRDJT16 0x22 /* M-read 16 bits (sz = 4 - low bits) */ +#define DL_MRDJT6 0x23 /* M-read 8 bits */ +#define DL_MRDIJT 0x24 /* M-read over JTAG (Ctl-out+Bulk-in) with auto-increment */ +#define DL_MRDIJT32 0x24 /* M-read 32 bits w/ai */ +#define DL_MRDIJT16 0x26 /* M-read 16 bits w/ai (sz = 4 - low bits) */ +#define DL_MRDIJT8 0x27 /* M-read 8 bits w/ai */ +#define DL_MRDDJT 0x28 /* M-read over JTAG (Ctl-out+Bulk-in) with auto-decrement */ +#define DL_MRDDJT32 0x28 /* M-read 32 bits w/ad */ +#define DL_MRDDJT16 0x2a /* M-read 16 bits w/ad (sz = 4 - low bits) */ +#define DL_MRDDJT8 0x2b /* M-read 8 bits w/ad */ +#define DL_MWRJT 0x2c /* Multiple write over JTAG (Bulk-out) */ +#define DL_MWRIJT 0x2d /* With auto-increment */ +#define DL_MWRDJT 0x2e /* With auto-decrement */ +#define DL_VRDJT 0x2f /* Vector read over JTAG (Bulk-out+Bulk-in) */ +#define DL_VWRJT 0x30 /* Vector write over JTAG (Bulk-out+Bulk-in) */ +#define DL_SCJT 0x31 /* Jtag scan (Bulk-out+Bulk-in) */ + +#define DL_CFRD 0x33 /* Reserved for dmamem use */ +#define DL_CFWR 0x34 /* Reserved for dmamem use */ +#define DL_GET_NVRAM 0x35 /* Query nvram parameter */ + +#define DL_DBGTRIG 0xFF /* Trigger bRequest type to aid debug */ + +#define DL_JTERROR 0x80000000 +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* states */ +#define DL_WAITING 0 /* waiting to rx first pkt that includes the hdr info */ +#define DL_READY 1 /* hdr was good, waiting for more of the compressed image */ +#define DL_BAD_HDR 2 /* hdr was corrupted */ +#define DL_BAD_CRC 3 /* compressed image was corrupted */ +#define DL_RUNNABLE 4 /* download was successful, waiting for go cmd */ +#define DL_START_FAIL 5 /* failed to initialize correctly */ +#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM value */ +#define DL_IMAGE_TOOBIG 7 /* download image too big (exceeds DATA_START for rdl) */ + +#define TIMEOUT 5000 /* Timeout for usb commands */ + +struct bcm_device_id { + char *name; + uint32 vend; + uint32 prod; +}; + +typedef struct { + uint32 state; + uint32 bytes; +} rdl_state_t; + +typedef struct { + uint32 chip; /* Chip id */ + uint32 chiprev; /* Chip rev */ + uint32 ramsize; /* Size of RAM */ + uint32 remapbase; /* Current remap base address */ + uint32 boardtype; /* Type of board */ + uint32 boardrev; /* Board revision */ +} bootrom_id_t; + +/* struct for backplane & jtag accesses */ +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + uint32 addr; /* backplane address for write */ + uint32 len; /* length of data: 1, 2, 4 bytes */ + uint32 data; /* data to write */ +} hwacc_t; + +/* struct for backplane */ +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + uint32 addr; /* backplane address for write */ + uint32 len; /* length of data: 1, 2, 4 bytes */ + uint8 data[1]; /* data to write */ +} hwacc_blk_t; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +typedef struct { + uint32 chip; /* Chip id */ + uint32 chiprev; /* Chip rev */ + uint32 ccrev; /* Chipcommon core rev */ + uint32 siclock; /* Backplane clock */ +} jtagd_id_t; + +/* Jtag configuration structure */ +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + uint8 clkd; /* Jtag clock divisor */ + uint8 disgpio; /* Gpio to disable external driver */ + uint8 irsz; /* IR size for readreg/writereg */ + uint8 drsz; /* DR size for readreg/writereg */ + + uint8 bigend; /* Big endian */ + uint8 mode; /* Current mode */ + uint16 delay; /* Delay between jtagm "simple commands" */ + + uint32 retries; /* Number of retries for jtagm operations */ + uint32 ctrl; /* Jtag control reg copy */ + uint32 ir_lvbase; /* Bits to add to IR values in LV tap */ + uint32 dretries; /* Number of retries for dma operations */ +} jtagconf_t; + +/* struct for jtag scan */ +#define MAX_USB_IR_BITS 256 +#define MAX_USB_DR_BITS 3072 +#define USB_IR_WORDS (MAX_USB_IR_BITS / 32) +#define USB_DR_WORDS (MAX_USB_DR_BITS / 32) +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + uint32 irsz; /* IR size in bits */ + uint32 drsz; /* DR size in bits */ + uint32 ts; /* Terminal state (def, pause, rti) */ + uint32 data[USB_IR_WORDS + USB_DR_WORDS]; /* IR & DR data */ +} scjt_t; +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* struct for querying nvram params from bootloader */ +#define QUERY_STRING_MAX 32 +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + char var[QUERY_STRING_MAX]; /* param name */ +} nvparam_t; + +typedef void (*exec_fn_t)(void *sih); + +#define USB_CTRL_IN (USB_TYPE_VENDOR | 0x80 | USB_RECIP_INTERFACE) +#define USB_CTRL_OUT (USB_TYPE_VENDOR | 0 | USB_RECIP_INTERFACE) + +#define USB_CTRL_EP_TIMEOUT 500 /* Timeout used in USB control_msg transactions. */ + +#define RDL_CHUNK 1500 /* size of each dl transfer */ + +/* bootloader makes special use of trx header "offsets" array */ +#define TRX_OFFSETS_DLFWLEN_IDX 0 /* Size of the fw; used in uncompressed case */ +#define TRX_OFFSETS_JUMPTO_IDX 1 /* RAM address for jumpto after download */ +#define TRX_OFFSETS_NVM_LEN_IDX 2 /* Length of appended NVRAM data */ +#ifdef BCMTRXV2 +/* The NVRAM region part of trx will be digitally signed in SDR image, + * so is the need for new cfg region which could pass parameters + * which dones not need to be digitally signed + */ +#define TRX_OFFSETS_DSG_LEN_IDX 3 /* Length of digital signature for the first image */ +#define TRX_OFFSETS_CFG_LEN_IDX 4 /* Length of config region, which is not digitally signed */ +#endif /* BCMTRXV2 */ + +#define TRX_OFFSETS_DLBASE_IDX 0 /* RAM start address for download */ + +#endif /* _USB_RDL_H */
diff --git a/src/include/wlc_extlog_idstr.h b/src/include/wlc_extlog_idstr.h new file mode 100644 index 0000000..f0f3507 --- /dev/null +++ b/src/include/wlc_extlog_idstr.h
@@ -0,0 +1,117 @@ +/* + * EXTLOG Module log ID to log Format String mapping table + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlc_extlog_idstr.h 241182 2011-02-17 21:50:03Z $ + */ +#ifndef _WLC_EXTLOG_IDSTR_H_ +#define _WLC_EXTLOG_IDSTR_H_ + +#include "wlioctl.h" + +/* Strings corresponding to the IDs defined in wlioctl.h + * This file is only included by the apps and not included by the external driver + * Formats of pre-existing ids should NOT be changed + */ +log_idstr_t extlog_fmt_str[ ] = { + {FMTSTR_DRIVER_UP_ID, 0, LOG_ARGTYPE_NULL, + "Driver is Up\n"}, + + {FMTSTR_DRIVER_DOWN_ID, 0, LOG_ARGTYPE_NULL, + "Driver is Down\n"}, + + {FMTSTR_SUSPEND_MAC_FAIL_ID, 0, LOG_ARGTYPE_INT, + "wlc_suspend_mac_and_wait() failed with psmdebug 0x%08x\n"}, + + {FMTSTR_NO_PROGRESS_ID, 0, LOG_ARGTYPE_INT, + "No Progress on TX for %d seconds\n"}, + + {FMTSTR_RFDISABLE_ID, 0, LOG_ARGTYPE_INT, + "Detected a change in RF Disable Input 0x%x\n"}, + + {FMTSTR_REG_PRINT_ID, 0, LOG_ARGTYPE_STR_INT, + "Register %s = 0x%x\n"}, + + {FMTSTR_EXPTIME_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Strong RF interference detected\n"}, + + {FMTSTR_JOIN_START_ID, FMTSTRF_USER, LOG_ARGTYPE_STR, + "Searching for networks with ssid %s\n"}, + + {FMTSTR_JOIN_COMPLETE_ID, FMTSTRF_USER, LOG_ARGTYPE_STR, + "Successfully joined network with BSSID %s\n"}, + + {FMTSTR_NO_NETWORKS_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "No networks found. Please check if the network exists and is in range\n"}, + + {FMTSTR_SECURITY_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "AP rejected due to security mismatch. Change the security settings and try again...\n"}, + + {FMTSTR_RATE_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "AP rejected due to rate mismatch\n"}, + + {FMTSTR_AP_PRUNED_ID, 0, LOG_ARGTYPE_INT, + "AP rejected due to reason %d\n"}, + + {FMTSTR_KEY_INSERTED_ID, 0, LOG_ARGTYPE_INT, + "Inserting keys for algorithm %d\n"}, + + {FMTSTR_DEAUTH_ID, FMTSTRF_USER, LOG_ARGTYPE_STR_INT, + "Received Deauth from %s with Reason %d\n"}, + + {FMTSTR_DISASSOC_ID, FMTSTRF_USER, LOG_ARGTYPE_STR_INT, + "Received Disassoc from %s with Reason %d\n"}, + + {FMTSTR_LINK_UP_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Link Up\n"}, + + {FMTSTR_LINK_DOWN_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Link Down\n"}, + + {FMTSTR_RADIO_HW_OFF_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Radio button is turned OFF. Please turn it on...\n"}, + + {FMTSTR_RADIO_HW_ON_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Hardware Radio button is turned ON\n"}, + + {FMTSTR_EVENT_DESC_ID, 0, LOG_ARGTYPE_INT_STR, + "Generated event id %d: (result status) is (%s)\n"}, + + {FMTSTR_PNP_SET_POWER_ID, 0, LOG_ARGTYPE_INT, + "Device going into power state %d\n"}, + + {FMTSTR_RADIO_SW_OFF_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Software Radio is disabled. Please enable it through the UI...\n"}, + + {FMTSTR_RADIO_SW_ON_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Software Radio is enabled\n"}, + + {FMTSTR_PWD_MISMATCH_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Potential passphrase mismatch. Please try a different one...\n"}, + + {FMTSTR_FATAL_ERROR_ID, 0, LOG_ARGTYPE_INT, + "Fatal Error: intstatus 0x%x\n"}, + + {FMTSTR_AUTH_FAIL_ID, 0, LOG_ARGTYPE_STR_INT, + "Authentication to %s Failed with status %d\n"}, + + {FMTSTR_ASSOC_FAIL_ID, 0, LOG_ARGTYPE_STR_INT, + "Association to %s Failed with status %d\n"}, + + {FMTSTR_IBSS_FAIL_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Unable to start IBSS since PeerNet is already active\n"}, + + {FMTSTR_EXTAP_FAIL_ID, FMTSTRF_USER, LOG_ARGTYPE_NULL, + "Unable to start Ext-AP since PeerNet is already active\n"}, + + {FMTSTR_MAX_ID, 0, 0, "\0"} +}; + +#endif /* _WLC_EXTLOG_IDSTR_H_ */
diff --git a/src/include/wlioctl.h b/src/include/wlioctl.h new file mode 100644 index 0000000..bbdf458 --- /dev/null +++ b/src/include/wlioctl.h
@@ -0,0 +1,4455 @@ +/* + * Custom OID/ioctl definitions for + * Broadcom 802.11abg Networking Device Driver + * + * Definitions subject to change without notice. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: wlioctl.h 647609 2016-07-06 21:27:18Z $ + */ + +#ifndef _wlioctl_h_ +#define _wlioctl_h_ + +#include <typedefs.h> +#include <proto/ethernet.h> +#include <proto/bcmip.h> +#include <proto/bcmeth.h> +#include <proto/bcmip.h> +#include <proto/bcmevent.h> +#include <proto/802.11.h> +#include <proto/802.1d.h> +#include <bcmwifi_channels.h> +#include <bcmwifi_rates.h> +#include <devctrl_if/wlioctl_defs.h> + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +#include <bcm_mpool_pub.h> +#include <bcmcdc.h> +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + + + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +#ifndef INTF_NAME_SIZ +#define INTF_NAME_SIZ 16 +#endif + +/* Used to send ioctls over the transport pipe */ +typedef struct remote_ioctl { + cdc_ioctl_t msg; + uint32 data_len; + char intf_name[INTF_NAME_SIZ]; +} rem_ioctl_t; +#define REMOTE_SIZE sizeof(rem_ioctl_t) + +typedef struct { + uint32 num; + chanspec_t list[1]; +} chanspec_list_t; + +/* association decision information */ +typedef struct { + bool assoc_approved; /* (re)association approved */ + uint16 reject_reason; /* reason code for rejecting association */ + struct ether_addr da; +#if 0 && (NDISVER >= 0x0620) + LARGE_INTEGER sys_time; /* current system time */ +#else + int64 sys_time; /* current system time */ +#endif +} assoc_decision_t; + +#define ACTION_FRAME_SIZE 1800 + +typedef struct wl_action_frame { + struct ether_addr da; + uint16 len; + uint32 packetId; + uint8 data[ACTION_FRAME_SIZE]; +} wl_action_frame_t; + +#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) + +typedef struct ssid_info +{ + uint8 ssid_len; /* the length of SSID */ + uint8 ssid[32]; /* SSID string */ +} ssid_info_t; + +typedef struct wl_af_params { + uint32 channel; + int32 dwell_time; + struct ether_addr BSSID; + wl_action_frame_t action_frame; +} wl_af_params_t; + +#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) + +#define MFP_TEST_FLAG_NORMAL 0 +#define MFP_TEST_FLAG_ANY_KEY 1 +typedef struct wl_sa_query { + uint32 flag; + uint8 action; + uint16 id; + struct ether_addr da; +} wl_sa_query_t; + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* require default structure packing */ +#define BWL_DEFAULT_PACKING +#include <packed_section_start.h> + + + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +/* Legacy structure to help keep backward compatible wl tool and tray app */ + +#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ + +typedef struct wl_bss_info_107 { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + uint8 channel; /* Channel no. */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + uint32 ie_length; /* byte length of Information Elements */ + /* variable length Information Elements */ +} wl_bss_info_107_t; + +/* + * Per-BSS information structure. + */ + +#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in wl_scan_results_t) + */ +typedef struct wl_bss_info_108 { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + chanspec_t chanspec; /* chanspec for bss */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + + uint8 n_cap; /* BSS is 802.11N Capable */ + uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ + uint8 ctl_ch; /* 802.11N BSS control channel number */ + uint32 reserved32[1]; /* Reserved for expansion of BSS properties */ + uint8 flags; /* flags */ + uint8 reserved[3]; /* Reserved for expansion of BSS properties */ + uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + uint16 ie_offset; /* offset at which IEs start, from beginning */ + uint32 ie_length; /* byte length of Information Elements */ + /* Add new fields here */ + /* variable length Information Elements */ +} wl_bss_info_108_t; + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */ + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in wl_scan_results_t) + */ +typedef struct wl_bss_info { + uint32 version; /* version field */ + uint32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + struct ether_addr BSSID; + uint16 beacon_period; /* units are Kusec */ + uint16 capability; /* Capability information */ + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; /* # rates in this set */ + uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + chanspec_t chanspec; /* chanspec for bss */ + uint16 atim_window; /* units are Kusec */ + uint8 dtim_period; /* DTIM period */ + int16 RSSI; /* receive signal strength (in dBm) */ + int8 phy_noise; /* noise (in dBm) */ + + uint8 n_cap; /* BSS is 802.11N Capable */ + uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ + uint8 ctl_ch; /* 802.11N BSS control channel number */ + uint8 padding1[3]; /* explicit struct alignment padding */ + uint16 vht_rxmcsmap; /* VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ + uint16 vht_txmcsmap; /* VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ + uint8 flags; /* flags */ + uint8 vht_cap; /* BSS is vht capable */ + uint8 reserved[2]; /* Reserved for expansion of BSS properties */ + uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + uint16 ie_offset; /* offset at which IEs start, from beginning */ + uint32 ie_length; /* byte length of Information Elements */ + int16 SNR; /* average SNR of during frame reception */ + /* Add new fields here */ + /* variable length Information Elements */ +} wl_bss_info_t; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +typedef struct wl_bsscfg { + uint32 bsscfg_idx; + uint32 wsec; + uint32 WPA_auth; + uint32 wsec_index; + uint32 associated; + uint32 BSS; + uint32 phytest_on; + struct ether_addr prev_BSSID; + struct ether_addr BSSID; + uint32 targetbss_wpa2_flags; + uint32 assoc_type; + uint32 assoc_state; +} wl_bsscfg_t; + +typedef struct wl_if_add { + uint32 bsscfg_flags; + uint32 if_flags; + uint32 ap; + struct ether_addr mac_addr; +} wl_if_add_t; + +typedef struct wl_bss_config { + uint32 atim_window; + uint32 beacon_period; + uint32 chanspec; +} wl_bss_config_t; + +#define WL_BSS_USER_RADAR_CHAN_SELECT 0x1 /* User application will randomly select + * radar channel. + */ + +#define DLOAD_HANDLER_VER 1 /* Downloader version */ +#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ +#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ + +#define DL_CRC_NOT_INUSE 0x0001 + +/* generic download types & flags */ +enum { + DL_TYPE_UCODE = 1, + DL_TYPE_CLM = 2 +}; + +/* ucode type values */ +enum { + UCODE_FW, + INIT_VALS, + BS_INIT_VALS +}; + +struct wl_dload_data { + uint16 flag; + uint16 dload_type; + uint32 len; + uint32 crc; + uint8 data[1]; +}; +typedef struct wl_dload_data wl_dload_data_t; + +struct wl_ucode_info { + uint32 ucode_type; + uint32 num_chunks; + uint32 chunk_len; + uint32 chunk_num; + uint8 data_chunk[1]; +}; +typedef struct wl_ucode_info wl_ucode_info_t; + +struct wl_clm_dload_info { + uint32 ds_id; + uint32 clm_total_len; + uint32 num_chunks; + uint32 chunk_len; + uint32 chunk_offset; + uint8 data_chunk[1]; +}; +typedef struct wl_clm_dload_info wl_clm_dload_info_t; + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +typedef struct wlc_ssid { + uint32 SSID_len; + uchar SSID[DOT11_MAX_SSID_LEN]; +} wlc_ssid_t; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +#define MAX_PREFERRED_AP_NUM 5 +typedef struct wlc_fastssidinfo { + uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; + wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; +} wlc_fastssidinfo_t; + +typedef BWL_PRE_PACKED_STRUCT struct wnm_url { + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT wnm_url_t; + +typedef struct chan_scandata { + uint8 txpower; + uint8 pad; + chanspec_t channel; /* Channel num, bw, ctrl_sb and band */ + uint32 channel_mintime; + uint32 channel_maxtime; +} chan_scandata_t; + +typedef enum wl_scan_type { + EXTDSCAN_FOREGROUND_SCAN, + EXTDSCAN_BACKGROUND_SCAN, + EXTDSCAN_FORCEDBACKGROUND_SCAN +} wl_scan_type_t; + +#define WLC_EXTDSCAN_MAX_SSID 5 + +typedef struct wl_extdscan_params { + int8 nprobes; /* 0, passive, otherwise active */ + int8 split_scan; /* split scan */ + int8 band; /* band */ + int8 pad; + wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /* ssid list */ + uint32 tx_rate; /* in 500ksec units */ + wl_scan_type_t scan_type; /* enum */ + int32 channel_num; + chan_scandata_t channel_list[1]; /* list of chandata structs */ +} wl_extdscan_params_t; + +#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) + +#define WL_SCAN_PARAMS_SSID_MAX 10 + +typedef struct wl_scan_params { + wlc_ssid_t ssid; /* default: {0, ""} */ + struct ether_addr bssid; /* default: bcast */ + int8 bss_type; /* default: any, + * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT + */ + uint8 scan_type; /* flags, 0 use default */ + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + int32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + int32 home_time; /* -1 use default, dwell time for the home channel + * between channel scans + */ + int32 channel_num; /* count of channels and ssids that follow + * + * low half is count of channels in channel_list, 0 + * means default (use all available channels) + * + * high half is entries in wlc_ssid_t array that + * follows channel_list, aligned for int32 (4 bytes) + * meaning an odd channel count implies a 2-byte pad + * between end of channel_list and first ssid + * + * if ssid count is zero, single ssid in the fixed + * parameter portion is assumed, otherwise ssid in + * the fixed portion is ignored + */ + uint16 channel_list[1]; /* list of chanspecs */ +} wl_scan_params_t; + +/* size of wl_scan_params not including variable length array */ +#define WL_SCAN_PARAMS_FIXED_SIZE 64 + +#define ISCAN_REQ_VERSION 1 + +/* incremental scan struct */ +typedef struct wl_iscan_params { + uint32 version; + uint16 action; + uint16 scan_duration; + wl_scan_params_t params; +} wl_iscan_params_t; + +/* 3 fields + size of wl_scan_params, not including variable length array */ +#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +typedef struct wl_scan_results { + uint32 buflen; + uint32 version; + uint32 count; + wl_bss_info_t bss_info[1]; +} wl_scan_results_t; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +/* size of wl_scan_results not including variable length array */ +#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) + +/* Used in EXT_STA */ +#define DNGL_RXCTXT_SIZE 45 + +#if defined(SIMPLE_ISCAN) +/* the buf lengh can be WLC_IOCTL_MAXLEN (8K) to reduce iteration */ +#define WLC_IW_ISCAN_MAXLEN 2048 +typedef struct iscan_buf { + struct iscan_buf * next; + char iscan_buf[WLC_IW_ISCAN_MAXLEN]; +} iscan_buf_t; +#endif /* SIMPLE_ISCAN */ + +#define ESCAN_REQ_VERSION 1 + +typedef struct wl_escan_params { + uint32 version; + uint16 action; + uint16 sync_id; + wl_scan_params_t params; +} wl_escan_params_t; + +#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) + +typedef struct wl_escan_result { + uint32 buflen; + uint32 version; + uint16 sync_id; + uint16 bss_count; + wl_bss_info_t bss_info[1]; +} wl_escan_result_t; + +#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) + +/* incremental scan results struct */ +typedef struct wl_iscan_results { + uint32 status; + wl_scan_results_t results; +} wl_iscan_results_t; + +/* size of wl_iscan_results not including variable length array */ +#define WL_ISCAN_RESULTS_FIXED_SIZE \ + (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) + +#define SCANOL_PARAMS_VERSION 1 + +typedef struct scanol_params { + uint32 version; + uint32 flags; /* offload scanning flags */ + int32 active_time; /* -1 use default, dwell time per channel for active scanning */ + int32 passive_time; /* -1 use default, dwell time per channel for passive scanning */ + int32 idle_rest_time; /* -1 use default, time idle between scan cycle */ + int32 idle_rest_time_multiplier; + int32 active_rest_time; + int32 active_rest_time_multiplier; + int32 scan_cycle_idle_rest_time; + int32 scan_cycle_idle_rest_multiplier; + int32 scan_cycle_active_rest_time; + int32 scan_cycle_active_rest_multiplier; + int32 max_rest_time; + int32 max_scan_cycles; + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 scan_start_delay; + uint32 nchannels; + uint32 ssid_count; + wlc_ssid_t ssidlist[1]; +} scanol_params_t; + +typedef struct wl_probe_params { + wlc_ssid_t ssid; + struct ether_addr bssid; + struct ether_addr mac; +} wl_probe_params_t; +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +#define WL_MAXRATES_IN_SET 16 /* max # of rates in a rateset */ +typedef struct wl_rateset { + uint32 count; /* # rates in this set */ + uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ +} wl_rateset_t; + +typedef struct wl_rateset_args { + uint32 count; /* # rates in this set */ + uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ + uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ + uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; /* supported mcs index bit map per nss */ +} wl_rateset_args_t; + +#define TXBF_RATE_MCS_ALL 4 +#define TXBF_RATE_VHT_ALL 4 +#define TXBF_RATE_OFDM_ALL 8 + +typedef struct wl_txbf_rateset { + uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL]; /* one for each stream */ + uint8 txbf_rate_mcs_bcm[TXBF_RATE_MCS_ALL]; /* one for each stream */ + uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL]; /* one for each stream */ + uint16 txbf_rate_vht_bcm[TXBF_RATE_VHT_ALL]; /* one for each stream */ + uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ + uint8 txbf_rate_ofdm_bcm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ + uint8 txbf_rate_ofdm_cnt; + uint8 txbf_rate_ofdm_cnt_bcm; +} wl_txbf_rateset_t; + +#define OFDM_RATE_MASK 0x0000007f +typedef uint8 ofdm_rates_t; + +typedef struct wl_rates_info { + wl_rateset_t rs_tgt; + uint32 phy_type; + int32 bandtype; + uint8 cck_only; + uint8 rate_mask; + uint8 mcsallow; + uint8 bw; + uint8 txstreams; +} wl_rates_info_t; + +/* uint32 list */ +typedef struct wl_uint32_list { + /* in - # of elements, out - # of entries */ + uint32 count; + /* variable length uint32 list */ + uint32 element[1]; +} wl_uint32_list_t; + +/* used for association with a specific BSSID and chanspec list */ +typedef struct wl_assoc_params { + struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ + uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, + * otherwise count of chanspecs in chanspec_list + * AND paired bssids following chanspec_list + * also, chanspec_num has to be set to zero + * for bssid list to be used + */ + int32 chanspec_num; /* 0: all available channels, + * otherwise count of chanspecs in chanspec_list + */ + chanspec_t chanspec_list[1]; /* list of chanspecs */ +} wl_assoc_params_t; + +#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) + +/* used for reassociation/roam to a specific BSSID and channel */ +typedef wl_assoc_params_t wl_reassoc_params_t; +#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + +/* used for association to a specific BSSID and channel */ +typedef wl_assoc_params_t wl_join_assoc_params_t; +#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + +/* used for join with or without a specific bssid and channel list */ +typedef struct wl_join_params { + wlc_ssid_t ssid; + wl_assoc_params_t params; /* optional field, but it must include the fixed portion + * of the wl_assoc_params_t struct when it does present. + */ +} wl_join_params_t; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ + WL_ASSOC_PARAMS_FIXED_SIZE) +/* scan params for extended join */ +typedef struct wl_join_scan_params { + uint8 scan_type; /* 0 use default, active or passive scan */ + int32 nprobes; /* -1 use default, number of probes per channel */ + int32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + int32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + int32 home_time; /* -1 use default, dwell time for the home channel + * between channel scans + */ +} wl_join_scan_params_t; + +/* extended join params */ +typedef struct wl_extjoin_params { + wlc_ssid_t ssid; /* {0, ""}: wildcard scan */ + wl_join_scan_params_t scan; + wl_join_assoc_params_t assoc; /* optional field, but it must include the fixed portion + * of the wl_join_assoc_params_t struct when it does + * present. + */ +} wl_extjoin_params_t; +#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ + WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) + +#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */ +#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ +typedef struct { + uint8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ + uint8 num_antcfg; /* number of available antenna configurations */ +} wlc_antselcfg_t; + +typedef struct { + uint32 duration; /* millisecs spent sampling this channel */ + uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ + /* move if cur bss moves channels) */ + uint32 congest_obss; /* traffic not in our bss */ + uint32 interference; /* millisecs detecting a non 802.11 interferer. */ + uint32 timestamp; /* second timestamp */ +} cca_congest_t; + +typedef struct { + chanspec_t chanspec; /* Which channel? */ + uint8 num_secs; /* How many secs worth of data */ + cca_congest_t secs[1]; /* Data */ +} cca_congest_channel_req_t; + +/* interference sources */ +enum interference_source { + ITFR_NONE = 0, /* interference */ + ITFR_PHONE, /* wireless phone */ + ITFR_VIDEO_CAMERA, /* wireless video camera */ + ITFR_MICROWAVE_OVEN, /* microwave oven */ + ITFR_BABY_MONITOR, /* wireless baby monitor */ + ITFR_BLUETOOTH, /* bluetooth */ + ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /* wireless camera or baby monitor */ + ITFR_BLUETOOTH_OR_BABY_MONITOR, /* bluetooth or baby monitor */ + ITFR_VIDEO_CAMERA_OR_PHONE, /* video camera or phone */ + ITFR_UNIDENTIFIED /* interference from unidentified source */ +}; + +/* structure for interference source report */ +typedef struct { + uint32 flags; /* flags. bit definitions below */ + uint32 source; /* last detected interference source */ + uint32 timestamp; /* second timestamp on interferenced flag change */ +} interference_source_rep_t; +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +typedef struct wl_country { + char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in + * the Country IE + */ + int32 rev; /* revision specifier for ccode + * on set, -1 indicates unspecified. + * on get, rev >= 0 + */ + char ccode[WLC_CNTRY_BUF_SZ]; /* nul-terminated built-in country code. + * variable length, but fixed size in + * struct allows simple allocation for + * expected country strings <= 3 chars. + */ +} wl_country_t; + +typedef struct wl_channels_in_country { + uint32 buflen; + uint32 band; + char country_abbrev[WLC_CNTRY_BUF_SZ]; + uint32 count; + uint32 channel[1]; +} wl_channels_in_country_t; + +typedef struct wl_country_list { + uint32 buflen; + uint32 band_set; + uint32 band; + uint32 count; + char country_abbrev[1]; +} wl_country_list_t; + +typedef struct wl_rm_req_elt { + int8 type; + int8 flags; + chanspec_t chanspec; + uint32 token; /* token for this measurement */ + uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ + uint32 tsf_l; /* TSF low 32-bits */ + uint32 dur; /* TUs */ +} wl_rm_req_elt_t; + +typedef struct wl_rm_req { + uint32 token; /* overall measurement set token */ + uint32 count; /* number of measurement requests */ + void *cb; /* completion callback function: may be NULL */ + void *cb_arg; /* arg to completion callback function */ + wl_rm_req_elt_t req[1]; /* variable length block of requests */ +} wl_rm_req_t; +#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) + +typedef struct wl_rm_rep_elt { + int8 type; + int8 flags; + chanspec_t chanspec; + uint32 token; /* token for this measurement */ + uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ + uint32 tsf_l; /* TSF low 32-bits */ + uint32 dur; /* TUs */ + uint32 len; /* byte length of data block */ + uint8 data[1]; /* variable length data block */ +} wl_rm_rep_elt_t; +#define WL_RM_REP_ELT_FIXED_LEN 24 /* length excluding data block */ + +#define WL_RPI_REP_BIN_NUM 8 +typedef struct wl_rm_rpi_rep { + uint8 rpi[WL_RPI_REP_BIN_NUM]; + int8 rpi_max[WL_RPI_REP_BIN_NUM]; +} wl_rm_rpi_rep_t; + +typedef struct wl_rm_rep { + uint32 token; /* overall measurement set token */ + uint32 len; /* length of measurement report block */ + wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ +} wl_rm_rep_t; +#define WL_RM_REP_FIXED_LEN 8 + +#ifdef BCMCCX + +#define LEAP_USER_MAX 32 +#define LEAP_DOMAIN_MAX 32 +#define LEAP_PASSWORD_MAX 32 + +typedef struct wl_leap_info { + wlc_ssid_t ssid; + uint8 user_len; + uchar user[LEAP_USER_MAX]; + uint8 password_len; + uchar password[LEAP_PASSWORD_MAX]; + uint8 domain_len; + uchar domain[LEAP_DOMAIN_MAX]; +} wl_leap_info_t; + +typedef struct wl_leap_list { + uint32 buflen; + uint32 version; + uint32 count; + wl_leap_info_t leap_info[1]; +} wl_leap_list_t; +#endif /* BCMCCX */ + +typedef enum sup_auth_status { + /* Basic supplicant authentication states */ + WLC_SUP_DISCONNECTED = 0, + WLC_SUP_CONNECTING, + WLC_SUP_IDREQUIRED, + WLC_SUP_AUTHENTICATING, + WLC_SUP_AUTHENTICATED, + WLC_SUP_KEYXCHANGE, + WLC_SUP_KEYED, + WLC_SUP_TIMEOUT, + WLC_SUP_LAST_BASIC_STATE, + + /* Extended supplicant authentication states */ + /* Waiting to receive handshake msg M1 */ + WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, + /* Preparing to send handshake msg M2 */ + WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, + /* Waiting to receive handshake msg M3 */ + WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, + WLC_SUP_KEYXCHANGE_PREP_M4, /* Preparing to send handshake msg M4 */ + WLC_SUP_KEYXCHANGE_WAIT_G1, /* Waiting to receive handshake msg G1 */ + WLC_SUP_KEYXCHANGE_PREP_G2 /* Preparing to send handshake msg G2 */ +} sup_auth_status_t; +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +typedef struct wl_wsec_key { + uint32 index; /* key index */ + uint32 len; /* key length */ + uint8 data[DOT11_MAX_KEY_SIZE]; /* key data */ + uint32 pad_1[18]; + uint32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ + uint32 flags; /* misc flags */ + uint32 pad_2[2]; + int pad_3; + int iv_initialized; /* has IV been initialized already? */ + int pad_4; + /* Rx IV */ + struct { + uint32 hi; /* upper 32 bits of IV */ + uint16 lo; /* lower 16 bits of IV */ + } rxiv; + uint32 pad_5[2]; + struct ether_addr ea; /* per station */ +} wl_wsec_key_t; + +#define WSEC_MIN_PSK_LEN 8 +#define WSEC_MAX_PSK_LEN 64 + +/* Flag for key material needing passhash'ing */ +#define WSEC_PASSPHRASE (1<<0) + +/* receptacle for WLC_SET_WSEC_PMK parameter */ +typedef struct { + ushort key_len; /* octets in key material */ + ushort flags; /* key handling qualification */ + uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */ +} wsec_pmk_t; + +typedef struct _pmkid { + struct ether_addr BSSID; + uint8 PMKID[WPA2_PMKID_LEN]; +} pmkid_t; + +typedef struct _pmkid_list { + uint32 npmkid; + pmkid_t pmkid[1]; +} pmkid_list_t; + +typedef struct _pmkid_cand { + struct ether_addr BSSID; + uint8 preauth; +} pmkid_cand_t; + +typedef struct _pmkid_cand_list { + uint32 npmkid_cand; + pmkid_cand_t pmkid_cand[1]; +} pmkid_cand_list_t; + +#define WL_STA_ANT_MAX 4 /* max possible rx antennas */ + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +typedef struct wl_assoc_info { + uint32 req_len; + uint32 resp_len; + uint32 flags; + struct dot11_assoc_req req; + struct ether_addr reassoc_bssid; /* used in reassoc's */ + struct dot11_assoc_resp resp; +} wl_assoc_info_t; + +typedef struct wl_led_info { + uint32 index; /* led index */ + uint32 behavior; + uint8 activehi; +} wl_led_info_t; + + +/* srom read/write struct passed through ioctl */ +typedef struct { + uint byteoff; /* byte offset */ + uint nbytes; /* number of bytes */ + uint16 buf[1]; +} srom_rw_t; + +/* similar cis (srom or otp) struct [iovar: may not be aligned] */ +typedef struct { + uint32 source; /* cis source */ + uint32 byteoff; /* byte offset */ + uint32 nbytes; /* number of bytes */ + /* data follows here */ +} cis_rw_t; + +/* R_REG and W_REG struct passed through ioctl */ +typedef struct { + uint32 byteoff; /* byte offset of the field in d11regs_t */ + uint32 val; /* read/write value of the field */ + uint32 size; /* sizeof the field */ + uint band; /* band (optional) */ +} rw_reg_t; + +/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ +/* PCL - Power Control Loop */ +typedef struct { + uint16 auto_ctrl; /* WL_ATTEN_XX */ + uint16 bb; /* Baseband attenuation */ + uint16 radio; /* Radio attenuation */ + uint16 txctl1; /* Radio TX_CTL1 value */ +} atten_t; + +/* Per-AC retry parameters */ +struct wme_tx_params_s { + uint8 short_retry; + uint8 short_fallback; + uint8 long_retry; + uint8 long_fallback; + uint16 max_rate; /* In units of 512 Kbps */ +}; + +typedef struct wme_tx_params_s wme_tx_params_t; + +#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) + +typedef struct wl_plc_nodelist { + uint32 count; /* Number of nodes */ + struct _node { + struct ether_addr ea; /* Node ether address */ + uint32 node_type; /* Node type */ + uint32 cost; /* PLC affinity */ + } node[1]; +} wl_plc_nodelist_t; + +typedef struct wl_plc_params { + uint32 cmd; /* Command */ + uint8 plc_failover; /* PLC failover control/status */ + struct ether_addr node_ea; /* Node ether address */ + uint32 cost; /* Link cost or mac cost */ +} wl_plc_params_t; + +/* Used to get specific link/ac parameters */ +typedef struct { + int32 ac; + uint8 val; + struct ether_addr ea; +} link_val_t; + + + +typedef struct { + uint16 ver; /* version of this struct */ + uint16 len; /* length in bytes of this structure */ + uint16 cap; /* sta's advertised capabilities */ + uint32 flags; /* flags defined below */ + uint32 idle; /* time since data pkt rx'd from sta */ + struct ether_addr ea; /* Station address */ + wl_rateset_t rateset; /* rateset in use */ + uint32 in; /* seconds elapsed since associated */ + uint32 listen_interval_inms; /* Min Listen interval in ms for this STA */ + uint32 tx_pkts; /* # of packets transmitted */ + uint32 tx_failures; /* # of packets failed */ + uint32 rx_ucast_pkts; /* # of unicast packets received */ + uint32 rx_mcast_pkts; /* # of multicast packets received */ + uint32 tx_rate; /* Rate of last successful tx frame */ + uint32 rx_rate; /* Rate of last successful rx frame */ + uint32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ + uint32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ + uint32 tx_tot_pkts; /* # of tx pkts (ucast + mcast) */ + uint32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */ + uint32 tx_mcast_pkts; /* # of mcast pkts txed */ + uint64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */ + uint64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */ + uint64 tx_ucast_bytes; /* data bytes txed (ucast) */ + uint64 tx_mcast_bytes; /* # data bytes txed (mcast) */ + uint64 rx_ucast_bytes; /* data bytes recvd (ucast) */ + uint64 rx_mcast_bytes; /* data bytes recvd (mcast) */ + int8 rssi[WL_STA_ANT_MAX]; /* average rssi per antenna + * of data frames + */ + int8 nf[WL_STA_ANT_MAX]; /* per antenna noise floor */ + uint16 aid; /* association ID */ + uint16 ht_capabilities; /* advertised ht caps */ + uint16 vht_flags; /* converted vht flags */ + uint32 tx_pkts_retried; /* # of frames where a retry was necessary */ + uint32 tx_pkts_retry_exhausted; /* # of frames where a retry was + * exhausted + */ + int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /* Per antenna RSSI of last + * received data frame. + */ +} sta_info_t; + +#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts) + +#define WL_STA_VER 4 + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +#define WLC_NUMRATES 16 /* max # of rates in a rateset */ + +typedef struct wlc_rateset { + uint32 count; /* number of rates in rates[] */ + uint8 rates[WLC_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ + uint8 htphy_membership; /* HT PHY Membership */ + uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ + uint16 vht_mcsmap; /* supported vht mcs nss bit map */ +} wlc_rateset_t; + +/* Used to get specific STA parameters */ +typedef struct { + uint32 val; + struct ether_addr ea; +} scb_val_t; + +/* Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ +typedef struct { + uint32 code; + scb_val_t ioctl_args; +} authops_t; + +/* channel encoding */ +typedef struct channel_info { + int hw_channel; + int target_channel; + int scan_channel; +} channel_info_t; + +/* For ioctls that take a list of MAC addresses */ +struct maclist { + uint count; /* number of MAC addresses */ + struct ether_addr ea[1]; /* variable length array of MAC addresses */ +}; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +/* get pkt count struct passed through ioctl */ +typedef struct get_pktcnt { + uint rx_good_pkt; + uint rx_bad_pkt; + uint tx_good_pkt; + uint tx_bad_pkt; + uint rx_ocast_good_pkt; /* unicast packets destined for others */ +} get_pktcnt_t; + +/* NINTENDO2 */ +#define LQ_IDX_MIN 0 +#define LQ_IDX_MAX 1 +#define LQ_IDX_AVG 2 +#define LQ_IDX_SUM 2 +#define LQ_IDX_LAST 3 +#define LQ_STOP_MONITOR 0 +#define LQ_START_MONITOR 1 + +/* Get averages RSSI, Rx PHY rate and SNR values */ +typedef struct { + int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */ + int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */ + int isvalid; /* Flag indicating whether above data is valid */ +} wl_lq_t; /* Link Quality */ + +typedef enum wl_wakeup_reason_type { + LCD_ON = 1, + LCD_OFF, + DRC1_WAKE, + DRC2_WAKE, + REASON_LAST +} wl_wr_type_t; + +typedef struct { +/* Unique filter id */ + uint32 id; + +/* stores the reason for the last wake up */ + uint8 reason; +} wl_wr_t; + +/* Get MAC specific rate histogram command */ +typedef struct { + struct ether_addr ea; /* MAC Address */ + uint8 ac_cat; /* Access Category */ + uint8 num_pkts; /* Number of packet entries to be averaged */ +} wl_mac_ratehisto_cmd_t; /* MAC Specific Rate Histogram command */ + +/* Get MAC rate histogram response */ +typedef struct { + uint32 rate[DOT11_RATE_MAX + 1]; /* Rates */ + uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ + uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ + uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ +} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */ + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* Linux network driver ioctl encoding */ +typedef struct wl_ioctl { + uint cmd; /* common ioctl definition */ + void *buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + uint8 set; /* 1=set IOCTL; 0=query IOCTL */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ +} wl_ioctl_t; +#ifdef CONFIG_COMPAT +typedef struct compat_wl_ioctl { + uint cmd; /* common ioctl definition */ + uint32 buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + uint8 set; /* 1=set IOCTL; 0=query IOCTL */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ +} compat_wl_ioctl_t; +#endif /* CONFIG_COMPAT */ + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +/* + * Structure for passing hardware and software + * revision info up from the driver. + */ +typedef struct wlc_rev_info { + uint vendorid; /* PCI vendor id */ + uint deviceid; /* device id of chip */ + uint radiorev; /* radio revision */ + uint chiprev; /* chip revision */ + uint corerev; /* core revision */ + uint boardid; /* board identifier (usu. PCI sub-device id) */ + uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ + uint boardrev; /* board revision */ + uint driverrev; /* driver version */ + uint ucoderev; /* microcode version */ + uint bus; /* bus type */ + uint chipnum; /* chip number */ + uint phytype; /* phy type */ + uint phyrev; /* phy revision */ + uint anarev; /* anacore rev */ + uint chippkg; /* chip package info */ + uint nvramrev; /* nvram revision number */ +} wlc_rev_info_t; + +#define WL_REV_INFO_LEGACY_LENGTH 48 + +#define WL_BRAND_MAX 10 +typedef struct wl_instance_info { + uint instance; + char brand[WL_BRAND_MAX]; +} wl_instance_info_t; + +/* structure to change size of tx fifo */ +typedef struct wl_txfifo_sz { + uint16 magic; + uint16 fifo; + uint16 size; +} wl_txfifo_sz_t; + +/* Transfer info about an IOVar from the driver */ +/* Max supported IOV name size in bytes, + 1 for nul termination */ +#define WLC_IOV_NAME_LEN 30 +typedef struct wlc_iov_trx_s { + uint8 module; + uint8 type; + char name[WLC_IOV_NAME_LEN]; +} wlc_iov_trx_t; + +/* bump this number if you change the ioctl interface */ +#define WLC_IOCTL_VERSION 2 +#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 + +#ifdef CONFIG_USBRNDIS_RETAIL +/* struct passed in for WLC_NDCONFIG_ITEM */ +typedef struct { + char *name; + void *param; +} ndconfig_item_t; +#endif + + +#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ + +#define WL_PHY_PAVAR_VER 1 /* pavars version */ +#define WL_PHY_PAVARS2_NUM 3 /* a1, b0, b1 */ +typedef struct wl_pavars2 { + uint16 ver; /* version of this struct */ + uint16 len; /* len of this structure */ + uint16 inuse; /* driver return 1 for a1,b0,b1 in current band range */ + uint16 phy_type; /* phy type */ + uint16 bandrange; + uint16 chain; + uint16 inpa[WL_PHY_PAVARS2_NUM]; /* phy pavars for one band range */ +} wl_pavars2_t; + +typedef struct wl_po { + uint16 phy_type; /* Phy type */ + uint16 band; + uint16 cckpo; + uint32 ofdmpo; + uint16 mcspo[8]; +} wl_po_t; + +#define WL_NUM_RPCALVARS 5 /* number of rpcal vars */ + +typedef struct wl_rpcal { + uint16 value; + uint16 update; +} wl_rpcal_t; + +typedef struct wl_aci_args { + int enter_aci_thresh; /* Trigger level to start detecting ACI */ + int exit_aci_thresh; /* Trigger level to exit ACI mode */ + int usec_spin; /* microsecs to delay between rssi samples */ + int glitch_delay; /* interval between ACI scans when glitch count is consistently high */ + uint16 nphy_adcpwr_enter_thresh; /* ADC power to enter ACI mitigation mode */ + uint16 nphy_adcpwr_exit_thresh; /* ADC power to exit ACI mitigation mode */ + uint16 nphy_repeat_ctr; /* Number of tries per channel to compute power */ + uint16 nphy_num_samples; /* Number of samples to compute power on one channel */ + uint16 nphy_undetect_window_sz; /* num of undetects to exit ACI Mitigation mode */ + uint16 nphy_b_energy_lo_aci; /* low ACI power energy threshold for bphy */ + uint16 nphy_b_energy_md_aci; /* mid ACI power energy threshold for bphy */ + uint16 nphy_b_energy_hi_aci; /* high ACI power energy threshold for bphy */ + uint16 nphy_noise_noassoc_glitch_th_up; /* wl interference 4 */ + uint16 nphy_noise_noassoc_glitch_th_dn; + uint16 nphy_noise_assoc_glitch_th_up; + uint16 nphy_noise_assoc_glitch_th_dn; + uint16 nphy_noise_assoc_aci_glitch_th_up; + uint16 nphy_noise_assoc_aci_glitch_th_dn; + uint16 nphy_noise_assoc_enter_th; + uint16 nphy_noise_noassoc_enter_th; + uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; + uint16 nphy_noise_noassoc_crsidx_incr; + uint16 nphy_noise_assoc_crsidx_incr; + uint16 nphy_noise_crsidx_decr; +} wl_aci_args_t; + +#define WL_ACI_ARGS_LEGACY_LENGTH 16 /* bytes of pre NPHY aci args */ +#define WL_SAMPLECOLLECT_T_VERSION 2 /* version of wl_samplecollect_args_t struct */ +typedef struct wl_samplecollect_args { + /* version 0 fields */ + uint8 coll_us; + int cores; + /* add'l version 1 fields */ + uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */ + uint16 length; /* length of entire structure */ + int8 trigger; + uint16 timeout; + uint16 mode; + uint32 pre_dur; + uint32 post_dur; + uint8 gpio_sel; + uint8 downsamp; + uint8 be_deaf; + uint8 agc; /* loop from init gain and going down */ + uint8 filter; /* override high pass corners to lowest */ + /* add'l version 2 fields */ + uint8 trigger_state; + uint8 module_sel1; + uint8 module_sel2; + uint16 nsamps; + int bitStart; + uint32 gpioCapMask; +} wl_samplecollect_args_t; + +#define WL_SAMPLEDATA_T_VERSION 1 /* version of wl_samplecollect_args_t struct */ +/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ +#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 + +typedef struct wl_sampledata { + uint16 version; /* structure version */ + uint16 size; /* size of structure */ + uint16 tag; /* Header/Data */ + uint16 length; /* data length */ + uint32 flag; /* bit def */ +} wl_sampledata_t; + + +/* WL_OTA START */ +/* OTA Test Status */ +enum { + WL_OTA_TEST_IDLE = 0, /* Default Idle state */ + WL_OTA_TEST_ACTIVE = 1, /* Test Running */ + WL_OTA_TEST_SUCCESS = 2, /* Successfully Finished Test */ + WL_OTA_TEST_FAIL = 3 /* Test Failed in the Middle */ +}; +/* OTA SYNC Status */ +enum { + WL_OTA_SYNC_IDLE = 0, /* Idle state */ + WL_OTA_SYNC_ACTIVE = 1, /* Waiting for Sync */ + WL_OTA_SYNC_FAIL = 2 /* Sync pkt not recieved */ +}; + +/* Various error states dut can get stuck during test */ +enum { + WL_OTA_SKIP_TEST_CAL_FAIL = 1, /* Phy calibration failed */ + WL_OTA_SKIP_TEST_SYNCH_FAIL = 2, /* Sync Packet not recieved */ + WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL = 3, /* Cmd flow file download failed */ + WL_OTA_SKIP_TEST_NO_TEST_FOUND = 4, /* No test found in Flow file */ + WL_OTA_SKIP_TEST_WL_NOT_UP = 5, /* WL UP failed */ + WL_OTA_SKIP_TEST_UNKNOWN_CALL /* Unintentional scheduling on ota test */ +}; + +/* Differentiator for ota_tx and ota_rx */ +enum { + WL_OTA_TEST_TX = 0, /* ota_tx */ + WL_OTA_TEST_RX = 1, /* ota_rx */ +}; + +/* Catch 3 modes of operation: 20Mhz, 40Mhz, 20 in 40 Mhz */ +enum { + WL_OTA_TEST_BW_20_IN_40MHZ = 0, /* 20 in 40 operation */ + WL_OTA_TEST_BW_20MHZ = 1, /* 20 Mhz operation */ + WL_OTA_TEST_BW_40MHZ = 2 /* full 40Mhz operation */ +}; +typedef struct ota_rate_info { + uint8 rate_cnt; /* Total number of rates */ + uint8 rate_val_mbps[WL_OTA_TEST_MAX_NUM_RATE]; /* array of rates from 1mbps to 130mbps */ + /* for legacy rates : ratein mbps * 2 */ + /* for HT rates : mcs index */ +} ota_rate_info_t; + +typedef struct ota_power_info { + int8 pwr_ctrl_on; /* power control on/off */ + int8 start_pwr; /* starting power/index */ + int8 delta_pwr; /* delta power/index */ + int8 end_pwr; /* end power/index */ +} ota_power_info_t; + +typedef struct ota_packetengine { + uint16 delay; /* Inter-packet delay */ + /* for ota_tx, delay is tx ifs in micro seconds */ + /* for ota_rx, delay is wait time in milliseconds */ + uint16 nframes; /* Number of frames */ + uint16 length; /* Packet length */ +} ota_packetengine_t; + +/* Test info vector */ +typedef struct wl_ota_test_args { + uint8 cur_test; /* test phase */ + uint8 chan; /* channel */ + uint8 bw; /* bandwidth */ + uint8 control_band; /* control band */ + uint8 stf_mode; /* stf mode */ + ota_rate_info_t rt_info; /* Rate info */ + ota_packetengine_t pkteng; /* packeteng info */ + uint8 txant; /* tx antenna */ + uint8 rxant; /* rx antenna */ + ota_power_info_t pwr_info; /* power sweep info */ + uint8 wait_for_sync; /* wait for sync or not */ +} wl_ota_test_args_t; + +typedef struct wl_ota_test_vector { + wl_ota_test_args_t test_arg[WL_OTA_TEST_MAX_NUM_SEQ]; /* Test argument struct */ + uint16 test_cnt; /* Total no of test */ + uint8 file_dwnld_valid; /* File successfully downloaded */ + uint8 sync_timeout; /* sync packet timeout */ + int8 sync_fail_action; /* sync fail action */ + struct ether_addr sync_mac; /* macaddress for sync pkt */ + struct ether_addr tx_mac; /* macaddress for tx */ + struct ether_addr rx_mac; /* macaddress for rx */ + int8 loop_test; /* dbg feature to loop the test */ +} wl_ota_test_vector_t; + + +/* struct copied back form dongle to host to query the status */ +typedef struct wl_ota_test_status { + int16 cur_test_cnt; /* test phase */ + int8 skip_test_reason; /* skip test reasoin */ + wl_ota_test_args_t test_arg; /* cur test arg details */ + uint16 test_cnt; /* total no of test downloaded */ + uint8 file_dwnld_valid; /* file successfully downloaded ? */ + uint8 sync_timeout; /* sync timeout */ + int8 sync_fail_action; /* sync fail action */ + struct ether_addr sync_mac; /* macaddress for sync pkt */ + struct ether_addr tx_mac; /* tx mac address */ + struct ether_addr rx_mac; /* rx mac address */ + uint8 test_stage; /* check the test status */ + int8 loop_test; /* Debug feature to puts test enfine in a loop */ + uint8 sync_status; /* sync status */ +} wl_ota_test_status_t; + +/* WL_OTA END */ + +/* wl_radar_args_t */ +typedef struct { + int npulses; /* required number of pulses at n * t_int */ + int ncontig; /* required number of pulses at t_int */ + int min_pw; /* minimum pulse width (20 MHz clocks) */ + int max_pw; /* maximum pulse width (20 MHz clocks) */ + uint16 thresh0; /* Radar detection, thresh 0 */ + uint16 thresh1; /* Radar detection, thresh 1 */ + uint16 blank; /* Radar detection, blank control */ + uint16 fmdemodcfg; /* Radar detection, fmdemod config */ + int npulses_lp; /* Radar detection, minimum long pulses */ + int min_pw_lp; /* Minimum pulsewidth for long pulses */ + int max_pw_lp; /* Maximum pulsewidth for long pulses */ + int min_fm_lp; /* Minimum fm for long pulses */ + int max_span_lp; /* Maximum deltat for long pulses */ + int min_deltat; /* Minimum spacing between pulses */ + int max_deltat; /* Maximum spacing between pulses */ + uint16 autocorr; /* Radar detection, autocorr on or off */ + uint16 st_level_time; /* Radar detection, start_timing level */ + uint16 t2_min; /* minimum clocks needed to remain in state 2 */ + uint32 version; /* version */ + uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */ + int npulses_fra; /* Radar detection, minimum French pulses set */ + int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */ + int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */ + uint16 percal_mask; /* defines which period cal is masked from radar detection */ + int quant; /* quantization resolution to pulse positions */ + uint32 min_burst_intv_lp; /* minimum burst to burst interval for bin3 radar */ + uint32 max_burst_intv_lp; /* maximum burst to burst interval for bin3 radar */ + int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */ + int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */ + uint16 feature_mask; /* 16-bit mask to specify enabled features */ +} wl_radar_args_t; + +#define WL_RADAR_ARGS_VERSION 2 + +typedef struct { + uint32 version; /* version */ + uint16 thresh0_20_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ + uint16 thresh1_20_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ + uint16 thresh0_40_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ + uint16 thresh1_40_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ + uint16 thresh0_80_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ + uint16 thresh1_80_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ + uint16 thresh0_20_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ + uint16 thresh1_20_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ + uint16 thresh0_40_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ + uint16 thresh1_40_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ + uint16 thresh0_80_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ + uint16 thresh1_80_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ +#ifdef WL11AC160 + uint16 thresh0_160_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ + uint16 thresh1_160_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ + uint16 thresh0_160_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ + uint16 thresh1_160_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ +#endif /* WL11AC160 */ +} wl_radar_thr_t; + +#define WL_RADAR_THR_VERSION 2 + +/* RSSI per antenna */ +typedef struct { + uint32 version; /* version field */ + uint32 count; /* number of valid antenna rssi */ + int8 rssi_ant[WL_RSSI_ANT_MAX]; /* rssi per antenna */ +} wl_rssi_ant_t; + +/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */ +typedef struct { + uint state; /* noted by WL_DFS_CACSTATE_XX. */ + uint duration; /* time spent in ms in state. */ + /* as dfs enters ISM state, it removes the operational channel from quiet channel + * list and notes the channel in channel_cleared. set to 0 if no channel is cleared + */ + chanspec_t chanspec_cleared; + /* chanspec cleared used to be a uint, add another to uint16 to maintain size */ + uint16 pad; +} wl_dfs_status_t; + +/* data structure used in 'radar_status' wl interface, which is use to query radar det status */ +typedef struct { + bool detected; + int count; + bool pretended; + uint32 radartype; + uint32 timenow; + uint32 timefromL; + int lp_csect_single; + int detected_pulse_index; + int nconsecq_pulses; + chanspec_t ch; + int pw[10]; + int intv[10]; + int fm[10]; +} wl_radar_status_t; + +#define NUM_PWRCTRL_RATES 12 + +typedef struct { + uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /* User set target */ + uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /* reg and local power limit */ + uint8 txpwr_local_max; /* local max according to the AP */ + uint8 txpwr_local_constraint; /* local constraint according to the AP */ + uint8 txpwr_chan_reg_max; /* Regulatory max for this channel */ + uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /* Latest target for 2.4 and 5 Ghz */ + uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ + uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /* On G phy, OFDM power offset */ + uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /* Max CCK power for this band (SROM) */ + uint8 txpwr_bphy_ofdm_max; /* Max OFDM power for this band (SROM) */ + uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /* Max power for A band (SROM) */ + int8 txpwr_antgain[2]; /* Ant gain for each band - from SROM */ + uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ +} tx_power_legacy_t; + +#define WL_TX_POWER_RATES_LEGACY 45 +#define WL_TX_POWER_MCS20_FIRST 12 +#define WL_TX_POWER_MCS20_NUM 16 +#define WL_TX_POWER_MCS40_FIRST 28 +#define WL_TX_POWER_MCS40_NUM 17 + +typedef struct { + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint8 local_max; /* local max according to the AP */ + uint8 local_constraint; /* local constraint according to the AP */ + int8 antgain[2]; /* Ant gain for each band - from SROM */ + uint8 rf_cores; /* count of RF Cores being reported */ + uint8 est_Pout[4]; /* Latest tx power out estimate per RF + * chain without adjustment + */ + uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ + uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ + uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ + uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ + uint8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ +} tx_power_legacy2_t; + +/* TX Power index defines */ +#define WL_NUM_RATES_CCK 4 /* 1, 2, 5.5, 11 Mbps */ +#define WL_NUM_RATES_OFDM 8 /* 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ +#define WL_NUM_RATES_MCS_1STREAM 8 /* MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ +#define WL_NUM_RATES_EXTRA_VHT 2 /* Additional VHT 11AC rates */ +#define WL_NUM_RATES_VHT 10 +#define WL_NUM_RATES_MCS32 1 + +#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK +#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM +#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM +#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM +#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32 +#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK +#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM +#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM +#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM +#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32 + +#define WL_NUM_2x2_ELEMENTS 4 +#define WL_NUM_3x3_ELEMENTS 6 + +typedef struct { + uint16 ver; /* version of this struct */ + uint16 len; /* length in bytes of this structure */ + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint32 buflen; /* ppr buffer length */ + uint8 pprbuf[1]; /* Latest target power buffer */ +} wl_txppr_t; + +#define WL_TXPPR_VERSION 1 +#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) +#define TX_POWER_T_VERSION 44 + + +typedef struct tx_inst_power { + uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ + uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ +} tx_inst_power_t; + +#define WL_NUM_TXCHAIN_MAX 4 +typedef struct wl_txchain_pwr_offsets { + int8 offset[WL_NUM_TXCHAIN_MAX]; /* quarter dBm signed offset for each chain */ +} wl_txchain_pwr_offsets_t; +/* maximum channels returned by the get valid channels iovar */ +#define WL_NUMCHANNELS 64 + +/* + * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, + * a one-byte length, and a variable length value. RSSI type tuple must be present + * in the array. + * + * Types are defined in "join preference types" section. + * + * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple + * and must be set to zero. + * + * Values are defined below. + * + * 1. RSSI - 2 octets + * offset 0: reserved + * offset 1: reserved + * + * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) + * offset 0: reserved + * offset 1: # of tuples + * offset 2: tuple 1 + * offset 14: tuple 2 + * ... + * offset 2 + 12 * (n - 1) octets: tuple n + * + * struct wpa_cfg_tuple { + * uint8 akm[DOT11_OUI_LEN+1]; akm suite + * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite + * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite + * }; + * + * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. + * + * 3. BAND - 2 octets + * offset 0: reserved + * offset 1: see "band preference" and "band types" + * + * 4. BAND RSSI - 2 octets + * offset 0: band types + * offset 1: +ve RSSI boost value in dB + */ + +struct tsinfo_arg { + uint8 octets[3]; +}; +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +#define NFIFO 6 /* # tx/rx fifopairs */ +#define NREINITREASONCOUNT 8 +#define REINITREASONIDX(_x) (((_x) < NREINITREASONCOUNT) ? (_x) : 0) + +/* version 7001 wl_cnt_t is same as version 7 with exception of phywatchdog is + * replaced with rxbcnlossmbss */ +#define WL_CNT_T_VERSION_7001 7001 /* version 7001 of wl_cnt_t struct */ +/* wl_cnt_t is merged from firmware twig to be in sync */ +#define WL_CNT_T_VERSION 7 /* current version of wl_cnt_t struct */ + +typedef struct { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txerror; /* tx data errors (derived: sum of others) */ + uint32 txctl; /* tx management frames */ + uint32 txprshort; /* tx short preamble frames */ + uint32 txserr; /* tx status errors */ + uint32 txnobuf; /* tx out of buffers errors */ + uint32 txnoassoc; /* tx discard because we're not associated */ + uint32 txrunt; /* tx runt frames */ + uint32 txchit; /* tx header cache hit (fastpath) */ + uint32 txcmiss; /* tx header cache miss (slowpath) */ + + /* transmit chip error counters */ + uint32 txuflo; /* tx fifo underflows */ + uint32 txphyerr; /* tx phy errors (indicated in tx status) */ + uint32 txphycrs; + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + uint32 rxerror; /* rx data errors (derived: sum of others) */ + uint32 rxctl; /* rx management frames */ + uint32 rxnobuf; /* rx out of buffers errors */ + uint32 rxnondata; /* rx non data frames in the data channel errors */ + uint32 rxbadds; /* rx bad DS errors */ + uint32 rxbadcm; /* rx bad control or management frames */ + uint32 rxfragerr; /* rx fragmentation errors */ + uint32 rxrunt; /* rx runt frames */ + uint32 rxgiant; /* rx giant frames */ + uint32 rxnoscb; /* rx no scb error */ + uint32 rxbadproto; /* rx invalid frames */ + uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ + uint32 rxbadda; /* rx frames tossed for invalid da */ + uint32 rxfilter; /* rx frames filtered out */ + + /* receive chip error counters */ + uint32 rxoflo; /* rx fifo overflow errors */ + uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ + + uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ + uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ + uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ + + /* misc counters */ + uint32 dmade; /* tx/rx dma descriptor errors */ + uint32 dmada; /* tx/rx dma data errors */ + uint32 dmape; /* tx/rx dma descriptor protocol errors */ + uint32 reset; /* reset count */ + uint32 tbtt; /* cnts the TBTT int's */ + uint32 txdmawar; + uint32 pkt_callback_reg_fail; /* callbacks register failure */ + + /* MAC counters: 32-bit version of d11.h's macstat_t */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txdnlfrm; /* Not used */ + uint32 txbcnfrm; /* beacons transmitted */ + uint32 txfunfl[8]; /* per-fifo tx underflows */ + uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS + * or BCN) + */ + uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for + * driver enqueued frames + */ + uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ + uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ + uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not + * data/control/management + */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ + uint32 rxbadplcp; /* parity check of the PLCP header failed */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ + uint32 rxstrt; /* Number of received frames with a good PLCP + * (i.e. passing parity check) + */ + uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ + uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ + uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ + uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ + uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ + uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ + uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ + uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ + uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ + uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC + * (unlikely to see these) + */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 rxbeaconobss; /* beacons received from other BSS */ + uint32 rxrsptmout; /* Number of response timeouts for transmitted frames + * expecting a response + */ + uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ + uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ + uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ + uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ + uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ + uint32 pmqovfl; /* Number of PMQ overflows */ + uint32 rxcgprqfrm; /* Number of received Probe requests that made it into + * the PRQ fifo + */ + uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ + uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did + * not get ACK + */ + uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ + uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ + * fifo because a probe response could not be sent out within + * the time limit defined in M_PRS_MAXTIME + */ + uint32 rxnack; /* obsolete */ + uint32 frmscons; /* obsolete */ + uint32 txnack; /* obsolete */ + uint32 txglitch_nack; /* obsolete */ + uint32 txburst; /* obsolete */ + + /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay; /* TKIPReplays */ + uint32 ccmpfmterr; /* CCMPFormatErrors */ + uint32 ccmpreplay; /* CCMPReplays */ + uint32 ccmpundec; /* CCMPDecryptErrors */ + uint32 fourwayfail; /* FourWayHandshakeFailures */ + uint32 wepundec; /* dot11WEPUndecryptableCount */ + uint32 wepicverr; /* dot11WEPICVErrorCount */ + uint32 decsuccess; /* DecryptSuccessCount */ + uint32 tkipicverr; /* TKIPICVErrorCount */ + uint32 wepexcluded; /* dot11WEPExcludedCount */ + + uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ + uint32 psmwds; /* Count PSM watchdogs */ + uint32 rxbcnlossmbss; /* Count beacon loss member of BSS (triggered by ucode) */ + + /* MBSS counters, AP only */ + uint32 prq_entries_handled; /* PRQ entries read in */ + uint32 prq_undirected_entries; /* which were bcast bss & ssid */ + uint32 prq_bad_entries; /* which could not be translated to info */ + uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ + uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ + uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ + uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* pkteng rx frame stats */ + uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ + uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ + + uint32 rfdisable; /* count of radio disables */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + + uint32 txexptime; /* Tx frames suppressed due to timer expiration */ + + uint32 txmpdu_sgi; /* count for sgi transmit */ + uint32 rxmpdu_sgi; /* count for sgi received */ + uint32 txmpdu_stbc; /* count for stbc transmit */ + uint32 rxmpdu_stbc; /* count for stbc received */ + + uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay_mcst; /* TKIPReplays */ + uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ + uint32 ccmpreplay_mcst; /* CCMPReplays */ + uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ + uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ + uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ + uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ + uint32 decsuccess_mcst; /* DecryptSuccessCount */ + uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ + uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ + + uint32 dma_hang; /* count for stbc received */ +} wl_cnt_t; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +typedef struct { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txerror; /* tx data errors (derived: sum of others) */ + uint32 txctl; /* tx management frames */ + uint32 txprshort; /* tx short preamble frames */ + uint32 txserr; /* tx status errors */ + uint32 txnobuf; /* tx out of buffers errors */ + uint32 txnoassoc; /* tx discard because we're not associated */ + uint32 txrunt; /* tx runt frames */ + uint32 txchit; /* tx header cache hit (fastpath) */ + uint32 txcmiss; /* tx header cache miss (slowpath) */ + + /* transmit chip error counters */ + uint32 txuflo; /* tx fifo underflows */ + uint32 txphyerr; /* tx phy errors (indicated in tx status) */ + uint32 txphycrs; + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + uint32 rxerror; /* rx data errors (derived: sum of others) */ + uint32 rxctl; /* rx management frames */ + uint32 rxnobuf; /* rx out of buffers errors */ + uint32 rxnondata; /* rx non data frames in the data channel errors */ + uint32 rxbadds; /* rx bad DS errors */ + uint32 rxbadcm; /* rx bad control or management frames */ + uint32 rxfragerr; /* rx fragmentation errors */ + uint32 rxrunt; /* rx runt frames */ + uint32 rxgiant; /* rx giant frames */ + uint32 rxnoscb; /* rx no scb error */ + uint32 rxbadproto; /* rx invalid frames */ + uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ + uint32 rxbadda; /* rx frames tossed for invalid da */ + uint32 rxfilter; /* rx frames filtered out */ + + /* receive chip error counters */ + uint32 rxoflo; /* rx fifo overflow errors */ + uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ + + uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ + uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ + uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ + + /* misc counters */ + uint32 dmade; /* tx/rx dma descriptor errors */ + uint32 dmada; /* tx/rx dma data errors */ + uint32 dmape; /* tx/rx dma descriptor protocol errors */ + uint32 reset; /* reset count */ + uint32 tbtt; /* cnts the TBTT int's */ + uint32 txdmawar; + uint32 pkt_callback_reg_fail; /* callbacks register failure */ + + /* MAC counters: 32-bit version of d11.h's macstat_t */ + uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /* number of RTS sent out by the MAC */ + uint32 txctsfrm; /* number of CTS sent out by the MAC */ + uint32 txackfrm; /* number of ACK frames sent out */ + uint32 txdnlfrm; /* Not used */ + uint32 txbcnfrm; /* beacons transmitted */ + uint32 txfunfl[6]; /* per-fifo tx underflows */ + uint32 rxtoolate; /* receive too late */ + uint32 txfbw; /* transmit at fallback bw (dynamic bw) */ + uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS + * or BCN) + */ + uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for + * driver enqueued frames + */ + uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ + uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ + uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not + * data/control/management + */ + uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ + uint32 rxbadplcp; /* parity check of the PLCP header failed */ + uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ + uint32 rxstrt; /* Number of received frames with a good PLCP + * (i.e. passing parity check) + */ + uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ + uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ + uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ + uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ + uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ + uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ + uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ + uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ + uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ + uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ + uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ + uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ + uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC + * (unlikely to see these) + */ + uint32 rxbeaconmbss; /* beacons received from member of BSS */ + uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 rxbeaconobss; /* beacons received from other BSS */ + uint32 rxrsptmout; /* Number of response timeouts for transmitted frames + * expecting a response + */ + uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ + uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ + uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ + uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ + uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ + uint32 pmqovfl; /* Number of PMQ overflows */ + uint32 rxcgprqfrm; /* Number of received Probe requests that made it into + * the PRQ fifo + */ + uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ + uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did + * not get ACK + */ + uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ + uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ + * fifo because a probe response could not be sent out within + * the time limit defined in M_PRS_MAXTIME + */ + uint32 rxnack; + uint32 frmscons; + uint32 txnack; /* obsolete */ + uint32 rxback; /* blockack rxcnt */ + uint32 txback; /* blockack txcnt */ + + /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay; /* TKIPReplays */ + uint32 ccmpfmterr; /* CCMPFormatErrors */ + uint32 ccmpreplay; /* CCMPReplays */ + uint32 ccmpundec; /* CCMPDecryptErrors */ + uint32 fourwayfail; /* FourWayHandshakeFailures */ + uint32 wepundec; /* dot11WEPUndecryptableCount */ + uint32 wepicverr; /* dot11WEPICVErrorCount */ + uint32 decsuccess; /* DecryptSuccessCount */ + uint32 tkipicverr; /* TKIPICVErrorCount */ + uint32 wepexcluded; /* dot11WEPExcludedCount */ + + uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ + + /* WPA2 counters (see rxundec for DecryptFailureCount) */ + uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ + uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ + uint32 tkipreplay_mcst; /* TKIPReplays */ + uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ + uint32 ccmpreplay_mcst; /* CCMPReplays */ + uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ + uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ + uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ + uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ + uint32 decsuccess_mcst; /* DecryptSuccessCount */ + uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ + uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ + + uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ + uint32 txexptime; /* Tx frames suppressed due to timer expiration */ + uint32 psmwds; /* Count PSM watchdogs */ + uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ + + /* MBSS counters, AP only */ + uint32 prq_entries_handled; /* PRQ entries read in */ + uint32 prq_undirected_entries; /* which were bcast bss & ssid */ + uint32 prq_bad_entries; /* which could not be translated to info */ + uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ + uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ + uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ + uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* pkteng rx frame stats */ + uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ + uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ + + uint32 rfdisable; /* count of radio disables */ + uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ + uint32 bphy_badplcp; + + uint32 txmpdu_sgi; /* count for sgi transmit */ + uint32 rxmpdu_sgi; /* count for sgi received */ + uint32 txmpdu_stbc; /* count for stbc transmit */ + uint32 rxmpdu_stbc; /* count for stbc received */ + + uint32 rxdrop20s; /* drop secondary cnt */ + +} wl_cnt_ver_six_t; + +#define WL_DELTA_STATS_T_VERSION 2 /* current version of wl_delta_stats_t struct */ + +typedef struct { + uint16 version; /* see definition of WL_DELTA_STATS_T_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txframe; /* tx data frames */ + uint32 txbyte; /* tx data bytes */ + uint32 txretrans; /* tx mac retransmits */ + uint32 txfail; /* tx failures */ + + /* receive stat counters */ + uint32 rxframe; /* rx data frames */ + uint32 rxbyte; /* rx data bytes */ + + /* per-rate receive stat counters */ + uint32 rx1mbps; /* packets rx at 1Mbps */ + uint32 rx2mbps; /* packets rx at 2Mbps */ + uint32 rx5mbps5; /* packets rx at 5.5Mbps */ + uint32 rx6mbps; /* packets rx at 6Mbps */ + uint32 rx9mbps; /* packets rx at 9Mbps */ + uint32 rx11mbps; /* packets rx at 11Mbps */ + uint32 rx12mbps; /* packets rx at 12Mbps */ + uint32 rx18mbps; /* packets rx at 18Mbps */ + uint32 rx24mbps; /* packets rx at 24Mbps */ + uint32 rx36mbps; /* packets rx at 36Mbps */ + uint32 rx48mbps; /* packets rx at 48Mbps */ + uint32 rx54mbps; /* packets rx at 54Mbps */ + uint32 rx108mbps; /* packets rx at 108mbps */ + uint32 rx162mbps; /* packets rx at 162mbps */ + uint32 rx216mbps; /* packets rx at 216 mbps */ + uint32 rx270mbps; /* packets rx at 270 mbps */ + uint32 rx324mbps; /* packets rx at 324 mbps */ + uint32 rx378mbps; /* packets rx at 378 mbps */ + uint32 rx432mbps; /* packets rx at 432 mbps */ + uint32 rx486mbps; /* packets rx at 486 mbps */ + uint32 rx540mbps; /* packets rx at 540 mbps */ + + /* phy stats */ + uint32 rxbadplcp; + uint32 rxcrsglitch; + uint32 bphy_rxcrsglitch; + uint32 bphy_badplcp; + +} wl_delta_stats_t; +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +typedef struct { + uint32 packets; + uint32 bytes; +} wl_traffic_stats_t; + +typedef struct { + uint16 version; /* see definition of WL_WME_CNT_VERSION */ + uint16 length; /* length of entire structure */ + + wl_traffic_stats_t tx[AC_COUNT]; /* Packets transmitted */ + wl_traffic_stats_t tx_failed[AC_COUNT]; /* Packets dropped or failed to transmit */ + wl_traffic_stats_t rx[AC_COUNT]; /* Packets received */ + wl_traffic_stats_t rx_failed[AC_COUNT]; /* Packets failed to receive */ + + wl_traffic_stats_t forward[AC_COUNT]; /* Packets forwarded by AP */ + + wl_traffic_stats_t tx_expired[AC_COUNT]; /* packets dropped due to lifetime expiry */ + +} wl_wme_cnt_t; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL +struct wl_msglevel2 { + uint32 low; + uint32 high; +}; + +typedef struct wl_mkeep_alive_pkt { + uint16 version; /* Version for mkeep_alive */ + uint16 length; /* length of fixed parameters in the structure */ + uint32 period_msec; + uint16 len_bytes; + uint8 keep_alive_id; /* 0 - 3 for N = 4 */ + uint8 data[1]; +} wl_mkeep_alive_pkt_t; + +#define WL_MKEEP_ALIVE_VERSION 1 +#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) +#define WL_MKEEP_ALIVE_PRECISION 500 + +/* TCP Keep-Alive conn struct */ +typedef struct wl_mtcpkeep_alive_conn_pkt { + struct ether_addr saddr; /* src mac address */ + struct ether_addr daddr; /* dst mac address */ + struct ipv4_addr sipaddr; /* source IP addr */ + struct ipv4_addr dipaddr; /* dest IP addr */ + uint16 sport; /* src port */ + uint16 dport; /* dest port */ + uint32 seq; /* seq number */ + uint32 ack; /* ACK number */ + uint16 tcpwin; /* TCP window */ +} wl_mtcpkeep_alive_conn_pkt_t; + +/* TCP Keep-Alive interval struct */ +typedef struct wl_mtcpkeep_alive_timers_pkt { + uint16 interval; /* interval timer */ + uint16 retry_interval; /* retry_interval timer */ + uint16 retry_count; /* retry_count */ +} wl_mtcpkeep_alive_timers_pkt_t; + +typedef struct wake_info { + uint32 wake_reason; + uint32 wake_info_len; /* size of packet */ + uchar packet[1]; +} wake_info_t; + +typedef struct wake_pkt { + uint32 wake_pkt_len; /* size of packet */ + uchar packet[1]; +} wake_pkt_t; + + +#define WL_MTCPKEEP_ALIVE_VERSION 1 + +#ifdef WLBA + +#define WLC_BA_CNT_VERSION 1 /* current version of wlc_ba_cnt_t */ + +/* block ack related stats */ +typedef struct wlc_ba_cnt { + uint16 version; /* WLC_BA_CNT_VERSION */ + uint16 length; /* length of entire structure */ + + /* transmit stat counters */ + uint32 txpdu; /* pdus sent */ + uint32 txsdu; /* sdus sent */ + uint32 txfc; /* tx side flow controlled packets */ + uint32 txfci; /* tx side flow control initiated */ + uint32 txretrans; /* retransmitted pdus */ + uint32 txbatimer; /* ba resend due to timer */ + uint32 txdrop; /* dropped packets */ + uint32 txaddbareq; /* addba req sent */ + uint32 txaddbaresp; /* addba resp sent */ + uint32 txdelba; /* delba sent */ + uint32 txba; /* ba sent */ + uint32 txbar; /* bar sent */ + uint32 txpad[4]; /* future */ + + /* receive side counters */ + uint32 rxpdu; /* pdus recd */ + uint32 rxqed; /* pdus buffered before sending up */ + uint32 rxdup; /* duplicate pdus */ + uint32 rxnobuf; /* pdus discarded due to no buf */ + uint32 rxaddbareq; /* addba req recd */ + uint32 rxaddbaresp; /* addba resp recd */ + uint32 rxdelba; /* delba recd */ + uint32 rxba; /* ba recd */ + uint32 rxbar; /* bar recd */ + uint32 rxinvba; /* invalid ba recd */ + uint32 rxbaholes; /* ba recd with holes */ + uint32 rxunexp; /* unexpected packets */ + uint32 rxpad[4]; /* future */ +} wlc_ba_cnt_t; +#endif /* WLBA */ + +/* structure for per-tid ampdu control */ +struct ampdu_tid_control { + uint8 tid; /* tid */ + uint8 enable; /* enable/disable */ +}; + +/* struct for per-tid, per-mode ampdu control */ +struct ampdu_tid_control_mode { + struct ampdu_tid_control control[NUMPRIO]; /* tid will be 0xff for not used element */ + char mode_name[8]; /* supported mode : AIBSS */ +}; + +/* structure for identifying ea/tid for sending addba/delba */ +struct ampdu_ea_tid { + struct ether_addr ea; /* Station address */ + uint8 tid; /* tid */ +}; +/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ +struct ampdu_retry_tid { + uint8 tid; /* tid */ + uint8 retry; /* retry value */ +}; + +/* structure for dpt iovars */ +typedef struct dpt_iovar { + struct ether_addr ea; /* Station address */ + uint8 mode; /* mode: depends on iovar */ + uint32 pad; /* future */ +} dpt_iovar_t; + +#define DPT_FNAME_LEN 48 /* Max length of friendly name */ + +typedef struct dpt_status { + uint8 status; /* flags to indicate status */ + uint8 fnlen; /* length of friendly name */ + uchar name[DPT_FNAME_LEN]; /* friendly name */ + uint32 rssi; /* RSSI of the link */ + sta_info_t sta; /* sta info */ +} dpt_status_t; + +/* structure for dpt list */ +typedef struct dpt_list { + uint32 num; /* number of entries in struct */ + dpt_status_t status[1]; /* per station info */ +} dpt_list_t; + +/* structure for dpt friendly name */ +typedef struct dpt_fname { + uint8 len; /* length of friendly name */ + uchar name[DPT_FNAME_LEN]; /* friendly name */ +} dpt_fname_t; + +#define BDD_FNAME_LEN 32 /* Max length of friendly name */ +typedef struct bdd_fname { + uint8 len; /* length of friendly name */ + uchar name[BDD_FNAME_LEN]; /* friendly name */ +} bdd_fname_t; + +/* structure for addts arguments */ +/* For ioctls that take a list of TSPEC */ +struct tslist { + int count; /* number of tspecs */ + struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ +}; + +#ifdef WLTDLS +/* structure for tdls iovars */ +typedef struct tdls_iovar { + struct ether_addr ea; /* Station address */ + uint8 mode; /* mode: depends on iovar */ + chanspec_t chanspec; + uint32 pad; /* future */ +} tdls_iovar_t; + +#define TDLS_WFD_IE_SIZE 512 +/* structure for tdls wfd ie */ +typedef struct tdls_wfd_ie_iovar { + struct ether_addr ea; /* Station address */ + uint8 mode; + uint16 length; + uint8 data[TDLS_WFD_IE_SIZE]; +} tdls_wfd_ie_iovar_t; +#endif /* WLTDLS */ + +/* structure for addts/delts arguments */ +typedef struct tspec_arg { + uint16 version; /* see definition of TSPEC_ARG_VERSION */ + uint16 length; /* length of entire structure */ + uint flag; /* bit field */ + /* TSPEC Arguments */ + struct tsinfo_arg tsinfo; /* TS Info bit field */ + uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ + uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ + uint min_srv_interval; /* Minimum Service Interval (us) */ + uint max_srv_interval; /* Maximum Service Interval (us) */ + uint inactivity_interval; /* Inactivity Interval (us) */ + uint suspension_interval; /* Suspension Interval (us) */ + uint srv_start_time; /* Service Start Time (us) */ + uint min_data_rate; /* Minimum Data Rate (bps) */ + uint mean_data_rate; /* Mean Data Rate (bps) */ + uint peak_data_rate; /* Peak Data Rate (bps) */ + uint max_burst_size; /* Maximum Burst Size (bytes) */ + uint delay_bound; /* Delay Bound (us) */ + uint min_phy_rate; /* Minimum PHY Rate (bps) */ + uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ + uint16 medium_time; /* Medium Time (32 us/s periods) */ + uint8 dialog_token; /* dialog token */ +} tspec_arg_t; + +/* tspec arg for desired station */ +typedef struct tspec_per_sta_arg { + struct ether_addr ea; + struct tspec_arg ts; +} tspec_per_sta_arg_t; + +/* structure for max bandwidth for each access category */ +typedef struct wme_max_bandwidth { + uint32 ac[AC_COUNT]; /* max bandwidth for each access category */ +} wme_max_bandwidth_t; + +#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) + +/* current version of wl_tspec_arg_t struct */ +#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ +#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ +#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ +#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ + + +#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 +#define WLC_WOWL_MAX_KEEPALIVE 2 + +/* Packet lifetime configuration per ac */ +typedef struct wl_lifetime { + uint32 ac; /* access class */ + uint32 lifetime; /* Packet lifetime value in ms */ +} wl_lifetime_t; + +/* Channel Switch Announcement param */ +typedef struct wl_chan_switch { + uint8 mode; /* value 0 or 1 */ + uint8 count; /* count # of beacons before switching */ + chanspec_t chspec; /* chanspec */ + uint8 reg; /* regulatory class */ + uint8 frame_type; /* csa frame type, unicast or broadcast */ +} wl_chan_switch_t; + +enum { + PFN_LIST_ORDER, + PFN_RSSI +}; + +enum { + DISABLE, + ENABLE +}; + +enum { + OFF_ADAPT, + SMART_ADAPT, + STRICT_ADAPT, + SLOW_ADAPT +}; + +#define SORT_CRITERIA_BIT 0 +#define AUTO_NET_SWITCH_BIT 1 +#define ENABLE_BKGRD_SCAN_BIT 2 +#define IMMEDIATE_SCAN_BIT 3 +#define AUTO_CONNECT_BIT 4 +#define ENABLE_BD_SCAN_BIT 5 +#define ENABLE_ADAPTSCAN_BIT 6 +#define IMMEDIATE_EVENT_BIT 8 +#define SUPPRESS_SSID_BIT 9 +#define ENABLE_NET_OFFLOAD_BIT 10 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_BIT 11 + +#define SORT_CRITERIA_MASK 0x0001 +#define AUTO_NET_SWITCH_MASK 0x0002 +#define ENABLE_BKGRD_SCAN_MASK 0x0004 +#define IMMEDIATE_SCAN_MASK 0x0008 +#define AUTO_CONNECT_MASK 0x0010 + +#define ENABLE_BD_SCAN_MASK 0x0020 +#define ENABLE_ADAPTSCAN_MASK 0x00c0 +#define IMMEDIATE_EVENT_MASK 0x0100 +#define SUPPRESS_SSID_MASK 0x0200 +#define ENABLE_NET_OFFLOAD_MASK 0x0400 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_MASK 0x0800 + +#define PFN_VERSION 2 +#define PFN_SCANRESULT_VERSION 1 +#define MAX_PFN_LIST_COUNT 16 + +#define PFN_COMPLETE 1 +#define PFN_INCOMPLETE 0 + +#define DEFAULT_BESTN 2 +#define DEFAULT_MSCAN 0 +#define DEFAULT_REPEAT 10 +#define DEFAULT_EXP 2 + +#define PFN_PARTIAL_SCAN_BIT 0 +#define PFN_PARTIAL_SCAN_MASK 1 + +/* PFN network info structure */ +typedef struct wl_pfn_subnet_info { + struct ether_addr BSSID; + uint8 channel; /* channel number only */ + uint8 SSID_len; + uint8 SSID[32]; +} wl_pfn_subnet_info_t; + +typedef struct wl_pfn_net_info { + wl_pfn_subnet_info_t pfnsubnet; + int16 RSSI; /* receive signal strength (in dBm) */ + uint16 timestamp; /* age in seconds */ +} wl_pfn_net_info_t; + +typedef struct wl_pfn_lnet_info { + wl_pfn_subnet_info_t pfnsubnet; /* BSSID + channel + SSID len + SSID */ + uint16 flags; /* partial scan, etc */ + int16 RSSI; /* receive signal strength (in dBm) */ + uint32 timestamp; /* age in miliseconds */ + uint16 rtt0; /* estimated distance to this AP in centimeters */ + uint16 rtt1; /* standard deviation of the distance to this AP in centimeters */ +} wl_pfn_lnet_info_t; + +typedef struct wl_pfn_lscanresults { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_lnet_info_t netinfo[1]; +} wl_pfn_lscanresults_t; + +typedef struct wl_pfn_scanresults { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_net_info_t netinfo[1]; +} wl_pfn_scanresults_t; + +/* PFN data structure */ +typedef struct wl_pfn_param { + int32 version; /* PNO parameters version */ + int32 scan_freq; /* Scan frequency */ + int32 lost_network_timeout; /* Timeout in sec. to declare + * discovered network as lost + */ + int16 flags; /* Bit field to control features + * of PFN such as sort criteria auto + * enable switch and background scan + */ + int16 rssi_margin; /* Margin to avoid jitter for choosing a + * PFN based on RSSI sort criteria + */ + uint8 bestn; /* number of best networks in each scan */ + uint8 mscan; /* number of scans recorded */ + uint8 repeat; /* Minimum number of scan intervals + *before scan frequency changes in adaptive scan + */ + uint8 exp; /* Exponent of 2 for maximum scan interval */ + int32 slow_freq; /* slow scan period */ +} wl_pfn_param_t; + +typedef struct wl_pfn_bssid { + struct ether_addr macaddr; + /* Bit4: suppress_lost, Bit3: suppress_found */ + uint16 flags; +} wl_pfn_bssid_t; +#define WL_PFN_SUPPRESSFOUND_MASK 0x08 +#define WL_PFN_SUPPRESSLOST_MASK 0x10 +#define WL_PFN_RSSI_MASK 0xff00 +#define WL_PFN_RSSI_SHIFT 8 + +typedef struct wl_pfn_cfg { + uint32 reporttype; + int32 channel_num; + uint16 channel_list[WL_NUMCHANNELS]; + uint32 flags; +} wl_pfn_cfg_t; +#define WL_PFN_REPORT_ALLNET 0 +#define WL_PFN_REPORT_SSIDNET 1 +#define WL_PFN_REPORT_BSSIDNET 2 + +#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ +#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ + +typedef struct wl_pfn { + wlc_ssid_t ssid; /* ssid name and its length */ + int32 flags; /* bit2: hidden */ + int32 infra; /* BSS Vs IBSS */ + int32 auth; /* Open Vs Closed */ + int32 wpa_auth; /* WPA type */ + int32 wsec; /* wsec value */ +} wl_pfn_t; + +typedef struct wl_pfn_list { + uint32 version; + uint32 enabled; + uint32 count; + wl_pfn_t pfn[1]; +} wl_pfn_list_t; + +typedef BWL_PRE_PACKED_STRUCT struct pfn_olmsg_params_t { + wlc_ssid_t ssid; + uint32 cipher_type; + uint32 auth_type; + uint8 channels[4]; +} BWL_POST_PACKED_STRUCT pfn_olmsg_params; + +#define WL_PFN_HIDDEN_BIT 2 +#define WL_PFN_HIDDEN_MASK 0x4 + +#ifndef BESTN_MAX +#define BESTN_MAX 3 +#endif + +#ifndef MSCAN_MAX +#define MSCAN_MAX 90 +#endif + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* Service discovery */ +typedef struct { + uint8 transaction_id; /* Transaction id */ + uint8 protocol; /* Service protocol type */ + uint16 query_len; /* Length of query */ + uint16 response_len; /* Length of response */ + uint8 qrbuf[1]; +} wl_p2po_qr_t; + +typedef struct { + uint16 period; /* extended listen period */ + uint16 interval; /* extended listen interval */ +} wl_p2po_listen_t; + +/* ANQP offload */ + +#define ANQPO_MAX_QUERY_SIZE 256 +typedef struct { + uint16 max_retransmit; /* ~0 use default, max retransmit on no ACK from peer */ + uint16 response_timeout; /* ~0 use default, msec to wait for resp after tx packet */ + uint16 max_comeback_delay; /* ~0 use default, max comeback delay in resp else fail */ + uint16 max_retries; /* ~0 use default, max retries on failure */ + uint16 query_len; /* length of ANQP query */ + uint8 query_data[1]; /* ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ +} wl_anqpo_set_t; + +typedef struct { + uint16 channel; /* channel of the peer */ + struct ether_addr addr; /* addr of the peer */ +} wl_anqpo_peer_t; + +#define ANQPO_MAX_PEER_LIST 64 +typedef struct { + uint16 count; /* number of peers in list */ + wl_anqpo_peer_t peer[1]; /* max ANQPO_MAX_PEER_LIST */ +} wl_anqpo_peer_list_t; + +#define ANQPO_MAX_IGNORE_SSID 64 +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of SSID in list */ + wlc_ssid_t ssid[1]; /* max ANQPO_MAX_IGNORE_SSID */ +} wl_anqpo_ignore_ssid_list_t; + +#define ANQPO_MAX_IGNORE_BSSID 64 +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of addr in list */ + struct ether_addr bssid[1]; /* max ANQPO_MAX_IGNORE_BSSID */ +} wl_anqpo_ignore_bssid_list_t; + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +struct toe_ol_stats_t { + /* Num of tx packets that don't need to be checksummed */ + uint32 tx_summed; + + /* Num of tx packets where checksum is filled by offload engine */ + uint32 tx_iph_fill; + uint32 tx_tcp_fill; + uint32 tx_udp_fill; + uint32 tx_icmp_fill; + + /* Num of rx packets where toe finds out if checksum is good or bad */ + uint32 rx_iph_good; + uint32 rx_iph_bad; + uint32 rx_tcp_good; + uint32 rx_tcp_bad; + uint32 rx_udp_good; + uint32 rx_udp_bad; + uint32 rx_icmp_good; + uint32 rx_icmp_bad; + + /* Num of tx packets in which csum error is injected */ + uint32 tx_tcp_errinj; + uint32 tx_udp_errinj; + uint32 tx_icmp_errinj; + + /* Num of rx packets in which csum error is injected */ + uint32 rx_tcp_errinj; + uint32 rx_udp_errinj; + uint32 rx_icmp_errinj; +}; + +/* Arp offload statistic counts */ +struct arp_ol_stats_t { + uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ + uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ + + uint32 arp_table_entries; /* ARP table entries */ + uint32 arp_table_overflow; /* ARP table additions skipped due to overflow */ + + uint32 host_request; /* ARP requests from host */ + uint32 host_reply; /* ARP replies from host */ + uint32 host_service; /* ARP requests from host serviced by ARP Agent */ + + uint32 peer_request; /* ARP requests received from network */ + uint32 peer_request_drop; /* ARP requests from network that were dropped */ + uint32 peer_reply; /* ARP replies received from network */ + uint32 peer_reply_drop; /* ARP replies from network that were dropped */ + uint32 peer_service; /* ARP request from host serviced by ARP Agent */ +}; + +/* NS offload statistic counts */ +struct nd_ol_stats_t { + uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ + uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ + uint32 peer_request; /* NS requests received from network */ + uint32 peer_request_drop; /* NS requests from network that were dropped */ + uint32 peer_reply_drop; /* NA replies from network that were dropped */ + uint32 peer_service; /* NS request from host serviced by firmware */ +}; + +/* + * Keep-alive packet offloading. + */ + +/* NAT keep-alive packets format: specifies the re-transmission period, the packet + * length, and packet contents. + */ +typedef struct wl_keep_alive_pkt { + uint32 period_msec; /* Retransmission period (0 to disable packet re-transmits) */ + uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ + uint8 data[1]; /* Variable length packet to transmit. Contents should include + * entire ethernet packet (enet header, IP header, UDP header, + * and UDP payload) in network byte order. + */ +} wl_keep_alive_pkt_t; + +#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) + + +/* + * Dongle pattern matching filter. + */ + +#define MAX_WAKE_PACKET_CACHE_BYTES 128 /* Maximum cached wake packet */ + +#define MAX_WAKE_PACKET_BYTES (DOT11_A3_HDR_LEN + \ + DOT11_QOS_LEN + \ + sizeof(struct dot11_llc_snap_header) + \ + ETHER_MAX_DATA) + +typedef struct pm_wake_packet { + uint32 status; /* Is the wake reason a packet (if all the other field's valid) */ + uint32 pattern_id; /* Pattern ID that matched */ + uint32 original_packet_size; + uint32 saved_packet_size; + uchar packet[MAX_WAKE_PACKET_CACHE_BYTES]; +} pm_wake_packet_t; + +/* Packet filter types. Currently, only pattern matching is supported. */ +typedef enum wl_pkt_filter_type { + WL_PKT_FILTER_TYPE_PATTERN_MATCH=0, /* Pattern matching filter */ + WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH=1, /* Magic packet match */ + WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2, /* A pattern list (match all to match filter) */ + WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH=3, /* SECURE WOWL magic / net pattern match */ + WL_PKT_FILTER_TYPE_APF_MATCH=4, /* Android packet filter match */ + WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT=5, /* Pattern matching filter with timeout event */ +} wl_pkt_filter_type_t; + +#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t + +/* String mapping for types that may be used by applications or debug */ +#define WL_PKT_FILTER_TYPE_NAMES \ + { "PATTERN", WL_PKT_FILTER_TYPE_PATTERN_MATCH }, \ + { "MAGIC", WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH }, \ + { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH }, \ + { "SECURE WOWL", WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH }, \ + { "APF", WL_PKT_FILTER_TYPE_APF_MATCH }, \ + { "PATTERN TIMEOUT", WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT } + +/* Pattern matching filter. Specifies an offset within received packets to + * start matching, the pattern to match, the size of the pattern, and a bitmask + * that indicates which bits within the pattern should be matched. + */ +typedef struct wl_pkt_filter_pattern { + uint32 offset; /* Offset within received packet to start pattern matching. + * Offset '0' is the first byte of the ethernet header. + */ + uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ + uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts + * at offset 0. Pattern immediately follows mask. + */ +} wl_pkt_filter_pattern_t; + +/* A pattern list is a numerically specified list of modified pattern structures. */ +typedef struct wl_pkt_filter_pattern_listel { + uint16 rel_offs; /* Offset to begin match (relative to 'base' below) */ + uint16 base_offs; /* Base for offset (defined below) */ + uint16 size_bytes; /* Size of mask/pattern */ + uint16 match_flags; /* Addition flags controlling the match */ + uint8 mask_and_data[1]; /* Variable length mask followed by data, each size_bytes */ +} wl_pkt_filter_pattern_listel_t; + +typedef struct wl_pkt_filter_pattern_list { + uint8 list_cnt; /* Number of elements in the list */ + uint8 PAD1[1]; /* Reserved (possible version: reserved) */ + uint16 totsize; /* Total size of this pattern list (includes this struct) */ + wl_pkt_filter_pattern_listel_t patterns[1]; /* Variable number of list elements */ +} wl_pkt_filter_pattern_list_t; + +typedef struct wl_pkt_filter_pattern_timeout { + uint32 offset; /* Offset within received packet to start pattern matching. + * Offset '0' is the first byte of the ethernet header. + */ + uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ + uint32 timeout; /* Timeout(seconds) */ + uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. + * mask starts at offset 0. Pattern + * immediately follows mask. + */ +} wl_pkt_filter_pattern_timeout_t; + +/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ +typedef struct wl_pkt_filter { + uint32 id; /* Unique filter id, specified by app. */ + uint32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ + uint32 negate_match; /* Negate the result of filter matches */ + union { /* Filter definitions */ + wl_pkt_filter_pattern_t pattern; /* Pattern matching filter */ + wl_pkt_filter_pattern_list_t patlist; /* List of patterns to match */ + wl_pkt_filter_pattern_timeout_t pattern_timeout; /* Pattern timeout event filter */ + } u; +} wl_pkt_filter_t; + +/* IOVAR "tcp_keep_set" parameter. Used to install tcp keep_alive stuff. */ +typedef struct wl_tcp_keep_set { + uint32 val1; + uint32 val2; +} wl_tcp_keep_set_t; + +#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) +#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) +#define WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_list_t, patterns) +#define WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN \ + OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data) +#define WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN \ + OFFSETOF(wl_pkt_filter_pattern_timeout_t, mask_and_pattern) + +/* IOVAR "pkt_filter_enable" parameter. */ +typedef struct wl_pkt_filter_enable { + uint32 id; /* Unique filter id */ + uint32 enable; /* Enable/disable bool */ +} wl_pkt_filter_enable_t; + +/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ +typedef struct wl_pkt_filter_list { + uint32 num; /* Number of installed packet filters */ + wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ +} wl_pkt_filter_list_t; + +#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) + +/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ +typedef struct wl_pkt_filter_stats { + uint32 num_pkts_matched; /* # filter matches for specified filter id */ + uint32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ + uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ +} wl_pkt_filter_stats_t; + +/* IOVAR "pkt_filter_ports" parameter. Configure TCP/UDP port filters. */ +typedef struct wl_pkt_filter_ports { + uint8 version; /* Be proper */ + uint8 reserved; /* Be really proper */ + uint16 count; /* Number of ports following */ + /* End of fixed data */ + uint16 ports[1]; /* Placeholder for ports[<count>] */ +} wl_pkt_filter_ports_t; + +#define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports) + +#define WL_PKT_FILTER_PORTS_VERSION 0 +#define WL_PKT_FILTER_PORTS_MAX 128 + +#define RSN_KCK_LENGTH 16 +#define RSN_KEK_LENGTH 16 +#define RSN_REPLAY_LEN 8 +typedef struct _gtkrefresh { + uchar KCK[RSN_KCK_LENGTH]; + uchar KEK[RSN_KEK_LENGTH]; + uchar ReplayCounter[RSN_REPLAY_LEN]; +} gtk_keyinfo_t, *pgtk_keyinfo_t; + +/* Sequential Commands ioctl */ +typedef struct wl_seq_cmd_ioctl { + uint32 cmd; /* common ioctl definition */ + uint32 len; /* length of user buffer */ +} wl_seq_cmd_ioctl_t; + +#define WL_SEQ_CMD_ALIGN_BYTES 4 + +/* These are the set of get IOCTLs that should be allowed when using + * IOCTL sequence commands. These are issued implicitly by wl.exe each time + * it is invoked. We never want to buffer these, or else wl.exe will stop working. + */ +#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ + (((cmd) == WLC_GET_MAGIC) || \ + ((cmd) == WLC_GET_VERSION) || \ + ((cmd) == WLC_GET_AP) || \ + ((cmd) == WLC_GET_INSTANCE)) + +typedef struct wl_pkteng { + uint32 flags; + uint32 delay; /* Inter-packet delay */ + uint32 nframes; /* Number of frames */ + uint32 length; /* Packet length */ + uint8 seqno; /* Enable/disable sequence no. */ + struct ether_addr dest; /* Destination address */ + struct ether_addr src; /* Source address */ +} wl_pkteng_t; + +typedef struct wl_pkteng_stats { + uint32 lostfrmcnt; /* RX PER test: no of frames lost (skip seqno) */ + int32 rssi; /* RSSI */ + int32 snr; /* signal to noise ratio */ + uint16 rxpktcnt[NUM_80211_RATES+1]; + uint8 rssi_qdb; /* qdB portion of the computed rssi */ +} wl_pkteng_stats_t; + + +typedef enum { + wowl_pattern_type_bitmap = 0, + wowl_pattern_type_arp, + wowl_pattern_type_na +} wowl_pattern_type_t; + +typedef struct wl_wowl_pattern { + uint32 masksize; /* Size of the mask in #of bytes */ + uint32 offset; /* Pattern byte offset in packet */ + uint32 patternoffset; /* Offset of start of pattern in the structure */ + uint32 patternsize; /* Size of the pattern itself in #of bytes */ + uint32 id; /* id */ + uint32 reasonsize; /* Size of the wakeup reason code */ + wowl_pattern_type_t type; /* Type of pattern */ + /* Mask follows the structure above */ + /* Pattern follows the mask is at 'patternoffset' from the start */ +} wl_wowl_pattern_t; + +typedef struct wl_wowl_pattern_list { + uint count; + wl_wowl_pattern_t pattern[1]; +} wl_wowl_pattern_list_t; + +typedef struct wl_wowl_wakeind { + uint8 pci_wakeind; /* Whether PCI PMECSR PMEStatus bit was set */ + uint32 ucode_wakeind; /* What wakeup-event indication was set by ucode */ +} wl_wowl_wakeind_t; + +typedef struct { + uint32 pktlen; /* size of packet */ + void *sdu; +} tcp_keepalive_wake_pkt_infop_t; + +/* per AC rate control related data structure */ +typedef struct wl_txrate_class { + uint8 init_rate; + uint8 min_rate; + uint8 max_rate; +} wl_txrate_class_t; + +/* structure for Overlap BSS scan arguments */ +typedef struct wl_obss_scan_arg { + int16 passive_dwell; + int16 active_dwell; + int16 bss_widthscan_interval; + int16 passive_total; + int16 active_total; + int16 chanwidth_transition_delay; + int16 activity_threshold; +} wl_obss_scan_arg_t; + +#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) + +/* RSSI event notification configuration. */ +typedef struct wl_rssi_event { + uint32 rate_limit_msec; /* # of events posted to application will be limited to + * one per specified period (0 to disable rate limit). + */ + uint8 num_rssi_levels; /* Number of entries in rssi_levels[] below */ + int8 rssi_levels[MAX_RSSI_LEVELS]; /* Variable number of RSSI levels. An event + * will be posted each time the RSSI of received + * beacons/packets crosses a level. + */ +} wl_rssi_event_t; + +typedef struct wl_action_obss_coex_req { + uint8 info; + uint8 num; + uint8 ch_list[1]; +} wl_action_obss_coex_req_t; + + +/* IOVar parameter block for small MAC address array with type indicator */ +#define WL_IOV_MAC_PARAM_LEN 4 + +#define WL_IOV_PKTQ_LOG_PRECS 16 + +typedef struct { + uint32 num_addrs; + char addr_type[WL_IOV_MAC_PARAM_LEN]; + struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; +} wl_iov_mac_params_t; + +/* This is extra info that follows wl_iov_mac_params_t */ +typedef struct { + uint32 addr_info[WL_IOV_MAC_PARAM_LEN]; +} wl_iov_mac_extra_params_t; + +/* Combined structure */ +typedef struct { + wl_iov_mac_params_t params; + wl_iov_mac_extra_params_t extra_params; +} wl_iov_mac_full_params_t; + +/* Parameter block for PKTQ_LOG statistics */ +#define PKTQ_LOG_COUNTERS_V4 \ + /* packets requested to be stored */ \ + uint32 requested; \ + /* packets stored */ \ + uint32 stored; \ + /* packets saved, because a lowest priority queue has given away one packet */ \ + uint32 saved; \ + /* packets saved, because an older packet from the same queue has been dropped */ \ + uint32 selfsaved; \ + /* packets dropped, because pktq is full with higher precedence packets */ \ + uint32 full_dropped; \ + /* packets dropped because pktq per that precedence is full */ \ + uint32 dropped; \ + /* packets dropped, in order to save one from a queue of a highest priority */ \ + uint32 sacrificed; \ + /* packets droped because of hardware/transmission error */ \ + uint32 busy; \ + /* packets re-sent because they were not received */ \ + uint32 retry; \ + /* packets retried again (ps pretend) prior to moving power save mode */ \ + uint32 ps_retry; \ + /* suppressed packet count */ \ + uint32 suppress; \ + /* packets finally dropped after retry limit */ \ + uint32 retry_drop; \ + /* the high-water mark of the queue capacity for packets - goes to zero as queue fills */ \ + uint32 max_avail; \ + /* the high-water mark of the queue utilisation for packets - ('inverse' of max_avail) */ \ + uint32 max_used; \ + /* the maximum capacity of the queue */ \ + uint32 queue_capacity; \ + /* count of rts attempts that failed to receive cts */ \ + uint32 rtsfail; \ + /* count of packets sent (acked) successfully */ \ + uint32 acked; \ + /* running total of phy rate of packets sent successfully */ \ + uint32 txrate_succ; \ + /* running total of phy 'main' rate */ \ + uint32 txrate_main; \ + /* actual data transferred successfully */ \ + uint32 throughput; \ + /* time difference since last pktq_stats */ \ + uint32 time_delta; + +typedef struct { + PKTQ_LOG_COUNTERS_V4 +} pktq_log_counters_v04_t; + +/* v5 is the same as V4 with extra parameter */ +typedef struct { + PKTQ_LOG_COUNTERS_V4 + /* cumulative time to transmit */ + uint32 airtime; +} pktq_log_counters_v05_t; + +typedef struct { + uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; + pktq_log_counters_v04_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; + uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; + uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; + char headings[1]; +} pktq_log_format_v04_t; + +typedef struct { + uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; + pktq_log_counters_v05_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; + uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; + uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; + char headings[1]; +} pktq_log_format_v05_t; + + +typedef struct { + uint32 version; + wl_iov_mac_params_t params; + union { + pktq_log_format_v04_t v04; + pktq_log_format_v05_t v05; + } pktq_log; +} wl_iov_pktq_log_t; + +/* PKTQ_LOG_AUTO, PKTQ_LOG_DEF_PREC flags introduced in v05, they are ignored by v04 */ +#define PKTQ_LOG_AUTO (1 << 31) +#define PKTQ_LOG_DEF_PREC (1 << 30) + +/* + * SCB_BS_DATA iovar definitions start. + */ +#define SCB_BS_DATA_STRUCT_VERSION 1 + +/* The actual counters maintained for each station */ +typedef BWL_PRE_PACKED_STRUCT struct { + /* The following counters are a subset of what pktq_stats provides per precedence. */ + uint32 retry; /* packets re-sent because they were not received */ + uint32 retry_drop; /* packets finally dropped after retry limit */ + uint32 rtsfail; /* count of rts attempts that failed to receive cts */ + uint32 acked; /* count of packets sent (acked) successfully */ + uint32 txrate_succ; /* running total of phy rate of packets sent successfully */ + uint32 txrate_main; /* running total of phy 'main' rate */ + uint32 throughput; /* actual data transferred successfully */ + uint32 time_delta; /* time difference since last pktq_stats */ + uint32 airtime; /* cumulative total medium access delay in useconds */ +} BWL_POST_PACKED_STRUCT iov_bs_data_counters_t; + +/* The structure for individual station information. */ +typedef BWL_PRE_PACKED_STRUCT struct { + struct ether_addr station_address; /* The station MAC address */ + uint16 station_flags; /* Bit mask of flags, for future use. */ + iov_bs_data_counters_t station_counters; /* The actual counter values */ +} BWL_POST_PACKED_STRUCT iov_bs_data_record_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 structure_version; /* Structure version number (for wl/wlu matching) */ + uint16 structure_count; /* Number of iov_bs_data_record_t records following */ + iov_bs_data_record_t structure_record[1]; /* 0 - structure_count records */ +} BWL_POST_PACKED_STRUCT iov_bs_data_struct_t; + +/* Bitmask of options that can be passed in to the iovar. */ +enum { + SCB_BS_DATA_FLAG_NO_RESET = (1<<0) /* Do not clear the counters after reading */ +}; +/* + * SCB_BS_DATA iovar definitions end. + */ + +typedef struct wlc_extlog_cfg { + int max_number; + uint16 module; /* bitmap */ + uint8 level; + uint8 flag; + uint16 version; +} wlc_extlog_cfg_t; + +typedef struct log_record { + uint32 time; + uint16 module; + uint16 id; + uint8 level; + uint8 sub_unit; + uint8 seq_num; + int32 arg; + char str[MAX_ARGSTR_LEN]; +} log_record_t; + +typedef struct wlc_extlog_req { + uint32 from_last; + uint32 num; +} wlc_extlog_req_t; + +typedef struct wlc_extlog_results { + uint16 version; + uint16 record_len; + uint32 num; + log_record_t logs[1]; +} wlc_extlog_results_t; + +typedef struct log_idstr { + uint16 id; + uint16 flag; + uint8 arg_type; + const char *fmt_str; +} log_idstr_t; + +#define FMTSTRF_USER 1 + +/* flat ID definitions + * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will + * affect backward compatibility with pre-existing apps + */ +typedef enum { + FMTSTR_DRIVER_UP_ID = 0, + FMTSTR_DRIVER_DOWN_ID = 1, + FMTSTR_SUSPEND_MAC_FAIL_ID = 2, + FMTSTR_NO_PROGRESS_ID = 3, + FMTSTR_RFDISABLE_ID = 4, + FMTSTR_REG_PRINT_ID = 5, + FMTSTR_EXPTIME_ID = 6, + FMTSTR_JOIN_START_ID = 7, + FMTSTR_JOIN_COMPLETE_ID = 8, + FMTSTR_NO_NETWORKS_ID = 9, + FMTSTR_SECURITY_MISMATCH_ID = 10, + FMTSTR_RATE_MISMATCH_ID = 11, + FMTSTR_AP_PRUNED_ID = 12, + FMTSTR_KEY_INSERTED_ID = 13, + FMTSTR_DEAUTH_ID = 14, + FMTSTR_DISASSOC_ID = 15, + FMTSTR_LINK_UP_ID = 16, + FMTSTR_LINK_DOWN_ID = 17, + FMTSTR_RADIO_HW_OFF_ID = 18, + FMTSTR_RADIO_HW_ON_ID = 19, + FMTSTR_EVENT_DESC_ID = 20, + FMTSTR_PNP_SET_POWER_ID = 21, + FMTSTR_RADIO_SW_OFF_ID = 22, + FMTSTR_RADIO_SW_ON_ID = 23, + FMTSTR_PWD_MISMATCH_ID = 24, + FMTSTR_FATAL_ERROR_ID = 25, + FMTSTR_AUTH_FAIL_ID = 26, + FMTSTR_ASSOC_FAIL_ID = 27, + FMTSTR_IBSS_FAIL_ID = 28, + FMTSTR_EXTAP_FAIL_ID = 29, + FMTSTR_MAX_ID +} log_fmtstr_id_t; + +#ifdef DONGLEOVERLAYS +typedef struct { + uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */ + uint32 offset; /* offset into overlay region to write code */ + uint32 len; /* overlay code len */ + /* overlay code follows this struct */ +} wl_ioctl_overlay_t; +#endif /* DONGLEOVERLAYS */ + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* 11k Neighbor Report element */ +typedef struct nbr_element { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; + uint8 channel; + uint8 phytype; + uint8 pad; +} nbr_element_t; + +/* no default structure packing */ +#include <packed_section_end.h> + +typedef struct keepalives_max_idle { + uint16 keepalive_count; /* nmbr of keepalives per bss_max_idle period */ + uint8 mkeepalive_index; /* mkeepalive_index for keepalive frame to be used */ + uint8 PAD; /* to align next field */ + uint16 max_interval; /* seconds */ +} keepalives_max_idle_t; + +#define PM_IGNORE_BCMC_PROXY_ARP (1 << 0) +#define PM_IGNORE_BCMC_ALL_DMS_ACCEPTED (1 << 1) + +/* require strict packing */ +#include <packed_section_start.h> + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + +/* Structures and constants used for "vndr_ie" IOVar interface */ +#define VNDR_IE_CMD_LEN 4 /* length of the set command string: + * "add", "del" (+ NUL) + */ + +#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + vndr_ie_t vndr_ie_data; /* vendor IE data */ +} BWL_POST_PACKED_STRUCT vndr_ie_info_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + int iecount; /* number of entries in the vndr_ie_list[] array */ + vndr_ie_info_t vndr_ie_list[1]; /* variable size list of vndr_ie_info_t structs */ +} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + char cmd[VNDR_IE_CMD_LEN]; /* vndr_ie IOVar set command : "add", "del" + NUL */ + vndr_ie_buf_t vndr_ie_buffer; /* buffer containing Vendor IE list information */ +} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; + +/* tag_ID/length/value_buffer tuple */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint8 id; + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT tlv_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + tlv_t ie_data; /* IE data */ +} BWL_POST_PACKED_STRUCT ie_info_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + int iecount; /* number of entries in the ie_list[] array */ + ie_info_t ie_list[1]; /* variable size list of ie_info_t structs */ +} BWL_POST_PACKED_STRUCT ie_buf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + char cmd[VNDR_IE_CMD_LEN]; /* ie IOVar set command : "add" + NUL */ + ie_buf_t ie_buffer; /* buffer containing IE list information */ +} BWL_POST_PACKED_STRUCT ie_setbuf_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ + uint8 id; /* IE type */ +} BWL_POST_PACKED_STRUCT ie_getbuf_t; + +/* structures used to define format of wps ie data from probe requests */ +/* passed up to applications via iovar "prbreq_wpsie" */ +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { + struct ether_addr staAddr; + uint16 ieLen; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { + sta_prbreq_wps_ie_hdr_t hdr; + uint8 ieData[1]; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { + uint32 totLen; + uint8 ieDataList[1]; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; + + +#ifdef WLMEDIA_TXFAILEVENT +typedef BWL_PRE_PACKED_STRUCT struct { + char dest[ETHER_ADDR_LEN]; /* destination MAC */ + uint8 prio; /* Packet Priority */ + uint8 flags; /* Flags */ + uint32 tsf_l; /* TSF timer low */ + uint32 tsf_h; /* TSF timer high */ + uint16 rates; /* Main Rates */ + uint16 txstatus; /* TX Status */ +} BWL_POST_PACKED_STRUCT txfailinfo_t; +#endif /* WLMEDIA_TXFAILEVENT */ + +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint8 local_max; /* local max according to the AP */ + uint8 local_constraint; /* local constraint according to the AP */ + int8 antgain[2]; /* Ant gain for each band - from SROM */ + uint8 rf_cores; /* count of RF Cores being reported */ + uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ + uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain w/o adjustment */ + uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ + uint8 tx_power_max[4]; /* Maximum target power among all rates */ + uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ + int8 clm_limits[WL_NUMRATES]; /* regulatory limits - 20, 40 or 80MHz */ + int8 clm_limits_subchan1[WL_NUMRATES]; /* regulatory limits - 20in40 or 40in80 */ + int8 clm_limits_subchan2[WL_NUMRATES]; /* regulatory limits - 20in80MHz */ + int8 sar; /* SAR limit for display by wl executable */ + int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ + uint8 version; /* Version of the data format wlu <--> driver */ + uint8 display_core; /* Displayed curpower core */ + int8 target_offsets[4]; /* Target power offsets for current rate per core */ + uint32 last_tx_ratespec; /* Ratespec for last transmition */ + uint user_target; /* user limit */ + uint32 board_limit_len; /* length of board limit buffer */ + uint32 target_len; /* length of target power buffer */ + int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; + uint8 pprdata[1]; /* ppr serialization buffer */ +} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + struct ipv4_addr ipv4_addr; + struct ether_addr nexthop; +} BWL_POST_PACKED_STRUCT ibss_route_entry_t; +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 num_entry; + ibss_route_entry_t route_entry[1]; +} BWL_POST_PACKED_STRUCT ibss_route_tbl_t; + +#define MAX_IBSS_ROUTE_TBL_ENTRY 64 +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +#define TXPWR_TARGET_VERSION 0 +typedef BWL_PRE_PACKED_STRUCT struct { + int32 version; /* version number */ + chanspec_t chanspec; /* txpwr report for this channel */ + int8 txpwr[WL_STA_ANT_MAX]; /* Max tx target power, in qdb */ + uint8 rf_cores; /* count of RF Cores being reported */ +} BWL_POST_PACKED_STRUCT txpwr_target_max_t; + +#define BSS_PEER_INFO_PARAM_CUR_VER 0 +/* Input structure for IOV_BSS_PEER_INFO */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + struct ether_addr ea; /* peer MAC address */ +} BWL_POST_PACKED_STRUCT bss_peer_info_param_t; + +#define BSS_PEER_INFO_CUR_VER 0 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + struct ether_addr ea; + int32 rssi; + uint32 tx_rate; /* current tx rate */ + uint32 rx_rate; /* current rx rate */ + wl_rateset_t rateset; /* rateset in use */ + uint32 age; /* age in seconds */ +} BWL_POST_PACKED_STRUCT bss_peer_info_t; + +#define BSS_PEER_LIST_INFO_CUR_VER 0 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 bss_peer_info_len; /* length of bss_peer_info_t */ + uint32 count; /* number of peer info */ + bss_peer_info_t peer_info[1]; /* peer info */ +} BWL_POST_PACKED_STRUCT bss_peer_list_info_t; + +#define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info) + +#define AIBSS_BCN_FORCE_CONFIG_VER_0 0 + +/* structure used to configure AIBSS beacon force xmit */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 len; + uint32 initial_min_bcn_dur; /* dur in ms to check a bcn in bcn_flood period */ + uint32 min_bcn_dur; /* dur in ms to check a bcn after bcn_flood period */ + uint32 bcn_flood_dur; /* Initial bcn xmit period in ms */ +} BWL_POST_PACKED_STRUCT aibss_bcn_force_config_t; + +#define AIBSS_TXFAIL_CONFIG_VER_0 0 + +/* structure used to configure aibss tx fail event */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 len; + uint32 bcn_timeout; /* dur in seconds to receive 1 bcn */ + uint32 max_tx_retry; /* no of consecutive no acks to send txfail event */ +} BWL_POST_PACKED_STRUCT aibss_txfail_config_t; + +/* no strict structure packing */ +#include <packed_section_end.h> + +#ifndef LINUX_POSTMOGRIFY_REMOVAL + /* Global ASSERT Logging */ +#define ASSERTLOG_CUR_VER 0x0100 +#define MAX_ASSRTSTR_LEN 64 + + typedef struct assert_record { + uint32 time; + uint8 seq_num; + char str[MAX_ASSRTSTR_LEN]; + } assert_record_t; + + typedef struct assertlog_results { + uint16 version; + uint16 record_len; + uint32 num; + assert_record_t logs[1]; + } assertlog_results_t; + +#define LOGRRC_FIX_LEN 8 +#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) + +#ifdef BCMWAPI_WAI +#define IV_LEN 16 + struct wapi_sta_msg_t + { + uint16 msg_type; + uint16 datalen; + uint8 vap_mac[6]; + uint8 reserve_data1[2]; + uint8 sta_mac[6]; + uint8 reserve_data2[2]; + uint8 gsn[IV_LEN]; + uint8 wie[256]; + }; +#endif /* BCMWAPI_WAI */ + + /* chanim acs record */ + typedef struct { + bool valid; + uint8 trigger; + chanspec_t selected_chspc; + int8 bgnoise; + uint32 glitch_cnt; + uint8 ccastats; + uint timestamp; + } chanim_acs_record_t; + + typedef struct { + chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; + uint8 count; + uint timestamp; + } wl_acs_record_t; + + typedef struct chanim_stats { + uint32 glitchcnt; /* normalized as per second count */ + uint32 badplcp; /* normalized as per second count */ + uint8 ccastats[CCASTATS_MAX]; /* normalized as 0-255 */ + int8 bgnoise; /* background noise level (in dBm) */ + chanspec_t chanspec; + uint32 timestamp; + uint32 bphy_glitchcnt; /* normalized as per second count */ + uint32 bphy_badplcp; /* normalized as per second count */ + uint8 chan_idle; /* normalized as 0~255 */ + } chanim_stats_t; + +#define WL_CHANIM_STATS_VERSION 2 + +typedef struct { + uint32 buflen; + uint32 version; + uint32 count; + chanim_stats_t stats[1]; +} wl_chanim_stats_t; + +#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) + +/* Noise measurement metrics. */ +#define NOISE_MEASURE_KNOISE 0x1 + +/* scb probe parameter */ +typedef struct { + uint32 scb_timeout; + uint32 scb_activity_time; + uint32 scb_max_probe; +} wl_scb_probe_t; + +/* structure/defines for selective mgmt frame (smf) stats support */ + +#define SMFS_VERSION 1 +/* selected mgmt frame (smf) stats element */ +typedef struct wl_smfs_elem { + uint32 count; + uint16 code; /* SC or RC code */ +} wl_smfs_elem_t; + +typedef struct wl_smf_stats { + uint32 version; + uint16 length; /* reserved for future usage */ + uint8 type; + uint8 codetype; + uint32 ignored_cnt; + uint32 malformed_cnt; + uint32 count_total; /* count included the interested group */ + wl_smfs_elem_t elem[1]; +} wl_smf_stats_t; + +#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); + +enum { + SMFS_CODETYPE_SC, + SMFS_CODETYPE_RC +}; + +typedef enum smfs_type { + SMFS_TYPE_AUTH, + SMFS_TYPE_ASSOC, + SMFS_TYPE_REASSOC, + SMFS_TYPE_DISASSOC_TX, + SMFS_TYPE_DISASSOC_RX, + SMFS_TYPE_DEAUTH_TX, + SMFS_TYPE_DEAUTH_RX, + SMFS_TYPE_MAX +} smfs_type_t; + +#ifdef PHYMON + +#define PHYMON_VERSION 1 + +typedef struct wl_phycal_core_state { + /* Tx IQ/LO calibration coeffs */ + int16 tx_iqlocal_a; + int16 tx_iqlocal_b; + int8 tx_iqlocal_ci; + int8 tx_iqlocal_cq; + int8 tx_iqlocal_di; + int8 tx_iqlocal_dq; + int8 tx_iqlocal_ei; + int8 tx_iqlocal_eq; + int8 tx_iqlocal_fi; + int8 tx_iqlocal_fq; + + /* Rx IQ calibration coeffs */ + int16 rx_iqcal_a; + int16 rx_iqcal_b; + + uint8 tx_iqlocal_pwridx; /* Tx Power Index for Tx IQ/LO calibration */ + uint32 papd_epsilon_table[64]; /* PAPD epsilon table */ + int16 papd_epsilon_offset; /* PAPD epsilon offset */ + uint8 curr_tx_pwrindex; /* Tx power index */ + int8 idle_tssi; /* Idle TSSI */ + int8 est_tx_pwr; /* Estimated Tx Power (dB) */ + int8 est_rx_pwr; /* Estimated Rx Power (dB) from RSSI */ + uint16 rx_gaininfo; /* Rx gain applied on last Rx pkt */ + uint16 init_gaincode; /* initgain required for ACI */ + int8 estirr_tx; + int8 estirr_rx; + +} wl_phycal_core_state_t; + +typedef struct wl_phycal_state { + int version; + int8 num_phy_cores; /* number of cores */ + int8 curr_temperature; /* on-chip temperature sensor reading */ + chanspec_t chspec; /* channspec for this state */ + bool aci_state; /* ACI state: ON/OFF */ + uint16 crsminpower; /* crsminpower required for ACI */ + uint16 crsminpowerl; /* crsminpowerl required for ACI */ + uint16 crsminpoweru; /* crsminpoweru required for ACI */ + wl_phycal_core_state_t phycal_core[1]; +} wl_phycal_state_t; + +#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) +#endif /* PHYMON */ + +/* discovery state */ +typedef struct wl_p2p_disc_st { + uint8 state; /* see state */ + chanspec_t chspec; /* valid in listen state */ + uint16 dwell; /* valid in listen state, in ms */ +} wl_p2p_disc_st_t; + +/* scan request */ +typedef struct wl_p2p_scan { + uint8 type; /* 'S' for WLC_SCAN, 'E' for "escan" */ + uint8 reserved[3]; + /* scan or escan parms... */ +} wl_p2p_scan_t; + +/* i/f request */ +typedef struct wl_p2p_if { + struct ether_addr addr; + uint8 type; /* see i/f type */ + chanspec_t chspec; /* for p2p_ifadd GO */ +} wl_p2p_if_t; + +/* i/f query */ +typedef struct wl_p2p_ifq { + uint bsscfgidx; + char ifname[BCM_MSG_IFNAME_MAX]; +} wl_p2p_ifq_t; + +/* OppPS & CTWindow */ +typedef struct wl_p2p_ops { + uint8 ops; /* 0: disable 1: enable */ + uint8 ctw; /* >= 10 */ +} wl_p2p_ops_t; + +/* absence and presence request */ +typedef struct wl_p2p_sched_desc { + uint32 start; + uint32 interval; + uint32 duration; + uint32 count; /* see count */ +} wl_p2p_sched_desc_t; + +typedef struct wl_p2p_sched { + uint8 type; /* see schedule type */ + uint8 action; /* see schedule action */ + uint8 option; /* see schedule option */ + wl_p2p_sched_desc_t desc[1]; +} wl_p2p_sched_t; + +typedef struct wl_bcmdcs_data { + uint reason; + chanspec_t chspec; +} wl_bcmdcs_data_t; + + +/* NAT configuration */ +typedef struct { + uint32 ipaddr; /* interface ip address */ + uint32 ipaddr_mask; /* interface ip address mask */ + uint32 ipaddr_gateway; /* gateway ip address */ + uint8 mac_gateway[6]; /* gateway mac address */ + uint32 ipaddr_dns; /* DNS server ip address, valid only for public if */ + uint8 mac_dns[6]; /* DNS server mac address, valid only for public if */ + uint8 GUID[38]; /* interface GUID */ +} nat_if_info_t; + +typedef struct { + uint op; /* operation code */ + bool pub_if; /* set for public if, clear for private if */ + nat_if_info_t if_info; /* interface info */ +} nat_cfg_t; + +typedef struct { + int state; /* NAT state returned */ +} nat_state_t; + + +#define BTA_STATE_LOG_SZ 64 + +/* BTAMP Statemachine states */ +enum { + HCIReset = 1, + HCIReadLocalAMPInfo, + HCIReadLocalAMPASSOC, + HCIWriteRemoteAMPASSOC, + HCICreatePhysicalLink, + HCIAcceptPhysicalLinkRequest, + HCIDisconnectPhysicalLink, + HCICreateLogicalLink, + HCIAcceptLogicalLink, + HCIDisconnectLogicalLink, + HCILogicalLinkCancel, + HCIAmpStateChange, + HCIWriteLogicalLinkAcceptTimeout +}; + +typedef struct flush_txfifo { + uint32 txfifobmp; + uint32 hwtxfifoflush; + struct ether_addr ea; +} flush_txfifo_t; + +enum { + SPATIAL_MODE_2G_IDX = 0, + SPATIAL_MODE_5G_LOW_IDX, + SPATIAL_MODE_5G_MID_IDX, + SPATIAL_MODE_5G_HIGH_IDX, + SPATIAL_MODE_5G_UPPER_IDX, + SPATIAL_MODE_MAX_IDX +}; + +#define WLC_TXCORE_MAX 4 /* max number of txcore supports */ +#define WLC_SUBBAND_MAX 4 /* max number of sub-band supports */ +typedef struct { + uint8 band2g[WLC_TXCORE_MAX]; + uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX]; +} sar_limit_t; + +/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ +typedef struct wl_mempool_stats { + int num; /* Number of memory pools */ + bcm_mp_stats_t s[1]; /* Variable array of memory pool stats. */ +} wl_mempool_stats_t; + +typedef struct { + uint32 ipaddr; + uint32 ipaddr_netmask; + uint32 ipaddr_gateway; +} nwoe_ifconfig_t; + +/* Traffic management priority classes */ +typedef enum trf_mgmt_priority_class { + trf_mgmt_priority_low = 0, /* Maps to 802.1p BK */ + trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ + trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ + trf_mgmt_priority_nochange = 3, /* do not update the priority */ + trf_mgmt_priority_invalid = (trf_mgmt_priority_nochange + 1) +} trf_mgmt_priority_class_t; + +/* Traffic management configuration parameters */ +typedef struct trf_mgmt_config { + uint32 trf_mgmt_enabled; /* 0 - disabled, 1 - enabled */ + uint32 flags; /* See TRF_MGMT_FLAG_xxx defines */ + uint32 host_ip_addr; /* My IP address to determine subnet */ + uint32 host_subnet_mask; /* My subnet mask */ + uint32 downlink_bandwidth; /* In units of kbps */ + uint32 uplink_bandwidth; /* In units of kbps */ + uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed tx bandwidth */ + uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed rx bandwidth */ +} trf_mgmt_config_t; + +/* Traffic management filter */ +typedef struct trf_mgmt_filter { + struct ether_addr dst_ether_addr; /* His L2 address */ + uint32 dst_ip_addr; /* His IP address */ + uint16 dst_port; /* His L4 port */ + uint16 src_port; /* My L4 port */ + uint16 prot; /* L4 protocol (only TCP or UDP) */ + uint16 flags; /* TBD. For now, this must be zero. */ + trf_mgmt_priority_class_t priority; /* Priority for filtered packets */ + uint32 dscp; /* DSCP */ +} trf_mgmt_filter_t; + +/* Traffic management filter list (variable length) */ +typedef struct trf_mgmt_filter_list { + uint32 num_filters; + trf_mgmt_filter_t filter[1]; +} trf_mgmt_filter_list_t; + +/* Traffic management global info used for all queues */ +typedef struct trf_mgmt_global_info { + uint32 maximum_bytes_per_second; + uint32 maximum_bytes_per_sampling_period; + uint32 total_bytes_consumed_per_second; + uint32 total_bytes_consumed_per_sampling_period; + uint32 total_unused_bytes_per_sampling_period; +} trf_mgmt_global_info_t; + +/* Traffic management shaping info per priority queue */ +typedef struct trf_mgmt_shaping_info { + uint32 gauranteed_bandwidth_percentage; + uint32 guaranteed_bytes_per_second; + uint32 guaranteed_bytes_per_sampling_period; + uint32 num_bytes_produced_per_second; + uint32 num_bytes_consumed_per_second; + uint32 num_queued_packets; /* Number of packets in queue */ + uint32 num_queued_bytes; /* Number of bytes in queue */ +} trf_mgmt_shaping_info_t; + +/* Traffic management shaping info array */ +typedef struct trf_mgmt_shaping_info_array { + trf_mgmt_global_info_t tx_global_shaping_info; + trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; + trf_mgmt_global_info_t rx_global_shaping_info; + trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; +} trf_mgmt_shaping_info_array_t; + + +/* Traffic management statistical counters */ +typedef struct trf_mgmt_stats { + uint32 num_processed_packets; /* Number of packets processed */ + uint32 num_processed_bytes; /* Number of bytes processed */ + uint32 num_discarded_packets; /* Number of packets discarded from queue */ +} trf_mgmt_stats_t; + +/* Traffic management statisics array */ +typedef struct trf_mgmt_stats_array { + trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; + trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; +} trf_mgmt_stats_array_t; + +typedef struct powersel_params { + /* LPC Params exposed via IOVAR */ + int32 tp_ratio_thresh; /* Throughput ratio threshold */ + uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ + uint8 pwr_stab_thresh; /* Number of successes before power step down */ + uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ +} powersel_params_t; + +typedef struct lpc_params { + /* LPC Params exposed via IOVAR */ + uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ + uint8 pwr_stab_thresh; /* Number of successes before power step down */ + uint8 lpc_exp_time; /* Time lapse for expiry of database */ + uint8 pwrup_slow_step; /* Step size for slow step up */ + uint8 pwrup_fast_step; /* Step size for fast step up */ + uint8 pwrdn_slow_step; /* Step size for slow step down */ +} lpc_params_t; + +/* tx pkt delay statistics */ +#define SCB_RETRY_SHORT_DEF 7 /* Default Short retry Limit */ +#define WLPKTDLY_HIST_NBINS 16 /* number of bins used in the Delay histogram */ + +/* structure to store per-AC delay statistics */ +typedef struct scb_delay_stats { + uint32 txmpdu_lost; /* number of MPDUs lost */ + uint32 txmpdu_cnt[SCB_RETRY_SHORT_DEF]; /* retry times histogram */ + uint32 delay_sum[SCB_RETRY_SHORT_DEF]; /* cumulative packet latency */ + uint32 delay_min; /* minimum packet latency observed */ + uint32 delay_max; /* maximum packet latency observed */ + uint32 delay_avg; /* packet latency average */ + uint32 delay_hist[WLPKTDLY_HIST_NBINS]; /* delay histogram */ +} scb_delay_stats_t; + +/* structure for txdelay event */ +typedef struct txdelay_event { + uint8 status; + int rssi; + chanim_stats_t chanim_stats; + scb_delay_stats_t delay_stats[AC_COUNT]; +} txdelay_event_t; + +/* structure for txdelay parameters */ +typedef struct txdelay_params { + uint16 ratio; /* Avg Txdelay Delta */ + uint8 cnt; /* Sample cnt */ + uint8 period; /* Sample period */ + uint8 tune; /* Debug */ +} txdelay_params_t; + +enum { + WNM_SERVICE_DMS = 1, + WNM_SERVICE_FMS = 2, + WNM_SERVICE_TFS = 3 +}; + +/* Definitions for WNM/NPS TCLAS */ +typedef struct wl_tclas { + uint8 user_priority; + uint8 fc_len; + dot11_tclas_fc_t fc; +} wl_tclas_t; + +#define WL_TCLAS_FIXED_SIZE OFFSETOF(wl_tclas_t, fc) + +typedef struct wl_tclas_list { + uint32 num; + wl_tclas_t tclas[1]; +} wl_tclas_list_t; + +/* Definitions for WNM/NPS Traffic Filter Service */ +typedef struct wl_tfs_req { + uint8 tfs_id; + uint8 tfs_actcode; + uint8 tfs_subelem_id; + uint8 send; +} wl_tfs_req_t; + +typedef struct wl_tfs_filter { + uint8 status; /* Status returned by the AP */ + uint8 tclas_proc; /* TCLAS processing value (0:and, 1:or) */ + uint8 tclas_cnt; /* count of all wl_tclas_t in tclas array */ + uint8 tclas[1]; /* VLA of wl_tclas_t */ +} wl_tfs_filter_t; +#define WL_TFS_FILTER_FIXED_SIZE OFFSETOF(wl_tfs_filter_t, tclas) + +typedef struct wl_tfs_fset { + struct ether_addr ea; /* Address of AP/STA involved with this filter set */ + uint8 tfs_id; /* TFS ID field chosen by STA host */ + uint8 status; /* Internal status TFS_STATUS_xxx */ + uint8 actcode; /* Action code DOT11_TFS_ACTCODE_xxx */ + uint8 token; /* Token used in last request frame */ + uint8 notify; /* Notify frame sent/received because of this set */ + uint8 filter_cnt; /* count of all wl_tfs_filter_t in filter array */ + uint8 filter[1]; /* VLA of wl_tfs_filter_t */ +} wl_tfs_fset_t; +#define WL_TFS_FSET_FIXED_SIZE OFFSETOF(wl_tfs_fset_t, filter) + +enum { + TFS_STATUS_DISABLED = 0, /* TFS filter set disabled by user */ + TFS_STATUS_DISABLING = 1, /* Empty request just sent to AP */ + TFS_STATUS_VALIDATED = 2, /* Filter set validated by AP (but maybe not enabled!) */ + TFS_STATUS_VALIDATING = 3, /* Filter set just sent to AP */ + TFS_STATUS_NOT_ASSOC = 4, /* STA not associated */ + TFS_STATUS_NOT_SUPPORT = 5, /* TFS not supported by AP */ + TFS_STATUS_DENIED = 6, /* Filter set refused by AP (=> all sets are disabled!) */ +}; + +typedef struct wl_tfs_status { + uint8 fset_cnt; /* count of all wl_tfs_fset_t in fset array */ + wl_tfs_fset_t fset[1]; /* VLA of wl_tfs_fset_t */ +} wl_tfs_status_t; + +typedef struct wl_tfs_set { + uint8 send; /* Immediatly register registered sets on AP side */ + uint8 tfs_id; /* ID of a specific set (existing or new), or nul for all */ + uint8 actcode; /* Action code for this filter set */ + uint8 tclas_proc; /* TCLAS processing operator for this filter set */ +} wl_tfs_set_t; + +typedef struct wl_tfs_term { + uint8 del; /* Delete internal set once confirmation received */ + uint8 tfs_id; /* ID of a specific set (existing), or nul for all */ +} wl_tfs_term_t; + + +#define DMS_DEP_PROXY_ARP (1 << 0) + +/* Definitions for WNM/NPS Directed Multicast Service */ +enum { + DMS_STATUS_DISABLED = 0, /* DMS desc disabled by user */ + DMS_STATUS_ACCEPTED = 1, /* Request accepted by AP */ + DMS_STATUS_NOT_ASSOC = 2, /* STA not associated */ + DMS_STATUS_NOT_SUPPORT = 3, /* DMS not supported by AP */ + DMS_STATUS_DENIED = 4, /* Request denied by AP */ + DMS_STATUS_TERM = 5, /* Request terminated by AP */ + DMS_STATUS_REMOVING = 6, /* Remove request just sent */ + DMS_STATUS_ADDING = 7, /* Add request just sent */ + DMS_STATUS_ERROR = 8, /* Non compliant AP behvior */ + DMS_STATUS_IN_PROGRESS = 9, /* Request just sent */ + DMS_STATUS_REQ_MISMATCH = 10 /* Conditions for sending DMS req not met */ +}; + +typedef struct wl_dms_desc { + uint8 user_id; + uint8 status; + uint8 token; + uint8 dms_id; + uint8 tclas_proc; + uint8 mac_len; /* length of all ether_addr in data array, 0 if STA */ + uint8 tclas_len; /* length of all wl_tclas_t in data array */ + uint8 data[1]; /* VLA of 'ether_addr' and 'wl_tclas_t' (in this order ) */ +} wl_dms_desc_t; + +#define WL_DMS_DESC_FIXED_SIZE OFFSETOF(wl_dms_desc_t, data) + +typedef struct wl_dms_status { + uint32 cnt; + wl_dms_desc_t desc[1]; +} wl_dms_status_t; + +typedef struct wl_dms_set { + uint8 send; + uint8 user_id; + uint8 tclas_proc; +} wl_dms_set_t; + +typedef struct wl_dms_term { + uint8 del; + uint8 user_id; +} wl_dms_term_t; + +typedef struct wl_service_term { + uint8 service; + union { + wl_dms_term_t dms; + } u; +} wl_service_term_t; + +/* Definitions for WNM/NPS BSS Transistion */ +typedef struct wl_bsstrans_req { + uint16 tbtt; /* time of BSS to end of life, in unit of TBTT */ + uint16 dur; /* time of BSS to keep off, in unit of minute */ + uint8 reqmode; /* request mode of BSS transition request */ + uint8 unicast; /* request by unicast or by broadcast */ +} wl_bsstrans_req_t; + +enum { + BSSTRANS_RESP_AUTO = 0, /* Currently equivalent to ENABLE */ + BSSTRANS_RESP_DISABLE = 1, /* Never answer BSS Trans Req frames */ + BSSTRANS_RESP_ENABLE = 2, /* Always answer Req frames with preset data */ + BSSTRANS_RESP_WAIT = 3, /* Send ind, wait and/or send preset data (NOT IMPL) */ + BSSTRANS_RESP_IMMEDIATE = 4 /* After an ind, set data and send resp (NOT IMPL) */ +}; + +typedef struct wl_bsstrans_resp { + uint8 policy; + uint8 status; + uint8 delay; + struct ether_addr target; +} wl_bsstrans_resp_t; + +/* "wnm_bsstrans_resp" argument programming behavior after BSSTRANS Req reception */ +enum { + WL_BSSTRANS_RESP_ROAM_ALWAYS = 0, /* Roam (or disassociate) in all cases */ + WL_BSSTRANS_RESP_ROAM_IF_MODE = 1, /* Roam only if requested by Request Mode field */ + WL_BSSTRANS_RESP_ROAM_IF_PREF = 2, /* Roam only if Preferred BSS provided */ + WL_BSSTRANS_RESP_WAIT = 3 /* Wait for deauth and send Accepted status */ +}; + +/* Definitions for WNM/NPS TIM Broadcast */ +typedef struct wl_timbc_offset { + int16 offset; /* offset in us */ + uint16 fix_intv; /* override interval sent from STA */ + uint16 rate_override; /* use rate override to send high rate TIM broadcast frame */ + uint8 tsf_present; /* show timestamp in TIM broadcast frame */ +} wl_timbc_offset_t; + +typedef struct wl_timbc_set { + uint8 interval; /* Interval in DTIM wished or required. */ + uint8 flags; /* Bitfield described below */ + uint16 rate_min; /* Minimum rate required for High/Low TIM frames. Optionnal */ + uint16 rate_max; /* Maximum rate required for High/Low TIM frames. Optionnal */ +} wl_timbc_set_t; + +enum { + WL_TIMBC_SET_TSF_REQUIRED = 1, /* Enable TIMBC only if TSF in TIM frames */ + WL_TIMBC_SET_NO_OVERRIDE = 2, /* ... if AP does not override interval */ + WL_TIMBC_SET_PROXY_ARP = 4, /* ... if AP support Proxy ARP */ + WL_TIMBC_SET_DMS_ACCEPTED = 8 /* ... if all DMS desc have been accepted */ +}; + +typedef struct wl_timbc_status { + uint8 status_sta; /* Status from internal state machine (check below) */ + uint8 status_ap; /* From AP response frame (check 8.4.2.86 from 802.11) */ + uint8 interval; + uint8 pad; + int32 offset; + uint16 rate_high; + uint16 rate_low; +} wl_timbc_status_t; + +enum { + WL_TIMBC_STATUS_DISABLE = 0, /* TIMBC disabled by user */ + WL_TIMBC_STATUS_REQ_MISMATCH = 1, /* AP settings do no match user requirements */ + WL_TIMBC_STATUS_NOT_ASSOC = 2, /* STA not associated */ + WL_TIMBC_STATUS_NOT_SUPPORT = 3, /* TIMBC not supported by AP */ + WL_TIMBC_STATUS_DENIED = 4, /* Req to disable TIMBC sent to AP */ + WL_TIMBC_STATUS_ENABLE = 5 /* TIMBC enabled */ +}; + +/* Definitions for PM2 Dynamic Fast Return To Sleep */ +typedef struct wl_pm2_sleep_ret_ext { + uint8 logic; /* DFRTS logic: see WL_DFRTS_LOGIC_* below */ + uint16 low_ms; /* Low FRTS timeout */ + uint16 high_ms; /* High FRTS timeout */ + uint16 rx_pkts_threshold; /* switching threshold: # rx pkts */ + uint16 tx_pkts_threshold; /* switching threshold: # tx pkts */ + uint16 txrx_pkts_threshold; /* switching threshold: # (tx+rx) pkts */ + uint32 rx_bytes_threshold; /* switching threshold: # rx bytes */ + uint32 tx_bytes_threshold; /* switching threshold: # tx bytes */ + uint32 txrx_bytes_threshold; /* switching threshold: # (tx+rx) bytes */ +} wl_pm2_sleep_ret_ext_t; + +#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ +#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ +#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ + +/* Values for the passive_on_restricted_mode iovar. When set to non-zero, this iovar + * disables automatic conversions of a channel from passively scanned to + * actively scanned. These values only have an effect for country codes such + * as XZ where some 5 GHz channels are defined to be passively scanned. + */ +#define WL_PASSACTCONV_DISABLE_NONE 0 /* Enable permanent and temporary conversions */ +#define WL_PASSACTCONV_DISABLE_ALL 1 /* Disable permanent and temporary conversions */ +#define WL_PASSACTCONV_DISABLE_PERM 2 /* Disable only permanent conversions */ + +/* Definitions for Reliable Multicast */ +#define WL_RMC_CNT_VERSION 1 +#define WL_RMC_MAX_CLIENT 32 +#define WL_RMC_FLAG_INBLACKLIST 1 +#define WL_RMC_FLAG_ACTIVEACKER 2 +#define WL_RMC_FLAG_RELMCAST 4 +#define WL_RMC_MAX_TABLE_ENTRY 4 + +#define WL_RMC_VER 1 +#define WL_RMC_INDEX_ACK_ALL 255 +#define WL_RMC_NUM_OF_MC_STREAMS 4 +#define WL_RMC_MAX_TRS_PER_GROUP 1 +#define WL_RMC_MAX_TRS_IN_ACKALL 1 +#define WL_RMC_ACK_MCAST0 0x02 +#define WL_RMC_ACK_MCAST_ALL 0x01 +#define WL_RMC_ACTF_TIME_MIN 300 /* time in ms */ +#define WL_RMC_ACTF_TIME_MAX 20000 /* time in ms */ +#define WL_RMC_ARTMO_MIN 350 /* time in ms */ +#define WL_RMC_ARTMO_MAX 40000 /* time in ms */ + +/* RMC events in action frames */ +enum rmc_opcodes { + RELMCAST_ENTRY_OP_DISABLE = 0, /* Disable multi-cast group */ + RELMCAST_ENTRY_OP_DELETE = 1, /* Delete multi-cast group */ + RELMCAST_ENTRY_OP_ENABLE = 2, /* Enable multi-cast group */ + RELMCAST_ENTRY_OP_ACK_ALL = 3 /* Enable ACK ALL bit in AMT */ +}; + +/* RMC operational modes */ +enum rmc_modes { + WL_RMC_MODE_RECEIVER = 0, /* Receiver mode by default */ + WL_RMC_MODE_TRANSMITTER = 1, /* Transmitter mode using wl ackreq */ + WL_RMC_MODE_INITIATOR = 2 /* Initiator mode using wl ackreq */ +}; + +/* Each RMC mcast client info */ +typedef struct wl_relmcast_client { + uint8 flag; /* status of client such as AR, R, or blacklisted */ + int16 rssi; /* rssi value of RMC client */ + struct ether_addr addr; /* mac address of RMC client */ +} wl_relmcast_client_t; + +/* RMC Counters */ +typedef struct wl_rmc_cnts { + uint16 version; /* see definition of WL_CNT_T_VERSION */ + uint16 length; /* length of entire structure */ + uint16 dupcnt; /* counter for duplicate rmc MPDU */ + uint16 ackreq_err; /* counter for wl ackreq error */ + uint16 af_tx_err; /* error count for action frame transmit */ + uint16 null_tx_err; /* error count for rmc null frame transmit */ + uint16 af_unicast_tx_err; /* error count for rmc unicast frame transmit */ + uint16 mc_no_amt_slot; /* No mcast AMT entry available */ + uint16 mc_no_glb_slot; /* No mcast entry available in global table */ + uint16 mc_not_mirrored; /* mcast group is not mirrored */ + uint16 mc_existing_tr; /* mcast group is already taken by transmitter */ + uint16 mc_exist_in_amt; /* mcast group is already programmed in amt */ + uint16 mc_not_exist_in_gbl; /* mcast group is not in global table */ + uint16 mc_not_exist_in_amt; /* mcast group is not in AMT table */ + uint16 mc_utilized; /* mcast addressed is already taken */ + uint16 mc_taken_other_tr; /* multi-cast addressed is already taken */ + uint32 rmc_rx_frames_mac; /* no of mc frames received from mac */ + uint32 rmc_tx_frames_mac; /* no of mc frames transmitted to mac */ + uint32 mc_null_ar_cnt; /* no. of times NULL AR is received */ + uint32 mc_ar_role_selected; /* no. of times took AR role */ + uint32 mc_ar_role_deleted; /* no. of times AR role cancelled */ + uint32 mc_noacktimer_expired; /* no. of times noack timer expired */ +} wl_rmc_cnts_t; + +/* RMC Status */ +typedef struct wl_relmcast_st { + uint8 ver; /* version of RMC */ + uint8 num; /* number of clients detected by transmitter */ + wl_relmcast_client_t clients[WL_RMC_MAX_CLIENT]; + uint16 err; /* error status (used in infra) */ + uint16 actf_time; /* action frame time period */ +} wl_relmcast_status_t; + +/* Entry for each STA/node */ +typedef struct wl_rmc_entry { + /* operation on multi-cast entry such add, + * delete, ack-all + */ + int8 flag; + struct ether_addr addr; /* multi-cast group mac address */ +} wl_rmc_entry_t; + +/* RMC table */ +typedef struct wl_rmc_entry_table { + uint8 index; /* index to a particular mac entry in table */ + uint8 opcode; /* opcodes or operation on entry */ + wl_rmc_entry_t entry[WL_RMC_MAX_TABLE_ENTRY]; +} wl_rmc_entry_table_t; + +/* Transmitter Info */ +typedef struct wl_rmc_trans_info { + struct ether_addr addr; /* transmitter mac */ + uint32 time_val; /* timer val in case aging of entry is required */ + uint16 seq; /* last seq number of packet received from transmitter */ + uint16 artmo; +} wl_rmc_trans_info_t; + +/* Multicast Group */ +typedef struct wl_rmc_grp_entry { + struct ether_addr mcaddr; /* multi-cast group mac */ + struct ether_addr ar; /* active receiver for the group */ + wl_rmc_trans_info_t tr_info[WL_RMC_MAX_TRS_PER_GROUP]; +} wl_rmc_grp_entry_t; + +/* RMC ACKALL Table */ +typedef struct wl_rmc_ackall_entry { + struct ether_addr ar; /* active receiver for the entry */ + wl_rmc_trans_info_t tr_info[WL_RMC_NUM_OF_MC_STREAMS]; +} wl_rmc_ackall_entry_t; + +/* RMC Peers Table */ +typedef struct wl_rmc_gbl_table { + uint8 activeMask; /* mask to denote the entry(s) that are active */ + wl_rmc_ackall_entry_t ackAll; /* structure to keep info related to ACK all */ + wl_rmc_grp_entry_t mc_entry[WL_RMC_NUM_OF_MC_STREAMS]; +} wl_rmc_gbl_table_t; + +/* To update vendor specific ie for RMC */ +typedef struct wl_rmc_vsie { + uint8 oui[DOT11_OUI_LEN]; + uint16 payload; /* IE Data Payload */ +} wl_rmc_vsie_t; + +typedef struct wl_proxd_iovar { + uint16 method; /* Proxmity Detection method */ + uint16 mode; /* Mode (neutral, initiator, target) */ +} wl_proxd_iovar_t; + +/* structures for proximity detection parameters */ +typedef struct wl_proxd_params_rssi_method { + chanspec_t chanspec; /* chanspec for home channel */ + uint16 interval; /* interval between neighbor finding attempts (in TU) */ + uint16 duration; /* duration of neighbor finding attempts (in ms) */ + int16 rssi_thresh; /* RSSI threshold (in dBm) */ + int16 tx_power; /* tx power of Proximity Detection frames (in dBm) */ + uint16 tx_rate; /* tx rate of Proximity Detection frames + * (in 500kbps units) + */ + uint16 timeout; /* state machine wait timeout of the frames (in ms) */ + uint16 maxconvergtmo; /* max wait converge timeout (in ms) */ +} wl_proxd_params_rssi_method_t; + +typedef struct wl_proxd_params_iovar { + uint16 method; /* Proxmity Detection method */ + union { + wl_proxd_params_rssi_method_t rssi_params; + } u; /* Method specific optional parameters */ +} wl_proxd_params_iovar_t; + +enum { + RSSI_REASON_UNKNOW, + RSSI_REASON_LOWRSSI, + RSSI_REASON_NSYC, + RSSI_REASON_TIMEOUT +}; + +enum { + RSSI_STATE_POLL, + RSSI_STATE_TPAIRING, + RSSI_STATE_IPAIRING, + RSSI_STATE_THANDSHAKE, + RSSI_STATE_IHANDSHAKE, + RSSI_STATE_CONFIRMED, + RSSI_STATE_PIPELINE, + RSSI_STATE_NEGMODE, + RSSI_STATE_MONITOR, + RSSI_STATE_LAST +}; + +typedef struct wl_proxd_status_iovar { + uint8 mode; + uint8 peermode; + uint8 state; + uint8 reason; + uint32 txcnt; + uint32 rxcnt; + struct ether_addr peer; + int16 hi_rssi; + int16 low_rssi; +} wl_proxd_status_iovar_t; + +#ifdef NET_DETECT +typedef struct net_detect_adapter_features { + bool wowl_enabled; + bool net_detect_enabled; + bool nlo_enabled; +} net_detect_adapter_features_t; + +typedef enum net_detect_bss_type { + nd_bss_any = 0, + nd_ibss, + nd_ess +} net_detect_bss_type_t; + +typedef struct net_detect_profile { + wlc_ssid_t ssid; + net_detect_bss_type_t bss_type; /* Ignore for now since Phase 1 is only for ESS */ + uint32 cipher_type; /* DOT11_CIPHER_ALGORITHM enumeration values */ + uint32 auth_type; /* DOT11_AUTH_ALGORITHM enumeration values */ +} net_detect_profile_t; + +typedef struct net_detect_profile_list { + uint32 num_nd_profiles; + net_detect_profile_t nd_profile[0]; +} net_detect_profile_list_t; + +typedef struct net_detect_config { + bool nd_enabled; + uint32 scan_interval; + uint32 wait_period; + bool wake_if_connected; + bool wake_if_disconnected; + net_detect_profile_list_t nd_profile_list; +} net_detect_config_t; + +typedef enum net_detect_wake_reason { + nd_reason_unknown, + nd_net_detected, + nd_wowl_event, + nd_ucode_error +} net_detect_wake_reason_t; + +typedef struct net_detect_wake_data { + net_detect_wake_reason_t nd_wake_reason; + uint32 nd_wake_date_length; + uint8 nd_wake_data[0]; /* Wake data (currently unused) */ +} net_detect_wake_data_t; + +#endif /* NET_DETECT */ + +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +typedef struct bcnreq { + uint8 bcn_mode; + int dur; + int channel; + struct ether_addr da; + uint16 random_int; + wlc_ssid_t ssid; + uint16 reps; +} bcnreq_t; + +typedef struct rrmreq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + uint16 reps; +} rrmreq_t; + +typedef struct framereq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + struct ether_addr ta; + uint16 reps; +} framereq_t; + +typedef struct statreq { + struct ether_addr da; + struct ether_addr peer; + uint16 random_int; + uint16 dur; + uint8 group_id; + uint16 reps; +} statreq_t; + +typedef struct wlc_l2keepalive_ol_params { + uint8 flags; + uint8 prio; + uint16 period_ms; +} wlc_l2keepalive_ol_params_t; + +typedef struct wlc_dwds_config { + uint32 enable; + uint32 mode; /* STA/AP interface */ + struct ether_addr ea; +} wlc_dwds_config_t; + +typedef struct wl_el_set_params_s { + uint8 set; /* Set number */ + uint32 size; /* Size to make/expand */ +} wl_el_set_params_t; + +typedef struct wl_el_tag_params_s { + uint16 tag; + uint8 set; + uint8 flags; +} wl_el_tag_params_t; + +/* Video Traffic Interference Monitor config */ +#define INTFER_VERSION 1 +typedef struct wl_intfer_params { + uint16 version; /* version */ + uint8 period; /* sample period */ + uint8 cnt; /* sample cnt */ + uint8 txfail_thresh; /* non-TCP txfail threshold */ + uint8 tcptxfail_thresh; /* tcptxfail threshold */ +} wl_intfer_params_t; + +typedef struct wl_staprio_cfg { + struct ether_addr ea; /* mac addr */ + uint8 prio; /* scb priority */ +} wl_staprio_cfg_t; + +typedef enum wl_stamon_cfg_cmd_type { + STAMON_CFG_CMD_DEL = 0, + STAMON_CFG_CMD_ADD = 1 +} wl_stamon_cfg_cmd_type_t; + +typedef struct wlc_stamon_sta_config { + wl_stamon_cfg_cmd_type_t cmd; /* 0 - delete, 1 - add */ + struct ether_addr ea; +} wlc_stamon_sta_config_t; + +/* Received Beacons lengths information */ +#define WL_LAST_BCNS_INFO_FIXED_LEN OFFSETOF(wlc_bcn_len_hist_t, bcnlen_ring) +typedef struct wlc_bcn_len_hist { + uint16 ver; /* version field */ + uint16 cur_index; /* current pointed index in ring buffer */ + uint32 max_bcnlen; /* Max beacon length received */ + uint32 min_bcnlen; /* Min beacon length received */ + uint32 ringbuff_len; /* Length of the ring buffer 'bcnlen_ring' */ + uint32 bcnlen_ring[1]; /* ring buffer storing received beacon lengths */ +} wlc_bcn_len_hist_t; + +/* WDS net interface types */ +#define WL_WDSIFTYPE_NONE 0x0 /* The interface type is neither WDS nor DWDS. */ +#define WL_WDSIFTYPE_WDS 0x1 /* The interface is WDS type. */ +#define WL_WDSIFTYPE_DWDS 0x2 /* The interface is DWDS type. */ + +typedef struct wl_bssload_static { + bool is_static; + uint16 sta_count; + uint8 chan_util; + uint16 aac; +} wl_bssload_static_t; + + +#ifdef SR_DEBUG +typedef struct /* pmu_reg */{ + uint32 pmu_control; + uint32 pmu_capabilities; + uint32 pmu_status; + uint32 res_state; + uint32 res_pending; + uint32 pmu_timer1; + uint32 min_res_mask; + uint32 max_res_mask; + uint32 pmu_chipcontrol1[4]; + uint32 pmu_regcontrol[5]; + uint32 pmu_pllcontrol[5]; + uint32 pmu_rsrc_up_down_timer[31]; + uint32 rsrc_dep_mask[31]; +} pmu_reg_t; + +typedef struct { + uint32 pmu_min_res_val; + uint16 pmu_flag; +} pmu_min_res_t; + +#endif /* SR_DEBUG */ + +typedef enum event_msgs_ext_command { + EVENTMSGS_NONE = 0, + EVENTMSGS_SET_BIT = 1, + EVENTMSGS_RESET_BIT = 2, + EVENTMSGS_SET_MASK = 3 +} event_msgs_ext_command_t; + +#define EVENTMSGS_VER 1 +#define EVENTMSGS_EXT_STRUCT_SIZE OFFSETOF(eventmsgs_ext_t, mask[0]) + +/* len - for SET it would be mask size from the application to the firmware + * for GET it would be actual firmware mask size + * maxgetsize - is only used for GET. indicate max mask size that the + * application can read from the firmware + */ +typedef struct eventmsgs_ext +{ + uint8 ver; + uint8 command; + uint8 len; + uint8 maxgetsize; + uint8 mask[1]; +} eventmsgs_ext_t; + +#ifdef TBTT_OFFSET_STAT +/* XXX: tbtt offset stat is only for primary STA and non-p2p link */ +typedef struct { + uint32 tbtt_offset_avg; + uint32 tbtt_offset_min; + uint32 tbtt_offset_max; +} tbtt_offset_stat_t; +#endif /* TBTT_OFFSET_STAT */ + +#endif /* _wlioctl_h_ */
diff --git a/src/makefiles/RelPath.mk b/src/makefiles/RelPath.mk new file mode 100644 index 0000000..8aa3cee --- /dev/null +++ b/src/makefiles/RelPath.mk
@@ -0,0 +1,81 @@ +ifdef _RELPATH_MK_ +$(if $D,$(info =-= Avoiding redundant include ($(MAKEFILE_LIST)))) +else +unexport _RELPATH_MK_ # in case of make -e +_RELPATH_MK_ := 1 + +# Protection against process recursion when this file is +# included by setting MAKEFILES. +ifneq (,$(filter %$(notdir $(lastword $(MAKEFILE_LIST))),$(MAKEFILES))) +MAKEFILES := $(filter-out %$(notdir $(lastword $(MAKEFILE_LIST))),$(MAKEFILES)) +ifndef MAKEFILES +unexport MAKEFILES +endif +endif + +# Usage: $(call relpath,[<from-dir>,]<to-dir>) +# Returns the relative path from <from-dir> to <to-dir>; <from-dir> +# may be elided in which case it defaults to $(CURDIR). + +_rp_space := +_rp_space += +_rp_uname_s := $(shell uname -s) + +# Utility functions. +_rp_compose = $(subst ${_rp_space},$(strip $1),$(strip $2)) +_rp_endlist = $(wordlist $1,$(words $2),$2) +_rp_canonpath = $(if $(findstring CYGWIN,$(_rp_uname_s)),$(shell cygpath -a -u $1),$(abspath $1)) + +# ----relpath(): Self-recursive function which compares the first element +# of two given paths, then calls itself with the next two +# elements, and so on, until a difference is found. At each +# step, if the first element of both paths matches, that +# element is produced. +----relpath = $(if $(filter $(firstword $1),$(firstword $2)), \ + $(firstword $1) \ + $(call $0,$(call _rp_endlist,2,$1),$(call _rp_endlist,2,$2)) \ + ) +# ---relpath(): This function removes $1 from the front of both $2 and +# $3 (removes common path prefix) and generates a relative +# path between the locations given by $2 and $3, by replacing +# each remaining element of $2 (after common prefix removal) +# with '..', then appending the remainder of $3 (after common +# prefix removal) to the string of '..'s +---relpath = $(foreach e,$(subst /, ,$(patsubst $(if $1,/)$1/%,%,$2)),..) \ + $(if $3,$(patsubst $(if $1,/)$1/%,%,$3)) +# --relpath(): This function runs the output of ----relpath() through +# ---relpath(), and turns the result into an actual relative +# path string, separated by '/'. +--relpath = $(call _rp_compose,/, \ + $(call -$0,$(call _rp_compose,/,$(call --$0,$3,$4)),$1,$2) \ + ) +# -relpath(): This function makes a determination about the two given +# paths -- does one strictly prefix the other? If so, this +# function produces a relative path between the two inputs, +# without calling --relpath() and taking the "long road". +# If $1 prefixes $2, the result is the remainder of $2 after +# removing $1. If $2 prefixes $1, the result is the remainder +# of $1 after removing $2, but with each element in that +# remainder converted to '..'. +-relpath = $(if $(filter $1,$2),., \ + $(if $(filter $1/%,$2), \ + $(patsubst $1/%,%,$2), \ + $(if $(filter $2/%,$1), \ + $(call _rp_compose,/, \ + $(foreach e,$(subst /, ,$(patsubst $2/%,%,$1)),..) \ + ), \ + $(call -$0,$1,$2,$(subst /, ,$1),$(subst /, ,$2)) \ + ) \ + ) \ + ) + +# relpath(): This function loops over each element in $2, calculating +# the relative path from $1 to each element of $2. +relpath = $(if $1,,$(error Error: missing first parameter to $0))$(strip \ + $(if $2, \ + $(foreach d,$2,$(call -$0,$(call _rp_canonpath,$1),$(call _rp_canonpath,$d))), \ + $(foreach d,$1,$(call -$0,$(call _rp_canonpath,${CURDIR}),$(call _rp_canonpath,$d))) \ + ) \ + ) + +endif #_RELPATH_MK_
diff --git a/src/makefiles/WLAN_Common.mk b/src/makefiles/WLAN_Common.mk new file mode 100644 index 0000000..6009766 --- /dev/null +++ b/src/makefiles/WLAN_Common.mk
@@ -0,0 +1,389 @@ +ifdef _WLAN_COMMON_MK +$(if $D,$(info Info: Avoiding redundant include ($(MAKEFILE_LIST)))) +else # _WLAN_COMMON_MK +_WLAN_COMMON_MK := 1 +unexport _WLAN_COMMON_MK # in case of make -e + +################################################################ +# Summary and Namespace Rules +################################################################ +# This is a special makefile fragment intended for common use. +# The most important design principle is that it be used only to +# define variables and functions in a tightly controlled namespace. +# If a make include file is used to set rules, pattern rules, +# or well known variables like CFLAGS, it can have unexpected +# effects on the including makefile, with the result that people +# either stop including it or stop changing it. +# Therefore, the only way to keep this a file which can be +# safely included by any GNU makefile and extended at will is +# to allow it only to set variables and only in its own namespace. +# The namespace is "WLAN_CamelCase" for normal variables, +# "wlan_lowercase" for functions, and WLAN_UPPERCASE for boolean +# "constants" (these are all really just make variables; only the +# usage patterns differ). +# Internal (logically file-scoped) variables are prefixed with "-" +# and have no other namespace restrictions. +# Every variable defined here should match one of these patterns. + +################################################################ +# Enforce required conditions +################################################################ + +ifneq (,$(filter 3.7% 3.80,$(MAKE_VERSION))) +$(error $(MAKE): Error: version $(MAKE_VERSION) too old, 3.81+ required) +endif + +################################################################ +# Derive including makefile since it's a little tricky. +################################################################ + +WLAN_Makefile := $(abspath $(lastword $(filter-out $(lastword $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))) + +################################################################ +# Shiny new ideas, can be enabled via environment for testing. +################################################################ + +ifdef WLAN_MakeBeta +$(info Info: BUILDING WITH "WLAN_MakeBeta" ENABLED!) +SHELL := /bin/bash +#export SHELLOPTS ?= pipefail +#.SUFFIXES: +#MAKEFLAGS += -r +endif + +################################################################ +# Allow a makefile to force this file into all child makes. +################################################################ + +ifdef WLAN_StickyCommon +export MAKEFILES := $(MAKEFILES) $(abspath $(lastword $(MAKEFILE_LIST))) +endif + +################################################################ +# Host type determination +################################################################ + +_common-uname-s := $(shell uname -s) + +# Typically this will not be tested explicitly; it's the default condition. +WLAN_HOST_TYPE := unix + +ifneq (,$(filter Linux,$(_common-uname-s))) + WLAN_LINUX_HOST := 1 +else ifneq (,$(filter CYGWIN%,$(_common-uname-s))) + WLAN_CYGWIN_HOST := 1 + WLAN_WINDOWS_HOST := 1 +else ifneq (,$(filter Darwin,$(_common-uname-s))) + WLAN_MACOS_HOST := 1 + WLAN_BSD_HOST := 1 +else ifneq (,$(filter FreeBSD NetBSD,$(_common-uname-s))) + WLAN_BSD_HOST := 1 +else ifneq (,$(filter SunOS%,$(_common-uname-s))) + WLAN_SOLARIS_HOST := 1 +endif + +################################################################ +# Utility variables +################################################################ + +empty := +space := $(empty) $(empty) +comma := , + +################################################################ +# Utility functions +################################################################ + +# Provides enhanced-format messages from make logic. +wlan_die = $(error Error: $1) +wlan_warning = $(warning Warning: $1) +wlan_info = $(info Info: $1) + +# Debug function to enable make verbosity. +wlan_dbg = $(if $D,$(call wlan_info,$1)) + +# Debug function to expose values of the listed variables. +wlan_dbgv = $(foreach _,$1,$(call wlan_dbg,$_=$($_))) + +# Make-time assertion. +define wlan_assert +ifeq (,$(findstring clean,$(MAKECMDGOALS))) +$(if $1,,$(call wlan_die,$2)) +endif +endef + +# Checks for the presence of an option in an option string +# like "aaa-bbb-ccc-ddd". +wlan_opt = $(if $(findstring -$1-,-$2-),1,0) + +# Compares two dotted numeric strings (e.g 2.3.16.1) for $1 >= $2 +define wlan_version_ge +$(findstring TRUE,$(shell bash -c 'sort -cu -t. -k1,1nr -k2,2nr -k3,3nr -k4,4nr <(echo -e "$2\n$1") 2>&1 || echo TRUE')) +endef + +# This is a useful macro to wrap around a compiler command line, +# e.g. "$(call wlan_cc,<command-line>). It organizes flags in a +# readable way while taking care not to change any ordering +# which matters. It also provides a hook for externally +# imposed C flags which can be passed in from the top level. +# This would be the best place to add a check for +# command line length. Requires a $(strlen) function; +# GMSL has one. +define wlan_cc +$(filter-out -D% -I%,$1) $(filter -D%,$1) $(filter -I%,$1) $(WLAN_EXTERNAL_CFLAGS) +endef + +# Applies the standard cygpath translation for a path on Cygwin. +define wlan_cygpath +$(if $(WLAN_CYGWIN_HOST),$(shell cygpath -m $1),$1) +endef + +################################################################ +# Standard make variables +################################################################ + +# This points to the root of the build tree, currently known to +# be 2 levels above the directory of this file. +ifndef WLAN_TreeBaseA +ifdef WLAN_CYGWIN_HOST +WLAN_TreeBaseA := $(shell cygpath -m -a $(dir $(lastword $(MAKEFILE_LIST)))../..) +else +WLAN_TreeBaseA := $(subst \,/,$(realpath $(dir $(lastword $(MAKEFILE_LIST)))../..)) +endif +endif + +# We've observed a bug, or at least a surprising behavior, in emake which +# causes the $(realpath) above to fail so this fallback is used. +ifndef WLAN_TreeBaseA +WLAN_TreeBaseA := $(shell cd $(dir $(lastword $(MAKEFILE_LIST)))../.. && pwd) +endif + +# Export these values so they can be used by scripts or nmake/pmake makefiles. +export WLAN_TreeBaseA + +# We may eventually remove this and require an +# explict absolute-vs-relative choice. +export WLAN_TreeBase := $(WLAN_TreeBaseA) + +# Pick up the "relpath" make function. +include $(WLAN_TreeBaseA)/src/makefiles/RelPath.mk + +# This is a relativized version of $(WLAN_TreeBaseA). +export WLAN_TreeBaseR = $(call relpath,$(WLAN_TreeBaseA)) + +# For compatibility, due to the prevalence of $(SRCBASE) +WLAN_SrcBaseA := $(WLAN_TreeBaseA)/src +WLAN_SrcBaseR = $(patsubst %/,%,$(dir $(WLAN_TreeBaseR))) + +# Show makefile list before we start including things. +$(call wlan_dbgv, CURDIR MAKEFILE_LIST) + +################################################################ +# Pick up the "universal settings file" containing +# the list of all available software components. +################################################################ + +include $(WLAN_TreeBaseA)/src/tools/release/WLAN.usf + +################################################################ +# Calculate paths to requested components. +################################################################ + +# This uses pattern matching to pull component paths from +# their basenames (e.g. src/wl/xyz => xyz). +# It also strips out component paths which don't currently exist. +# This may be required due to our "partial-source" build styles +# and the fact that linux mkdep throws an error when a directory +# specified with -I doesn't exist. +define _common-component-names-to-rel-paths +$(strip \ + $(patsubst $(WLAN_TreeBaseA)/%,%,$(wildcard $(addprefix $(WLAN_TreeBaseA)/,\ + $(sort $(foreach name,$(if $1,$1,$(WLAN_COMPONENT_PATHS)),$(filter %/$(name),$(WLAN_COMPONENT_PATHS)))))))) +endef + +# If WLAN_ComponentsInUse is unset it defaults to the full set (for now, anyway - TODO). +# It's also possible to request the full set with a literal '*'. +ifeq (,$(WLAN_ComponentsInUse)) + WLAN_ComponentsInUse := $(sort $(notdir $(WLAN_COMPONENT_PATHS))) + # $(call wlan_die,no SW component request) +else ifeq (*,$(WLAN_ComponentsInUse)) + WLAN_ComponentsInUse := $(sort $(notdir $(WLAN_COMPONENT_PATHS))) + $(call wlan_info,all SW components requested ("$(WLAN_ComponentsInUse)")) +else + WLAN_ComponentsInUse := $(sort $(WLAN_ComponentsInUse)) +endif +WLAN_ComponentPathsInUse := $(call _common-component-names-to-rel-paths,$(WLAN_ComponentsInUse)) + +# Test that all requested components exist. +ifneq ($(sort $(WLAN_ComponentsInUse)),$(notdir $(WLAN_ComponentPathsInUse))) +# TODO - turned off until old branches support this infrastructure. +# $(call wlan_warning,bogus component request: "$(sort $(WLAN_ComponentsInUse))" != "$(notdir $(WLAN_ComponentPathsInUse))") +endif + +# Loop through all components in use. If an xyz.mk file exists at the base of +# component xyz's subtree, include it and use its contents to modify the list +# of include and src dirs. Otherwise, use the defaults for that component. +# Also generate a WLAN_ComponentBaseDir_xyz variable for each component "xyz". +WLAN_ComponentIncPathsInUse := +WLAN_ComponentSrcPathsInUse := +$(foreach _path,$(WLAN_ComponentPathsInUse), \ + $(if $(wildcard $(WLAN_TreeBaseA)/$(_path)/$(notdir $(_path)).mk),$(eval include $(WLAN_TreeBaseA)/$(_path)/$(notdir $(_path)).mk)) \ + $(eval $(notdir $(_path))_IncDirs ?= include) \ + $(eval $(notdir $(_path))_SrcDirs ?= src) \ + $(eval WLAN_ComponentIncPathsInUse += $(addprefix $(_path)/,$($(notdir $(_path))_IncDirs))) \ + $(eval WLAN_ComponentSrcPathsInUse += $(addprefix $(_path)/,$($(notdir $(_path))_SrcDirs))) \ + $(eval WLAN_ComponentBaseDir_$$(notdir $(_path)) := $$(WLAN_TreeBaseA)/$(_path)) \ +) + +# Phy specific subdirs +ifeq ($(findstring phymods,$(WLAN_ComponentsInUse)),phymods) +PHY_TOP_DIR = src/wl/phymods +PHY_CMN_DIR_LIST = dbg +PHY_1OFF_DIR_LIST = +PHY_TYPE_LIST = cmn +PHY_MOD_LIST = core radar +PHY_MOD_SRC_DIRS = $(foreach PHY_CMN_DIR,$(PHY_CMN_DIR_LIST),$(PHY_TOP_DIR)/cmn/$(PHY_CMN_DIR)/src) +PHY_MOD_SRC_DIRS += $(foreach PHY_1OFF_DIR,$(PHY_1OFF_DIR_LIST),$(PHY_TOP_DIR)/$(PHY_1OFF_DIR)/src) +PHY_MOD_SRC_DIRS += $(foreach PHY_TYPE,$(PHY_TYPE_LIST),\ + $(foreach PHY_MOD,$(PHY_MOD_LIST),$(PHY_TOP_DIR)/$(PHY_TYPE)/$(PHY_MOD)/src)) +PHY_MOD_INC_DIRS = $(foreach PHY_CMN_DIR,$(PHY_CMN_DIR_LIST),$(PHY_TOP_DIR)/cmn/$(PHY_CMN_DIR)/include) +PHY_MOD_INC_DIRS += $(foreach PHY_1OFF_DIR,$(PHY_1OFF_DIR_LIST),$(PHY_TOP_DIR)/$(PHY_1OFF_DIR)/include) +PHY_MOD_INC_DIRS += $(foreach PHY_TYPE,$(PHY_TYPE_LIST),\ + $(foreach PHY_MOD,$(PHY_MOD_LIST),$(PHY_TOP_DIR)/$(PHY_TYPE)/$(PHY_MOD)/include)) +PHY_MOD_INC_DIRS += $(foreach PHY_DIR,$(PHY_MOD_SRC_DIRS),$(PHY_DIR)) +else +PHY_MOD_SRC_DIRS = +PHY_MOD_INC_DIRS = +endif + +# Global include/source path +WLAN_StdSrcDirs = src/shared src/wl/sys src/wl/phy src/bcmcrypto +WLAN_StdSrcDirs += $(PHY_MOD_SRC_DIRS) +WLAN_StdIncDirs = src/include src/common/include src/common/include/devctrl_if +WLAN_StdIncDirs += $(PHY_MOD_INC_DIRS) + +WLAN_SrcIncDirs = src/shared src/wl/sys src/wl/ndis/include src/wl/phy src/bcmcrypto +WLAN_SrcIncDirs += src/wl/keymgmt/src src/wl/iocv/src +WLAN_SrcIncDirs += $(PHY_MOD_SRC_DIRS) + +export WLAN_StdSrcDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_StdSrcDirs)) +export WLAN_StdIncDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_StdIncDirs)) +export WLAN_SrcIncDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_SrcIncDirs)) +export WLAN_StdIncPathR = $(addprefix -I,$(WLAN_StdIncDirsR)) +export WLAN_IncDirsR = $(WLAN_StdIncDirsR) $(WLAN_SrcIncDirsR) +export WLAN_IncPathR = $(addprefix -I,$(WLAN_IncDirsR)) + +export WLAN_StdSrcDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_StdSrcDirs)) +export WLAN_StdIncDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_StdIncDirs)) +export WLAN_SrcIncDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_SrcIncDirs)) +export WLAN_StdIncPathA = $(addprefix -I,$(WLAN_StdIncDirsA)) +export WLAN_IncDirsA = $(WLAN_StdIncDirsA) $(WLAN_SrcIncDirsA) +export WLAN_IncPathA = $(addprefix -I,$(WLAN_IncDirsA)) + +# Public convenience macros based on WLAN_ComponentPathsInUse list. +export WLAN_ComponentSrcDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_ComponentSrcPathsInUse)) +export WLAN_ComponentIncDirsR = $(addprefix $(WLAN_TreeBaseR)/,$(WLAN_ComponentIncPathsInUse)) +export WLAN_ComponentIncPathR = $(addprefix -I,$(WLAN_ComponentIncDirsR)) + +export WLAN_ComponentSrcDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_ComponentSrcPathsInUse)) +export WLAN_ComponentIncDirsA = $(addprefix $(WLAN_TreeBaseA)/,$(WLAN_ComponentIncPathsInUse)) +export WLAN_ComponentIncPathA = $(addprefix -I,$(WLAN_ComponentIncDirsA)) + +export WLAN_ComponentSrcDirs = $(WLAN_ComponentSrcDirsA) +export WLAN_ComponentIncDirs = $(WLAN_ComponentIncDirsA) +export WLAN_ComponentIncPath = $(WLAN_ComponentIncPathA) + +# Dump a representative sample of derived variables in debug mode. +$(call wlan_dbgv, WLAN_TreeBaseA WLAN_TreeBaseR WLAN_SrcBaseA WLAN_SrcBaseR \ + WLAN_ComponentPathsInUse WLAN_ComponentIncPath WLAN_ComponentIncPathR \ + WLAN_ComponentSrcDirs WLAN_ComponentSrcDirsR) + +# Special case for Windows to reflect CL in the build log if used. +ifdef WLAN_WINDOWS_HOST +ifdef CL +$(info Info: CL=$(CL)) +endif +endif + +# A big hammer for debugging each shell invocation. +# Warning: this can get lost if a sub-makefile sets SHELL explicitly, and +# if so the parent should add $WLAN_ShellDebugSHELL to the call. +ifeq ($D,2) +WLAN_ShellDebug := 1 +endif +ifdef WLAN_ShellDebug +ORIG_SHELL := $(SHELL) +SHELL = $(strip $(warning Shell: ORIG_SHELL=$(ORIG_SHELL) PATH=$(PATH))$(ORIG_SHELL)) -x +WLAN_ShellDebugSHELL := SHELL='$$(warning Shell: ORIG_SHELL=$$(ORIG_SHELL) PATH=$$(PATH))$(ORIG_SHELL) -x' +endif + +# Variables of general utility. +WLAN_Perl := perl +WLAN_Python := python +WLAN_WINPFX ?= Z: + +# These macros are used to stash an extra copy of generated source files, +# such that when a source release is made those files can be reconstituted +# from the stash during builds. Required if the generating tools or inputs +# are not shipped. +define wlan_copy_to_gen + $(if $(WLAN_COPY_GEN),&& mkdir -p $(subst $(abspath $2),$(abspath $2/$(WLAN_GEN_BASEDIR)),$(dir $(abspath $1))) && \ + cp -pv $1 $(subst $(abspath $2),$(abspath $2/$(WLAN_GEN_BASEDIR)),$(abspath $1).GEN)) +endef + +################################################################ +# CLM function; generates a rule to run ClmCompiler iff the XML exists. +# USAGE: $(call WLAN_GenClmCompilerRule,target-dir,src-base[,flags[,ext]]) +# This macro uses GNU make's eval function to generate an +# explicit rule to generate a particular CLM data file each time +# it's called. Make variables which should be evaluated during eval +# processing get one $, those which must defer till "runtime" get $$. +# The CLM "base flags" are the default minimal set, the "ext flags" +# are those which must be present for all release builds. +# The "clm_compiled" phony target is provided for makefiles which need +# to defer some other processing until CLM data is ready, and "clm_clean" +# and "CLM_DATA_FILES" make it easier for internal client makefiles to +# clean up CLM data (externally, this is treated as source and not removed). +# The outermost conditional allows this rule to become a no-op +# in external settings where there is no XML input file while allowing +# it to turn back on automatically if an XML file is provided. +# A vpath is used to find the XML input because this file is not allowed +# to be present in external builds. Use of vpath allows it to be "poached" +# from the internal build as necessary. +# There are a few ways to set ClmCompiler flags: passing them as the $3 +# parameter (preferred) or by overriding CLMCOMPDEFFLAGS. Additionally, +# when the make variable CLM_TYPE is defined it points to a config file +# for the compiler. The CLMCOMPEXTFLAGS variable contains "external flags" +# which must be present for all external builds. It can be forced to "" for +# debug builds. +# Note: the .c file is listed with and without a path due to the way the +# Linux kernel Makefiles generate .depend data. +# The undocumented $5 parameter has been used for dongle testing +# against variant XML but its semantics are subject to change. +CLMCOMPDEFFLAGS ?= --region '\#a/0' --region '\#r/0' --full_set +CLMCOMPEXTFLAGS := --obfuscate +define WLAN_GenClmCompilerRule +$(eval\ +.PHONY: clm_compiled clm_clean +vpath wlc_clm_data$4.c $1 $$(abspath $1) +ifneq (,$(wildcard $(addsuffix /wl/clm/private/wlc_clm_data.xml,$2 $2/../../src $2/../../../src))) + vpath wlc_clm_data.xml $(wildcard $(addsuffix /wl/clm/private,$5 $2 $2/../../src $2/../../../src)) + vpath %.clm $(addsuffix /wl/clm/types,$2 $2/../../src $2/../../../src) + $$(sort $1/wlc_clm_data$4.c ./wlc_clm_data$4.c): \ + wlc_clm_data.xml $2/wl/clm/include/wlc_clm_data.h $$(wildcard $2/wl/clm/bin/ClmCompiler.py) $$(if $$(CLM_TYPE),$$(CLM_TYPE).clm) ; \ + $$(strip $$(abspath $$(<D)/../../../tools/build/ClmCompiler) \ + $$(if $$(CLM_TYPE),--config_file $$(lastword $$^) $3,$$(if $3,$3,$$(CLMCOMPDEFFLAGS))) \ + $(CLMCOMPEXTFLAGS) $$< $$@ $$(call wlan_copy_to_gen,$$@,$2)) +else + vpath %.GEN $(subst $(abspath $2),$(abspath $2/$(WLAN_GEN_BASEDIR)),$1) $(sort $(patsubst %/,%,$(dir $(wildcard $(subst $(abspath $2),$(abspath $2/$(WLAN_GEN_BASEDIR)),$(dir $1))*/*.GEN)))) + $1/%: %.GEN ; cp -pv $$< $$@ +endif + clm_compiled: $1/wlc_clm_data$4.c + clm_clean:: ; $$(RM) $1/wlc_clm_data$4.c + CLM_DATA_FILES += $1/wlc_clm_data$4.c +) +endef + +################################################################ + +endif # _WLAN_COMMON_MK
diff --git a/src/shared/bcm_app_utils.c b/src/shared/bcm_app_utils.c new file mode 100644 index 0000000..430e6ea --- /dev/null +++ b/src/shared/bcm_app_utils.c
@@ -0,0 +1,229 @@ +/* + * Misc utility routines used by kernel or app-level. + * Contents are wifi-specific, used by any kernel or app-level + * software that might want wifi things as it grows. + * + * $Copyright Open Broadcom Corporation$ + * $Id: bcm_app_utils.c 315295 2012-02-16 06:55:23Z $ + */ + +#include <typedefs.h> + +#ifdef BCMDRIVER +#include <osl.h> +#include <bcmutils.h> +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#else /* BCMDRIVER */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#ifndef ASSERT +#define ASSERT(exp) +#endif +#endif /* BCMDRIVER */ +#include <bcmwifi_channels.h> + +#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) +#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ +#endif + +#include <bcmutils.h> +#include <wlioctl.h> + +cca_congest_channel_req_t * +cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg, + bool percent); + +int +cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer); + +/* Take an array of measurments representing a single channel over time and return + a summary. Currently implemented as a simple average but could easily evolve + into more cpomplex alogrithms. +*/ +cca_congest_channel_req_t * +cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg, bool percent) +{ + int sec; + cca_congest_t totals; + + totals.duration = 0; + totals.congest_ibss = 0; + totals.congest_obss = 0; + totals.interference = 0; + avg->num_secs = 0; + + for (sec = 0; sec < input->num_secs; sec++) { + if (input->secs[sec].duration) { + totals.duration += input->secs[sec].duration; + totals.congest_ibss += input->secs[sec].congest_ibss; + totals.congest_obss += input->secs[sec].congest_obss; + totals.interference += input->secs[sec].interference; + avg->num_secs++; + } + } + avg->chanspec = input->chanspec; + + if (!avg->num_secs || !totals.duration) + return (avg); + + if (percent) { + avg->secs[0].duration = totals.duration / avg->num_secs; + avg->secs[0].congest_ibss = totals.congest_ibss * 100/totals.duration; + avg->secs[0].congest_obss = totals.congest_obss * 100/totals.duration; + avg->secs[0].interference = totals.interference * 100/totals.duration; + } else { + avg->secs[0].duration = totals.duration / avg->num_secs; + avg->secs[0].congest_ibss = totals.congest_ibss / avg->num_secs; + avg->secs[0].congest_obss = totals.congest_obss / avg->num_secs; + avg->secs[0].interference = totals.interference / avg->num_secs; + } + + return (avg); +} + +static void +cca_info(uint8 *bitmap, int num_bits, int *left, int *bit_pos) +{ + int i; + for (*left = 0, i = 0; i < num_bits; i++) { + if (isset(bitmap, i)) { + (*left)++; + *bit_pos = i; + } + } +} + +static uint8 +spec_to_chan(chanspec_t chspec) +{ + uint8 center_ch, edge, primary, sb; + + center_ch = CHSPEC_CHANNEL(chspec); + + if (CHSPEC_IS20(chspec)) { + return center_ch; + } else { + /* the lower edge of the wide channel is half the bw from + * the center channel. + */ + if (CHSPEC_IS40(chspec)) { + edge = center_ch - CH_20MHZ_APART; + } else { + /* must be 80MHz (until we support more) */ + ASSERT(CHSPEC_IS80(chspec)); + edge = center_ch - CH_40MHZ_APART; + } + + /* find the channel number of the lowest 20MHz primary channel */ + primary = edge + CH_10MHZ_APART; + + /* select the actual subband */ + sb = (chspec & WL_CHANSPEC_CTL_SB_MASK) >> WL_CHANSPEC_CTL_SB_SHIFT; + primary = primary + sb * CH_20MHZ_APART; + + return primary; + } +} + +#define CCA_THRESH_MILLI 14 +#define CCA_THRESH_INTERFERE 6 + +/* + Take an array of measumrements representing summaries of different channels. + Return a recomended channel. + Interference is evil, get rid of that first. + Then hunt for lowest Other bss traffic. + Don't forget that channels with low duration times may not have accurate readings. + For the moment, do not overwrite input array. +*/ +int +cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer) +{ + uint8 bitmap[CEIL(MAX_CCA_CHANNELS, NBBY)]; /* 38 Max channels needs 5 bytes = 40 */ + int i, left, winner; + uint32 min_obss = 1 << 30; + + ASSERT(num_chans < MAX_CCA_CHANNELS); + for (i = 0; i < (int)sizeof(bitmap); i++) + bitmap[i] = 0; + + /* Initially, all channels are up for consideration */ + for (i = 0; i < num_chans; i++) { + if (input[i]->chanspec) + setbit(bitmap, i); + } + cca_info(bitmap, num_chans, &left, &i); + if (!left) + return CCA_ERRNO_TOO_FEW; + + /* Filter for 2.4 GHz Band */ + if (flags & CCA_FLAG_2G_ONLY) { + for (i = 0; i < num_chans; i++) { + if (!CHSPEC_IS2G(input[i]->chanspec)) + clrbit(bitmap, i); + } + } + cca_info(bitmap, num_chans, &left, &i); + if (!left) + return CCA_ERRNO_BAND; + + /* Filter for 5 GHz Band */ + if (flags & CCA_FLAG_5G_ONLY) { + for (i = 0; i < num_chans; i++) { + if (!CHSPEC_IS5G(input[i]->chanspec)) + clrbit(bitmap, i); + } + } + cca_info(bitmap, num_chans, &left, &i); + if (!left) + return CCA_ERRNO_BAND; + + /* Filter for Duration */ + if (!(flags & CCA_FLAG_IGNORE_DURATION)) { + for (i = 0; i < num_chans; i++) { + if (input[i]->secs[0].duration < CCA_THRESH_MILLI) + clrbit(bitmap, i); + } + } + cca_info(bitmap, num_chans, &left, &i); + if (!left) + return CCA_ERRNO_DURATION; + + /* Filter for 1 6 11 on 2.4 Band */ + if (flags & CCA_FLAGS_PREFER_1_6_11) { + int tmp_channel = spec_to_chan(input[i]->chanspec); + int is2g = CHSPEC_IS2G(input[i]->chanspec); + for (i = 0; i < num_chans; i++) { + if (is2g && tmp_channel != 1 && tmp_channel != 6 && tmp_channel != 11) + clrbit(bitmap, i); + } + } + cca_info(bitmap, num_chans, &left, &i); + if (!left) + return CCA_ERRNO_PREF_CHAN; + + /* Toss high interference interference */ + if (!(flags & CCA_FLAG_IGNORE_INTERFER)) { + for (i = 0; i < num_chans; i++) { + if (input[i]->secs[0].interference > CCA_THRESH_INTERFERE) + clrbit(bitmap, i); + } + cca_info(bitmap, num_chans, &left, &i); + if (!left) + return CCA_ERRNO_INTERFER; + } + + /* Now find lowest obss */ + winner = 0; + for (i = 0; i < num_chans; i++) { + if (isset(bitmap, i) && input[i]->secs[0].congest_obss < min_obss) { + winner = i; + min_obss = input[i]->secs[0].congest_obss; + } + } + *answer = input[winner]->chanspec; + + return 0; +}
diff --git a/src/shared/bcmutils.c b/src/shared/bcmutils.c new file mode 100644 index 0000000..524bdb6 --- /dev/null +++ b/src/shared/bcmutils.c
@@ -0,0 +1,3102 @@ +/* + * Driver O/S-independent utility routines + * + * $Copyright Open Broadcom Corporation$ + * $Id: bcmutils.c 461404 2014-03-12 01:59:36Z $ + */ + +#include <bcm_cfg.h> +#include <typedefs.h> +#include <bcmdefs.h> +#include <stdarg.h> +#ifdef BCMDRIVER + +#include <osl.h> +#include <bcmutils.h> +#if defined(BCMNVRAM) +#include <siutils.h> +#include <bcmnvram.h> +#endif + +#else /* !BCMDRIVER */ + +#include <stdio.h> +#include <string.h> +#include <bcmutils.h> + +#if defined(BCMEXTSUP) +#include <bcm_osl.h> +#endif + +#ifndef ASSERT +#define ASSERT(exp) +#endif + +#endif /* !BCMDRIVER */ + +#include <bcmendian.h> +#include <bcmdevs.h> +#include <proto/ethernet.h> +#include <proto/vlan.h> +#include <proto/bcmip.h> +#include <proto/802.1d.h> +#include <proto/802.11.h> + + +void *_bcmutils_dummy_fn = NULL; + + +#ifdef CUSTOM_DSCP_TO_PRIO_MAPPING +#define CUST_IPV4_TOS_PREC_MASK 0x3F +#define DCSP_MAX_VALUE 64 +extern uint dhd_dscpmap_enable; +/* 0:BE,1:BK,2:RESV(BK):,3:EE,:4:CL,5:VI,6:VO,7:NC */ +int dscp2priomap[DCSP_MAX_VALUE]= +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0 +}; +#endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */ + +#ifdef BCMDRIVER + + + +/* copy a pkt buffer chain into a buffer */ +uint +pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) +{ + uint n, ret = 0; + + if (len < 0) + len = 4096; /* "infinite" */ + + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= PKTLEN(osh, p); + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(PKTDATA(osh, p) + offset, buf, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} + +/* copy a buffer into a pkt buffer chain */ +uint +pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) +{ + uint n, ret = 0; + + + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= PKTLEN(osh, p); + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(buf, PKTDATA(osh, p) + offset, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} + + + +/* return total length of buffer chain */ +uint BCMFASTPATH +pkttotlen(osl_t *osh, void *p) +{ + uint total; + int len; + + total = 0; + for (; p; p = PKTNEXT(osh, p)) { + len = PKTLEN(osh, p); + total += len; +#ifdef BCMLFRAG + if (BCMLFRAG_ENAB()) { + if (PKTISFRAG(osh, p)) { + total += PKTFRAGTOTLEN(osh, p); + } + } +#endif + } + + return (total); +} + +/* return the last buffer of chained pkt */ +void * +pktlast(osl_t *osh, void *p) +{ + for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) + ; + + return (p); +} + +/* count segments of a chained packet */ +uint BCMFASTPATH +pktsegcnt(osl_t *osh, void *p) +{ + uint cnt; + + for (cnt = 0; p; p = PKTNEXT(osh, p)) { + cnt++; +#ifdef BCMLFRAG + if (BCMLFRAG_ENAB()) { + if (PKTISFRAG(osh, p)) { + cnt += PKTFRAGTOTNUM(osh, p); + } + } +#endif + } + + return cnt; +} + + +/* count segments of a chained packet */ +uint BCMFASTPATH +pktsegcnt_war(osl_t *osh, void *p) +{ + uint cnt; + uint8 *pktdata; + uint len, remain, align64; + + for (cnt = 0; p; p = PKTNEXT(osh, p)) { + cnt++; + len = PKTLEN(osh, p); + if (len > 128) { + pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ + /* Check for page boundary straddle (2048B) */ + if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) + cnt++; + + align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ + align64 = (64 - align64) & 0x3f; + len -= align64; /* bytes from aligned 64B to end */ + /* if aligned to 128B, check for MOD 128 between 1 to 4B */ + remain = len % 128; + if (remain > 0 && remain <= 4) + cnt++; /* add extra seg */ + } + } + + return cnt; +} + +uint8 * BCMFASTPATH +pktdataoffset(osl_t *osh, void *p, uint offset) +{ + uint total = pkttotlen(osh, p); + uint pkt_off = 0, len = 0; + uint8 *pdata = (uint8 *) PKTDATA(osh, p); + + if (offset > total) + return NULL; + + for (; p; p = PKTNEXT(osh, p)) { + pdata = (uint8 *) PKTDATA(osh, p); + pkt_off = offset - len; + len += PKTLEN(osh, p); + if (len > offset) + break; + } + return (uint8*) (pdata+pkt_off); +} + + +/* given a offset in pdata, find the pkt seg hdr */ +void * +pktoffset(osl_t *osh, void *p, uint offset) +{ + uint total = pkttotlen(osh, p); + uint len = 0; + + if (offset > total) + return NULL; + + for (; p; p = PKTNEXT(osh, p)) { + len += PKTLEN(osh, p); + if (len > offset) + break; + } + return p; +} + +/* + * osl multiple-precedence packet queue + * hi_prec is always >= the number of the highest non-empty precedence + */ +void * BCMFASTPATH +pktq_penq(struct pktq *pq, int prec, void *p) +{ + struct pktq_prec *q; + + ASSERT(prec >= 0 && prec < pq->num_prec); + /* queueing chains not allowed and no segmented SKB (Kernel-3.18.y) */ + ASSERT(!((PKTLINK(p) != NULL) && (PKTLINK(p) != p))); + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + PKTSETLINK(p, NULL); + if (q->head) + PKTSETLINK(q->tail, p); + else + q->head = p; + + q->tail = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + return p; +} + +void * BCMFASTPATH +pktq_penq_head(struct pktq *pq, int prec, void *p) +{ + struct pktq_prec *q; + + ASSERT(prec >= 0 && prec < pq->num_prec); + /* queueing chains not allowed and no segmented SKB (Kernel-3.18.y) */ + ASSERT(!((PKTLINK(p) != NULL) && (PKTLINK(p) != p))); + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + PKTSETLINK(p, NULL); + if (q->head == NULL) + q->tail = p; + + PKTSETLINK(p, q->head); + q->head = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + return p; +} + +void * BCMFASTPATH +pktq_pdeq(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if (prev_p == NULL) + return NULL; + + if ((p = PKTLINK(prev_p)) == NULL) + return NULL; + + q->len--; + + pq->len--; + + PKTSETLINK(prev_p, PKTLINK(p)); + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg) +{ + struct pktq_prec *q; + void *p, *prev = NULL; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + p = q->head; + + while (p) { + if (fn == NULL || (*fn)(p, arg)) { + break; + } else { + prev = p; + p = PKTLINK(p); + } + } + if (p == NULL) + return NULL; + + if (prev == NULL) { + if ((q->head = PKTLINK(p)) == NULL) { + q->tail = NULL; + } + } else { + PKTSETLINK(prev, PKTLINK(p)); + if (q->tail == p) { + q->tail = prev; + } + } + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_pdeq_tail(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + void *p, *prev; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = PKTLINK(p)) + prev = p; + + if (prev) + PKTSETLINK(prev, NULL); + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + return p; +} + +void +pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) +{ + struct pktq_prec *q; + void *p, *prev = NULL; + + q = &pq->q[prec]; + p = q->head; + while (p) { + if (fn == NULL || (*fn)(p, arg)) { + bool head = (p == q->head); + if (head) + q->head = PKTLINK(p); + else + PKTSETLINK(prev, PKTLINK(p)); + PKTSETLINK(p, NULL); + PKTFREE(osh, p, dir); + q->len--; + pq->len--; + p = (head ? q->head : PKTLINK(prev)); + } else { + prev = p; + p = PKTLINK(p); + } + } + + if (q->head == NULL) { + ASSERT(q->len == 0); + q->tail = NULL; + } +} + +bool BCMFASTPATH +pktq_pdel(struct pktq *pq, void *pktbuf, int prec) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + if (!pktbuf) + return FALSE; + + q = &pq->q[prec]; + + if (q->head == pktbuf) { + if ((q->head = PKTLINK(pktbuf)) == NULL) + q->tail = NULL; + } else { + for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) + ; + if (p == NULL) + return FALSE; + + PKTSETLINK(p, PKTLINK(pktbuf)); + if (q->tail == pktbuf) + q->tail = p; + } + + q->len--; + pq->len--; + PKTSETLINK(pktbuf, NULL); + return TRUE; +} + +void +pktq_init(struct pktq *pq, int num_prec, int max_len) +{ + int prec; + + ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); + + /* pq is variable size; only zero out what's requested */ + bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); + + pq->num_prec = (uint16)num_prec; + + pq->max = (uint16)max_len; + + for (prec = 0; prec < num_prec; prec++) + pq->q[prec].max = pq->max; +} + +void +pktq_set_max_plen(struct pktq *pq, int prec, int max_len) +{ + ASSERT(prec >= 0 && prec < pq->num_prec); + + if (prec < pq->num_prec) + pq->q[prec].max = (uint16)max_len; +} + +void * BCMFASTPATH +pktq_deq(struct pktq *pq, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + if (prec_out) + *prec_out = prec; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH +pktq_deq_tail(struct pktq *pq, int *prec_out) +{ + struct pktq_prec *q; + void *p, *prev; + int prec; + + if (pq->len == 0) + return NULL; + + for (prec = 0; prec < pq->hi_prec; prec++) + if (pq->q[prec].head) + break; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = PKTLINK(p)) + prev = p; + + if (prev) + PKTSETLINK(prev, NULL); + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + if (prec_out) + *prec_out = prec; + + PKTSETLINK(p, NULL); + + return p; +} + +void * +pktq_peek(struct pktq *pq, int *prec_out) +{ + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + if (prec_out) + *prec_out = prec; + + return (pq->q[prec].head); +} + +void * +pktq_peek_tail(struct pktq *pq, int *prec_out) +{ + int prec; + + if (pq->len == 0) + return NULL; + + for (prec = 0; prec < pq->hi_prec; prec++) + if (pq->q[prec].head) + break; + + if (prec_out) + *prec_out = prec; + + return (pq->q[prec].tail); +} + +void +pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) +{ + int prec; + + /* Optimize flush, if pktq len = 0, just return. + * pktq len of 0 means pktq's prec q's are all empty. + */ + if (pq->len == 0) { + return; + } + + for (prec = 0; prec < pq->num_prec; prec++) + pktq_pflush(osh, pq, prec, dir, fn, arg); + if (fn == NULL) + ASSERT(pq->len == 0); +} + +/* Return sum of lengths of a specific set of precedences */ +int +pktq_mlen(struct pktq *pq, uint prec_bmp) +{ + int prec, len; + + len = 0; + + for (prec = 0; prec <= pq->hi_prec; prec++) + if (prec_bmp & (1 << prec)) + len += pq->q[prec].len; + + return len; +} + +/* Priority peek from a specific set of precedences */ +void * BCMFASTPATH +pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + { + return NULL; + } + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) + if (prec-- == 0) + return NULL; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if (prec_out) + *prec_out = prec; + + return p; +} +/* Priority dequeue from a specific set of precedences */ +void * BCMFASTPATH +pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) + if (prec-- == 0) + return NULL; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + if (prec_out) + *prec_out = prec; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +#endif /* BCMDRIVER */ + +#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) +const unsigned char bcm_ctype[] = { + + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ + _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, + _BCM_C, /* 8-15 */ + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ + _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ + _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ + _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ + _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ + _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, + _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ + _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, + _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ + _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ + _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ +}; + +ulong +BCMROMFN(bcm_strtoul)(const char *cp, char **endp, uint base) +{ + ulong result, last_result = 0, value; + bool minus; + + minus = FALSE; + + while (bcm_isspace(*cp)) + cp++; + + if (cp[0] == '+') + cp++; + else if (cp[0] == '-') { + minus = TRUE; + cp++; + } + + if (base == 0) { + if (cp[0] == '0') { + if ((cp[1] == 'x') || (cp[1] == 'X')) { + base = 16; + cp = &cp[2]; + } else { + base = 8; + cp = &cp[1]; + } + } else + base = 10; + } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { + cp = &cp[2]; + } + + result = 0; + + while (bcm_isxdigit(*cp) && + (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { + result = result*base + value; + /* Detected overflow */ + if (result < last_result && !minus) + return (ulong)-1; + last_result = result; + cp++; + } + + if (minus) + result = (ulong)(-(long)result); + + if (endp) + *endp = DISCARD_QUAL(cp, char); + + return (result); +} + +int +BCMROMFN(bcm_atoi)(const char *s) +{ + return (int)bcm_strtoul(s, NULL, 10); +} + +/* return pointer to location of substring 'needle' in 'haystack' */ +char * +BCMROMFN(bcmstrstr)(const char *haystack, const char *needle) +{ + int len, nlen; + int i; + + if ((haystack == NULL) || (needle == NULL)) + return DISCARD_QUAL(haystack, char); + + nlen = strlen(needle); + len = strlen(haystack) - nlen + 1; + + for (i = 0; i < len; i++) + if (memcmp(needle, &haystack[i], nlen) == 0) + return DISCARD_QUAL(&haystack[i], char); + return (NULL); +} + +char * +BCMROMFN(bcmstrcat)(char *dest, const char *src) +{ + char *p; + + p = dest + strlen(dest); + + while ((*p++ = *src++) != '\0') + ; + + return (dest); +} + +char * +BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size) +{ + char *endp; + char *p; + + p = dest + strlen(dest); + endp = p + size; + + while (p != endp && (*p++ = *src++) != '\0') + ; + + return (dest); +} + + +/**************************************************************************** +* Function: bcmstrtok +* +* Purpose: +* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), +* but allows strToken() to be used by different strings or callers at the same +* time. Each call modifies '*string' by substituting a NULL character for the +* first delimiter that is encountered, and updates 'string' to point to the char +* after the delimiter. Leading delimiters are skipped. +* +* Parameters: +* string (mod) Ptr to string ptr, updated by token. +* delimiters (in) Set of delimiter characters. +* tokdelim (out) Character that delimits the returned token. (May +* be set to NULL if token delimiter is not required). +* +* Returns: Pointer to the next token found. NULL when no more tokens are found. +***************************************************************************** +*/ +char * +bcmstrtok(char **string, const char *delimiters, char *tokdelim) +{ + unsigned char *str; + unsigned long map[8]; + int count; + char *nextoken; + + if (tokdelim != NULL) { + /* Prime the token delimiter */ + *tokdelim = '\0'; + } + + /* Clear control map */ + for (count = 0; count < 8; count++) { + map[count] = 0; + } + + /* Set bits in delimiter table */ + do { + map[*delimiters >> 5] |= (1 << (*delimiters & 31)); + } + while (*delimiters++); + + str = (unsigned char*)*string; + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets str to point to the terminal + * null (*str == '\0') + */ + while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { + str++; + } + + nextoken = (char*)str; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. + */ + for (; *str; str++) { + if (map[*str >> 5] & (1 << (*str & 31))) { + if (tokdelim != NULL) { + *tokdelim = *str; + } + + *str++ = '\0'; + break; + } + } + + *string = (char*)str; + + /* Determine if a token has been found. */ + if (nextoken == (char *) str) { + return NULL; + } + else { + return nextoken; + } +} + + +#define xToLower(C) \ + ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) + + +/**************************************************************************** +* Function: bcmstricmp +* +* Purpose: Compare to strings case insensitively. +* +* Parameters: s1 (in) First string to compare. +* s2 (in) Second string to compare. +* +* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if +* t1 > t2, when ignoring case sensitivity. +***************************************************************************** +*/ +int +bcmstricmp(const char *s1, const char *s2) +{ + char dc, sc; + + while (*s2 && *s1) { + dc = xToLower(*s1); + sc = xToLower(*s2); + if (dc < sc) return -1; + if (dc > sc) return 1; + s1++; + s2++; + } + + if (*s1 && !*s2) return 1; + if (!*s1 && *s2) return -1; + return 0; +} + + +/**************************************************************************** +* Function: bcmstrnicmp +* +* Purpose: Compare to strings case insensitively, upto a max of 'cnt' +* characters. +* +* Parameters: s1 (in) First string to compare. +* s2 (in) Second string to compare. +* cnt (in) Max characters to compare. +* +* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if +* t1 > t2, when ignoring case sensitivity. +***************************************************************************** +*/ +int +bcmstrnicmp(const char* s1, const char* s2, int cnt) +{ + char dc, sc; + + while (*s2 && *s1 && cnt) { + dc = xToLower(*s1); + sc = xToLower(*s2); + if (dc < sc) return -1; + if (dc > sc) return 1; + s1++; + s2++; + cnt--; + } + + if (!cnt) return 0; + if (*s1 && !*s2) return 1; + if (!*s1 && *s2) return -1; + return 0; +} + +/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ +int +BCMROMFN(bcm_ether_atoe)(const char *p, struct ether_addr *ea) +{ + int i = 0; + char *ep; + + for (;;) { + ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); + p = ep; + if (!*p++ || i == 6) + break; + } + + return (i == 6); +} + +int +BCMROMFN(bcm_atoipv4)(const char *p, struct ipv4_addr *ip) +{ + + int i = 0; + char *c; + for (;;) { + ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0); + if (*c++ != '.' || i == IPV4_ADDR_LEN) + break; + p = c; + } + return (i == IPV4_ADDR_LEN); +} +#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ + + +#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) +/* registry routine buffer preparation utility functions: + * parameter order is like strncpy, but returns count + * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) + */ +ulong +wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) +{ + ulong copyct = 1; + ushort i; + + if (abuflen == 0) + return 0; + + /* wbuflen is in bytes */ + wbuflen /= sizeof(ushort); + + for (i = 0; i < wbuflen; ++i) { + if (--abuflen == 0) + break; + *abuf++ = (char) *wbuf++; + ++copyct; + } + *abuf = '\0'; + + return copyct; +} +#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ + +char * +bcm_ether_ntoa(const struct ether_addr *ea, char *buf) +{ + static const char hex[] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + const uint8 *octet = ea->octet; + char *p = buf; + int i; + + for (i = 0; i < 6; i++, octet++) { + *p++ = hex[(*octet >> 4) & 0xf]; + *p++ = hex[*octet & 0xf]; + *p++ = ':'; + } + + *(p-1) = '\0'; + + return (buf); +} + +char * +bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) +{ + snprintf(buf, 16, "%d.%d.%d.%d", + ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); + return (buf); +} + +char * +bcm_ipv6_ntoa(void *ipv6, char *buf) +{ + /* Implementing RFC 5952 Sections 4 + 5 */ + /* Not thoroughly tested */ + uint16 tmp[8]; + uint16 *a = &tmp[0]; + char *p = buf; + int i, i_max = -1, cnt = 0, cnt_max = 1; + uint8 *a4 = NULL; + memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if (a[i]) { + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + cnt = 0; + } else + cnt++; + } + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + if (i_max == 0 && + /* IPv4-translated: ::ffff:0:a.b.c.d */ + ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || + /* IPv4-mapped: ::ffff:a.b.c.d */ + (cnt_max == 5 && a[5] == 0xffff))) + a4 = (uint8*) (a + 6); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if ((uint8*) (a + i) == a4) { + snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); + break; + } else if (i == i_max) { + *p++ = ':'; + i += cnt_max - 1; + p[0] = ':'; + p[1] = '\0'; + } else { + if (i) + *p++ = ':'; + p += snprintf(p, 8, "%x", ntoh16(a[i])); + } + } + + return buf; +} +#ifdef BCMDRIVER + +void +bcm_mdelay(uint ms) +{ + uint i; + + for (i = 0; i < ms; i++) { + OSL_DELAY(1000); + } +} + + + + + +#if defined(DHD_DEBUG) +/* pretty hex print a pkt buffer chain */ +void +prpkt(const char *msg, osl_t *osh, void *p0) +{ + void *p; + + if (msg && (msg[0] != '\0')) + printf("%s:\n", msg); + + for (p = p0; p; p = PKTNEXT(osh, p)) + prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); +} +#endif + +/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. + * Also updates the inplace vlan tag if requested. + * For debugging, it returns an indication of what it did. + */ +uint BCMFASTPATH +pktsetprio(void *pkt, bool update_vtag) +{ + struct ether_header *eh; + struct ethervlan_header *evh; + uint8 *pktdata; + int priority = 0; + int rc = 0; + + pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); + ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); + + eh = (struct ether_header *) pktdata; + + if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { + uint16 vlan_tag; + int vlan_prio, dscp_prio = 0; + + evh = (struct ethervlan_header *)eh; + + vlan_tag = ntoh16(evh->vlan_tag); + vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; + + if (evh->ether_type == hton16(ETHER_TYPE_IP)) { + uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); + uint8 tos_tc = IP_TOS46(ip_body); + dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + } + + /* DSCP priority gets precedence over 802.1P (vlan tag) */ + if (dscp_prio != 0) { + priority = dscp_prio; + rc |= PKTPRIO_VDSCP; + } else { + priority = vlan_prio; + rc |= PKTPRIO_VLAN; + } + /* + * If the DSCP priority is not the same as the VLAN priority, + * then overwrite the priority field in the vlan tag, with the + * DSCP priority value. This is required for Linux APs because + * the VLAN driver on Linux, overwrites the skb->priority field + * with the priority value in the vlan tag + */ + if (update_vtag && (priority != vlan_prio)) { + vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); + vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; + evh->vlan_tag = hton16(vlan_tag); + rc |= PKTPRIO_UPD; + } + } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) { + uint8 *ip_body = pktdata + sizeof(struct ether_header); + uint8 tos_tc = IP_TOS46(ip_body); + uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; + switch (dscp) { + case DSCP_EF: + priority = PRIO_8021D_VO; + break; + case DSCP_AF31: + case DSCP_AF32: + case DSCP_AF33: + priority = PRIO_8021D_CL; + break; + case DSCP_AF21: + case DSCP_AF22: + case DSCP_AF23: + case DSCP_AF11: + case DSCP_AF12: + case DSCP_AF13: + priority = PRIO_8021D_EE; + break; + default: +#ifndef CUSTOM_DSCP_TO_PRIO_MAPPING + priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); +#else + if (dhd_dscpmap_enable) { + priority = (int)dscp2priomap[((tos_tc >> IPV4_TOS_DSCP_SHIFT) + & CUST_IPV4_TOS_PREC_MASK)]; + } + else { + priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + } +#endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */ + break; + } + + rc |= PKTPRIO_DSCP; + } + + ASSERT(priority >= 0 && priority <= MAXPRIO); + PKTSETPRIO(pkt, priority); + return (rc | priority); +} + + +static char bcm_undeferrstr[32]; +static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; + +/* Convert the error codes into related error strings */ +const char * +bcmerrorstr(int bcmerror) +{ + /* check if someone added a bcmerror code but forgot to add errorstring */ + ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); + + if (bcmerror > 0 || bcmerror < BCME_LAST) { + snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); + return bcm_undeferrstr; + } + + ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); + + return bcmerrorstrtable[-bcmerror]; +} + + + +/* iovar table lookup */ +const bcm_iovar_t* +bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) +{ + const bcm_iovar_t *vi; + const char *lookup_name; + + /* skip any ':' delimited option prefixes */ + lookup_name = strrchr(name, ':'); + if (lookup_name != NULL) + lookup_name++; + else + lookup_name = name; + + ASSERT(table != NULL); + + for (vi = table; vi->name; vi++) { + if (!strcmp(vi->name, lookup_name)) + return vi; + } + /* ran to end of table */ + + return NULL; /* var name not found */ +} + +int +bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) +{ + int bcmerror = 0; + + /* length check on io buf */ + switch (vi->type) { + case IOVT_BOOL: + case IOVT_INT8: + case IOVT_INT16: + case IOVT_INT32: + case IOVT_UINT8: + case IOVT_UINT16: + case IOVT_UINT32: + /* all integers are int32 sized args at the ioctl interface */ + if (len < (int)sizeof(int)) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_BUFFER: + /* buffer must meet minimum length requirement */ + if (len < vi->minlen) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_VOID: + if (!set) { + /* Cannot return nil... */ + bcmerror = BCME_UNSUPPORTED; + } else if (len) { + /* Set is an action w/o parameters */ + bcmerror = BCME_BUFTOOLONG; + } + break; + + default: + /* unknown type for length check in iovar info */ + ASSERT(0); + bcmerror = BCME_UNSUPPORTED; + } + + return bcmerror; +} + +#endif /* BCMDRIVER */ + + +uint8 * +bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst) +{ + uint8 *new_dst = dst; + bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst; + + /* dst buffer should always be valid */ + ASSERT(dst); + + /* data len must be within valid range */ + ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)); + + /* source data buffer pointer should be valid, unless datalen is 0 + * meaning no data with this TLV + */ + ASSERT((data != NULL) || (datalen == 0)); + + /* only do work if the inputs are valid + * - must have a dst to write to AND + * - datalen must be within range AND + * - the source data pointer must be non-NULL if datalen is non-zero + * (this last condition detects datalen > 0 with a NULL data pointer) + */ + if ((dst != NULL) && + ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) && + ((data != NULL) || (datalen == 0))) { + + /* write type, len fields */ + dst_tlv->id = (uint8)type; + dst_tlv->len = (uint8)datalen; + + /* if data is present, copy to the output buffer and update + * pointer to output buffer + */ + if (datalen > 0) { + + memcpy(dst_tlv->data, data, datalen); + } + + /* update the output destination poitner to point past + * the TLV written + */ + new_dst = dst + BCM_TLV_HDR_SIZE + datalen; + } + + return (new_dst); +} + +uint8 * +bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen) +{ + uint8 *new_dst = dst; + + if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) { + + /* if len + tlv hdr len is more than destlen, don't do anything + * just return the buffer untouched + */ + if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) { + + new_dst = bcm_write_tlv(type, data, datalen, dst); + } + } + + return (new_dst); +} + +uint8 * +bcm_copy_tlv(const void *src, uint8 *dst) +{ + uint8 *new_dst = dst; + const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; + uint totlen; + + ASSERT(dst && src); + if (dst && src) { + + totlen = BCM_TLV_HDR_SIZE + src_tlv->len; + memcpy(dst, src_tlv, totlen); + new_dst = dst + totlen; + } + + return (new_dst); +} + + +uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen) +{ + uint8 *new_dst = dst; + const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; + + ASSERT(src); + if (src) { + if (bcm_valid_tlv(src_tlv, dst_maxlen)) { + new_dst = bcm_copy_tlv(src, dst); + } + } + + return (new_dst); +} + + +#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) +/******************************************************************************* + * crc8 + * + * Computes a crc8 over the input data using the polynomial: + * + * x^8 + x^7 +x^6 + x^4 + x^2 + 1 + * + * The caller provides the initial value (either CRC8_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When checking, a final + * return value of CRC8_GOOD_VALUE indicates a valid CRC. + * + * Reference: Dallas Semiconductor Application Note 27 + * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", + * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., + * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt + * + * **************************************************************************** + */ + +static const uint8 crc8_table[256] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F +}; + +#define CRC_INNER_LOOP(n, c, x) \ + (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] + +uint8 +BCMROMFN(hndcrc8)( + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint8 crc /* either CRC8_INIT_VALUE or previous return value */ +) +{ + /* hard code the crc loop instead of using CRC_INNER_LOOP macro + * to avoid the undefined and unnecessary (uint8 >> 8) operation. + */ + while (nbytes-- > 0) + crc = crc8_table[(crc ^ *pdata++) & 0xff]; + + return crc; +} + +/******************************************************************************* + * crc16 + * + * Computes a crc16 over the input data using the polynomial: + * + * x^16 + x^12 +x^5 + 1 + * + * The caller provides the initial value (either CRC16_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When checking, a final + * return value of CRC16_GOOD_VALUE indicates a valid CRC. + * + * Reference: Dallas Semiconductor Application Note 27 + * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", + * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., + * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt + * + * **************************************************************************** + */ + +static const uint16 crc16_table[256] = { + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, + 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, + 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, + 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, + 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, + 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, + 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, + 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, + 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, + 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, + 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, + 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, + 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, + 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, + 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, + 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, + 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, + 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, + 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, + 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, + 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, + 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, + 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, + 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, + 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, + 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, + 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, + 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, + 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, + 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 +}; + +uint16 +BCMROMFN(hndcrc16)( + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint16 crc /* either CRC16_INIT_VALUE or previous return value */ +) +{ + while (nbytes-- > 0) + CRC_INNER_LOOP(16, crc, *pdata++); + return crc; +} + +static const uint32 crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +/* + * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if + * accumulating over multiple pieces. + */ +uint32 +BCMROMFN(hndcrc32)(uint8 *pdata, uint nbytes, uint32 crc) +{ + uint8 *pend; + pend = pdata + nbytes; + while (pdata < pend) + CRC_INNER_LOOP(32, crc, *pdata++); + + return crc; +} + +#ifdef notdef +#define CLEN 1499 /* CRC Length */ +#define CBUFSIZ (CLEN+4) +#define CNBUFS 5 /* # of bufs */ + +void +testcrc32(void) +{ + uint j, k, l; + uint8 *buf; + uint len[CNBUFS]; + uint32 crcr; + uint32 crc32tv[CNBUFS] = + {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; + + ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); + + /* step through all possible alignments */ + for (l = 0; l <= 4; l++) { + for (j = 0; j < CNBUFS; j++) { + len[j] = CLEN; + for (k = 0; k < len[j]; k++) + *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; + } + + for (j = 0; j < CNBUFS; j++) { + crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); + ASSERT(crcr == crc32tv[j]); + } + } + + MFREE(buf, CBUFSIZ*CNBUFS); + return; +} +#endif /* notdef */ + +/* + * Advance from the current 1-byte tag/1-byte length/variable-length value + * triple, to the next, returning a pointer to the next. + * If the current or next TLV is invalid (does not fit in given buffer length), + * NULL is returned. + * *buflen is not modified if the TLV elt parameter is invalid, or is decremented + * by the TLV parameter's length if it is valid. + */ +bcm_tlv_t * +BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen) +{ + int len; + + /* validate current elt */ + if (!bcm_valid_tlv(elt, *buflen)) { + return NULL; + } + + /* advance to next elt */ + len = elt->len; + elt = (bcm_tlv_t*)(elt->data + len); + *buflen -= (TLV_HDR_LEN + len); + + /* validate next elt */ + if (!bcm_valid_tlv(elt, *buflen)) { + return NULL; + } + + return elt; +} + +/* + * Traverse a string of 1-byte tag/1-byte length/variable-length value + * triples, returning a pointer to the substring whose first element + * matches tag + */ +bcm_tlv_t * +BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key) +{ + bcm_tlv_t *elt; + int totlen; + + elt = (bcm_tlv_t*)buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + int len = elt->len; + + /* validate remaining totlen */ + if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { + + return (elt); + } + + elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + + return NULL; +} + +/* + * Traverse a string of 1-byte tag/1-byte length/variable-length value + * triples, returning a pointer to the substring whose first element + * matches tag. Stop parsing when we see an element whose ID is greater + * than the target key. + */ +bcm_tlv_t * +BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key) +{ + bcm_tlv_t *elt; + int totlen; + + elt = (bcm_tlv_t*)buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + uint id = elt->id; + int len = elt->len; + + /* Punt if we start seeing IDs > than target key */ + if (id > key) { + return (NULL); + } + + /* validate remaining totlen */ + if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { + return (elt); + } + + elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + return NULL; +} +#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ + +#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ + defined(DHD_DEBUG) +int +bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len) +{ + int i, slen = 0; + uint32 bit, mask; + const char *name; + mask = bd->mask; + if (len < 2 || !buf) + return 0; + + buf[0] = '\0'; + + for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { + bit = bd->bitfield[i].bit; + if ((flags & mask) == bit) { + if (len > (int)strlen(name)) { + slen = strlen(name); + strncpy(buf, name, slen+1); + } + break; + } + } + return slen; +} + +int +bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) +{ + int i; + char* p = buf; + char hexstr[16]; + int slen = 0, nlen = 0; + uint32 bit; + const char* name; + + if (len < 2 || !buf) + return 0; + + buf[0] = '\0'; + + for (i = 0; flags != 0; i++) { + bit = bd[i].bit; + name = bd[i].name; + if (bit == 0 && flags != 0) { + /* print any unnamed bits */ + snprintf(hexstr, 16, "0x%X", flags); + name = hexstr; + flags = 0; /* exit loop */ + } else if ((flags & bit) == 0) + continue; + flags &= ~bit; + nlen = strlen(name); + slen += nlen; + /* count btwn flag space */ + if (flags != 0) + slen += 1; + /* need NULL char as well */ + if (len <= slen) + break; + /* copy NULL char but don't count it */ + strncpy(p, name, nlen + 1); + p += nlen; + /* copy btwn flag space and NULL char */ + if (flags != 0) + p += snprintf(p, 2, " "); + } + + /* indicate the str was too short */ + if (flags != 0) { + if (len < 2) + p -= 2 - len; /* overwrite last char */ + p += snprintf(p, 2, ">"); + } + + return (int)(p - buf); +} + +/* print bytes formatted as hex to a string. return the resulting string length */ +int +bcm_format_hex(char *str, const void *bytes, int len) +{ + int i; + char *p = str; + const uint8 *src = (const uint8*)bytes; + + for (i = 0; i < len; i++) { + p += snprintf(p, 3, "%02X", *src); + src++; + } + return (int)(p - str); +} +#endif + +/* pretty hex print a contiguous buffer */ +void +prhex(const char *msg, uchar *buf, uint nbytes) +{ + char line[128], *p; + int len = sizeof(line); + int nchar; + uint i; + + if (msg && (msg[0] != '\0')) + printf("%s:\n", msg); + + p = line; + for (i = 0; i < nbytes; i++) { + if (i % 16 == 0) { + nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ + p += nchar; + len -= nchar; + } + if (len > 0) { + nchar = snprintf(p, len, "%02x ", buf[i]); + p += nchar; + len -= nchar; + } + + if (i % 16 == 15) { + printf("%s\n", line); /* flush line */ + p = line; + len = sizeof(line); + } + } + + /* flush last partial line */ + if (p != line) + printf("%s\n", line); +} + +static const char *crypto_algo_names[] = { + "NONE", + "WEP1", + "TKIP", + "WEP128", + "AES_CCM", + "AES_OCB_MSDU", + "AES_OCB_MPDU", +#ifdef BCMCCX + "CKIP", + "CKIP_MMH", + "WEP_MMH", + "NALG", +#else + "NALG", + "UNDEF", + "UNDEF", + "UNDEF", +#endif /* BCMCCX */ + "WAPI", + "PMK", + "BIP", + "AES_GCM", + "AES_CCM256", + "AES_GCM256", + "BIP_CMAC256", + "BIP_GMAC", + "BIP_GMAC256", + "UNDEF" +}; + +const char * +bcm_crypto_algo_name(uint algo) +{ + return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; +} + + +char * +bcm_chipname(uint chipid, char *buf, uint len) +{ + const char *fmt; + + fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; + snprintf(buf, len, fmt, chipid); + return buf; +} + +/* Produce a human-readable string for boardrev */ +char * +bcm_brev_str(uint32 brev, char *buf) +{ + if (brev < 0x100) + snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); + else + snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); + + return (buf); +} + +#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ + +/* dump large strings to console */ +void +printbig(char *buf) +{ + uint len, max_len; + char c; + + len = strlen(buf); + + max_len = BUFSIZE_TODUMP_ATONCE; + + while (len > max_len) { + c = buf[max_len]; + buf[max_len] = '\0'; + printf("%s", buf); + buf[max_len] = c; + + buf += max_len; + len -= max_len; + } + /* print the remaining string */ + printf("%s\n", buf); + return; +} + +/* routine to dump fields in a fileddesc structure */ +uint +bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, + char *buf, uint32 bufsize) +{ + uint filled_len; + int len; + struct fielddesc *cur_ptr; + + filled_len = 0; + cur_ptr = fielddesc_array; + + while (bufsize > 1) { + if (cur_ptr->nameandfmt == NULL) + break; + len = snprintf(buf, bufsize, cur_ptr->nameandfmt, + read_rtn(arg0, arg1, cur_ptr->offset)); + /* check for snprintf overflow or error */ + if (len < 0 || (uint32)len >= bufsize) + len = bufsize - 1; + buf += len; + bufsize -= len; + filled_len += len; + cur_ptr++; + } + return filled_len; +} + +uint +bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) +{ + uint len; + + len = strlen(name) + 1; + + if ((len + datalen) > buflen) + return 0; + + strncpy(buf, name, buflen); + + /* append data onto the end of the name string */ + memcpy(&buf[len], data, datalen); + len += datalen; + + return len; +} + +/* Quarter dBm units to mW + * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 + * Table is offset so the last entry is largest mW value that fits in + * a uint16. + */ + +#define QDBM_OFFSET 153 /* Offset for first entry */ +#define QDBM_TABLE_LEN 40 /* Table size */ + +/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. + * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 + */ +#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */ + +/* Largest mW value that will round down to the last table entry, + * QDBM_OFFSET + QDBM_TABLE_LEN-1. + * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. + */ +#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ + +static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { +/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ +/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, +/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, +/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, +/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, +/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 +}; + +uint16 +BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm) +{ + uint factor = 1; + int idx = qdbm - QDBM_OFFSET; + + if (idx >= QDBM_TABLE_LEN) { + /* clamp to max uint16 mW value */ + return 0xFFFF; + } + + /* scale the qdBm index up to the range of the table 0-40 + * where an offset of 40 qdBm equals a factor of 10 mW. + */ + while (idx < 0) { + idx += 40; + factor *= 10; + } + + /* return the mW value scaled down to the correct factor of 10, + * adding in factor/2 to get proper rounding. + */ + return ((nqdBm_to_mW_map[idx] + factor/2) / factor); +} + +uint8 +BCMROMFN(bcm_mw_to_qdbm)(uint16 mw) +{ + uint8 qdbm; + int offset; + uint mw_uint = mw; + uint boundary; + + /* handle boundary case */ + if (mw_uint <= 1) + return 0; + + offset = QDBM_OFFSET; + + /* move mw into the range of the table */ + while (mw_uint < QDBM_TABLE_LOW_BOUND) { + mw_uint *= 10; + offset -= 40; + } + + for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) { + boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - + nqdBm_to_mW_map[qdbm])/2; + if (mw_uint < boundary) break; + } + + qdbm += (uint8)offset; + + return (qdbm); +} + + +uint +BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length) +{ + uint bitcount = 0, i; + uint8 tmp; + for (i = 0; i < length; i++) { + tmp = bitmap[i]; + while (tmp) { + bitcount++; + tmp &= (tmp - 1); + } + } + return bitcount; +} + +#ifdef BCMDRIVER + +/* Initialization of bcmstrbuf structure */ +void +bcm_binit(struct bcmstrbuf *b, char *buf, uint size) +{ + b->origsize = b->size = size; + b->origbuf = b->buf = buf; +} + +/* Buffer sprintf wrapper to guard against buffer overflow */ +int +bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + + r = vsnprintf(b->buf, b->size, fmt, ap); + + /* Non Ansi C99 compliant returns -1, + * Ansi compliant return r >= b->size, + * bcmstdlib returns 0, handle all + */ + /* r == 0 is also the case when strlen(fmt) is zero. + * typically the case when "" is passed as argument. + */ + if ((r == -1) || (r >= (int)b->size)) { + b->size = 0; + } else { + b->size -= r; + b->buf += r; + } + + va_end(ap); + + return r; +} + +void +bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) +{ + int i; + + if (msg != NULL && msg[0] != '\0') + bcm_bprintf(b, "%s", msg); + for (i = 0; i < len; i ++) + bcm_bprintf(b, "%02X", buf[i]); + if (newline) + bcm_bprintf(b, "\n"); +} + +void +bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) +{ + int i; + + for (i = 0; i < num_bytes; i++) { + num[i] += amount; + if (num[i] >= amount) + break; + amount = 1; + } +} + +int +bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) +{ + int i; + + for (i = nbytes - 1; i >= 0; i--) { + if (arg1[i] != arg2[i]) + return (arg1[i] - arg2[i]); + } + return 0; +} + +void +bcm_print_bytes(const char *name, const uchar *data, int len) +{ + int i; + int per_line = 0; + + printf("%s: %d \n", name ? name : "", len); + for (i = 0; i < len; i++) { + printf("%02x ", *data++); + per_line++; + if (per_line == 16) { + per_line = 0; + printf("\n"); + } + } + printf("\n"); +} + +/* Look for vendor-specific IE with specified OUI and optional type */ +bcm_tlv_t * +bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len) +{ + bcm_tlv_t *ie; + uint8 ie_len; + + ie = (bcm_tlv_t*)tlvs; + + /* make sure we are looking at a valid IE */ + if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { + return NULL; + } + + /* Walk through the IEs looking for an OUI match */ + do { + ie_len = ie->len; + if ((ie->id == DOT11_MNG_PROPR_ID) && + (ie_len >= (DOT11_OUI_LEN + type_len)) && + !bcmp(ie->data, voui, DOT11_OUI_LEN)) + { + /* compare optional type */ + if (type_len == 0 || + !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { + return (ie); /* a match */ + } + } + } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); + + return NULL; +} + +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) + +int +bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) +{ + uint i, c; + char *p = buf; + char *endp = buf + SSID_FMT_BUF_LEN; + + if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; + + for (i = 0; i < ssid_len; i++) { + c = (uint)ssid[i]; + if (c == '\\') { + *p++ = '\\'; + *p++ = '\\'; + } else if (bcm_isprint((uchar)c)) { + *p++ = (char)c; + } else { + p += snprintf(p, (endp - p), "\\x%02X", c); + } + } + *p = '\0'; + ASSERT(p < endp); + + return (int)(p - buf); +} +#endif + +#endif /* BCMDRIVER */ + +/* + * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL. + * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0 + * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. + * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. +*/ + +unsigned int +process_nvram_vars(char *varbuf, unsigned int len) +{ + char *dp; + bool findNewline; + int column; + unsigned int buf_len, n; + unsigned int pad = 0; + + dp = varbuf; + + findNewline = FALSE; + column = 0; + + for (n = 0; n < len; n++) { + if (varbuf[n] == '\r') + continue; + if (findNewline && varbuf[n] != '\n') + continue; + findNewline = FALSE; + if (varbuf[n] == '#') { + findNewline = TRUE; + continue; + } + if (varbuf[n] == '\n') { + if (column == 0) + continue; + *dp++ = 0; + column = 0; + continue; + } + *dp++ = varbuf[n]; + column++; + } + buf_len = (unsigned int)(dp - varbuf); + if (buf_len % 4) { + pad = 4 - buf_len % 4; + if (pad && (buf_len + pad <= len)) { + buf_len += pad; + } + } + + while (dp < varbuf + n) + *dp++ = 0; + + return buf_len; +} + +/* calculate a * b + c */ +void +bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c) +{ +#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;} + uint32 r1, r0; + uint32 a1, a0, b1, b0, t, cc = 0; + + a1 = a >> 16; + a0 = a & 0xffff; + b1 = b >> 16; + b0 = b & 0xffff; + + r0 = a0 * b0; + FORMALIZE(r0); + + t = (a1 * b0) << 16; + FORMALIZE(t); + + r0 += t; + FORMALIZE(r0); + + t = (a0 * b1) << 16; + FORMALIZE(t); + + r0 += t; + FORMALIZE(r0); + + FORMALIZE(c); + + r0 += c; + FORMALIZE(r0); + + r0 |= (cc % 2) ? 0x80000000 : 0; + r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); + + *r_high = r1; + *r_low = r0; +} + +/* calculate a / b */ +void +bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) +{ + uint32 a1 = a_high, a0 = a_low, r0 = 0; + + if (b < 2) + return; + + while (a1 != 0) { + r0 += (0xffffffff / b) * a1; + bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); + } + + r0 += a0 / b; + *r = r0; +} + +#ifndef setbit /* As in the header file */ +#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS +/* Set bit in byte array. */ +void +setbit(void *array, uint bit) +{ + ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY); +} + +/* Clear bit in byte array. */ +void +clrbit(void *array, uint bit) +{ + ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY)); +} + +/* Test if bit is set in byte array. */ +bool +isset(const void *array, uint bit) +{ + return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))); +} + +/* Test if bit is clear in byte array. */ +bool +isclr(const void *array, uint bit) +{ + return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0); +} +#endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */ +#endif /* setbit */ + +void +bcm_bitprint32(const uint32 u32) +{ + int i; + for (i = NBITS(uint32) - 1; i >= 0; i--) { + isbitset(u32, i) ? printf("1") : printf("0"); + if ((i % NBBY) == 0) printf(" "); + } + printf("\n"); +} + +#ifdef BCMDRIVER +/* + * Hierarchical Multiword bitmap based small id allocator. + * + * Multilevel hierarchy bitmap. (maximum 2 levels) + * First hierarchy uses a multiword bitmap to identify 32bit words in the + * second hierarchy that have at least a single bit set. Each bit in a word of + * the second hierarchy represents a unique ID that may be allocated. + * + * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. + * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word + * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. + * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non + * non-zero bitmap word carrying at least one free ID. + * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. + * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID + * + * Design Notes: + * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many + * bits are computed each time on allocation and deallocation, requiring 4 + * array indexed access and 3 arithmetic operations. When not defined, a runtime + * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. + * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. + * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may + * be used by defining BCM_MWBMAP_USE_CNTSETBITS. + * + * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array + * size is fixed. No intention to support larger than 4K indice allocation. ID + * allocators for ranges smaller than 4K will have a wastage of only 12Bytes + * with savings in not having to use an indirect access, had it been dynamically + * allocated. + */ +#define BCM_MWBMAP_ITEMS_MAX (4 * 1024) /* May increase to 16K */ + +#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) +#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) +#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) +#define BCM_MWBMAP_SHIFT_OP (5) +#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) +#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) +#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) + +/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ +#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) +#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) + +#if defined(BCM_MWBMAP_DEBUG) +#define BCM_MWBMAP_AUDIT(mwb) \ + do { \ + ASSERT((mwb != NULL) && \ + (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ + bcm_mwbmap_audit(mwb); \ + } while (0) +#define MWBMAP_ASSERT(exp) ASSERT(exp) +#define MWBMAP_DBG(x) printf x +#else /* !BCM_MWBMAP_DEBUG */ +#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) +#define MWBMAP_ASSERT(exp) do {} while (0) +#define MWBMAP_DBG(x) +#endif /* !BCM_MWBMAP_DEBUG */ + + +typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ + uint16 wmaps; /* Total number of words in free wd bitmap */ + uint16 imaps; /* Total number of words in free id bitmap */ + int16 ifree; /* Count of free indices. Used only in audits */ + uint16 total; /* Total indices managed by multiword bitmap */ + + void * magic; /* Audit handle parameter from user */ + + uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + + uint32 id_bitmap[0]; /* Second level bitmap */ +} bcm_mwbmap_t; + +/* Incarnate a hierarchical multiword bitmap based small index allocator. */ +struct bcm_mwbmap * +BCMATTACHFN(bcm_mwbmap_init)(osl_t *osh, uint32 items_max) +{ + struct bcm_mwbmap * mwbmap_p; + uint32 wordix, size, words, extra; + + /* Implementation Constraint: Uses 32bit word bitmap */ + MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); + MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); + MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); + MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); + + ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); + + /* Determine the number of words needed in the multiword bitmap */ + extra = BCM_MWBMAP_MODOP(items_max); + words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); + + /* Allocate runtime state of multiword bitmap */ + /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ + size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); + mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); + if (mwbmap_p == (bcm_mwbmap_t *)NULL) { + ASSERT(0); + goto error1; + } + memset(mwbmap_p, 0, size); + + /* Initialize runtime multiword bitmap state */ + mwbmap_p->imaps = (uint16)words; + mwbmap_p->ifree = (int16)items_max; + mwbmap_p->total = (uint16)items_max; + + /* Setup magic, for use in audit of handle */ + mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); + + /* Setup the second level bitmap of free indices */ + /* Mark all indices as available */ + for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { + mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + } + + /* Ensure that extra indices are tagged as un-available */ + if (extra) { /* fixup the free ids in last bitmap and wd_count */ + uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; + *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + } + + /* Setup the first level bitmap hierarchy */ + extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); + words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); + + mwbmap_p->wmaps = (uint16)words; + + for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) + mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); + if (extra) { + uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; + *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ + } + + return mwbmap_p; + +error1: + return BCM_MWBMAP_INVALID_HDL; +} + +/* Release resources used by multiword bitmap based small index allocator. */ +void +BCMATTACHFN(bcm_mwbmap_fini)(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) + + (sizeof(uint32) * mwbmap_p->imaps)); + return; +} + +/* Allocate a unique small index using a multiword bitmap index allocator. */ +uint32 +bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + /* Start with the first hierarchy */ + for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { + + bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ + + if (bitmap != 0U) { + + uint32 count, bitix, *bitmap_p; + + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + + /* clear all except trailing 1 */ + bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); + MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == + bcm_count_leading_zeros(bitmap)); + bitix = (BCM_MWBMAP_BITS_WORD - 1) + - bcm_count_leading_zeros(bitmap); /* use asm clz */ + wordix = BCM_MWBMAP_MULOP(wordix) + bitix; + + /* Clear bit if wd count is 0, without conditional branch */ +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + mwbmap_p->wd_count[wordix]--; + count = mwbmap_p->wd_count[wordix]; + MWBMAP_ASSERT(count == + (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + MWBMAP_ASSERT(count >= 0); + + /* clear wd_bitmap bit if id_map count is 0 */ + bitmap = (count == 0) << bitix; + + MWBMAP_DBG(( + "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); + + *bitmap_p ^= bitmap; + + /* Use bitix in the second hierarchy */ + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ + MWBMAP_ASSERT(bitmap != 0U); + + /* clear all except trailing 1 */ + bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); + MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == + bcm_count_leading_zeros(bitmap)); + bitix = BCM_MWBMAP_MULOP(wordix) + + (BCM_MWBMAP_BITS_WORD - 1) + - bcm_count_leading_zeros(bitmap); /* use asm clz */ + + mwbmap_p->ifree--; /* decrement system wide free count */ + MWBMAP_ASSERT(mwbmap_p->ifree >= 0); + + MWBMAP_DBG(( + "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, + mwbmap_p->ifree)); + + *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ + + return bitix; + } + } + + ASSERT(mwbmap_p->ifree == 0); + + return BCM_MWBMAP_INVALID_IDX; +} + +/* Force an index at a specified position to be in use */ +void +bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 count, wordix, bitmap, *bitmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + /* Start with second hierarchy */ + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + ASSERT((*bitmap_p & bitmap) == bitmap); + + mwbmap_p->ifree--; /* update free count */ + ASSERT(mwbmap_p->ifree >= 0); + + MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, + mwbmap_p->ifree)); + + *bitmap_p ^= bitmap; /* mark as in use */ + + /* Update first hierarchy */ + bitix = wordix; + + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + mwbmap_p->wd_count[bitix]--; + count = mwbmap_p->wd_count[bitix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + MWBMAP_ASSERT(count >= 0); + + bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); + + MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", + BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, + (*bitmap_p) ^ bitmap, count)); + + *bitmap_p ^= bitmap; /* mark as in use */ + + return; +} + +/* Free a previously allocated index back into the multiword bitmap allocator */ +void +bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap, *bitmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + /* Start with second level hierarchy */ + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->id_bitmap[wordix]; + + ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ + + mwbmap_p->ifree++; /* update free count */ + ASSERT(mwbmap_p->ifree <= mwbmap_p->total); + + MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, + mwbmap_p->ifree)); + + *bitmap_p |= bitmap; /* mark as available */ + + /* Now update first level hierarchy */ + + bitix = wordix; + + wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + +#if !defined(BCM_MWBMAP_USE_CNTSETBITS) + mwbmap_p->wd_count[bitix]++; +#endif + +#if defined(BCM_MWBMAP_DEBUG) + { + uint32 count; +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[bitix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + + MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); + + MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", + bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); + } +#endif /* BCM_MWBMAP_DEBUG */ + + *bitmap_p |= bitmap; + + return; +} + +/* Fetch the toal number of free indices in the multiword bitmap allocator */ +uint32 +bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(mwbmap_p->ifree >= 0); + + return mwbmap_p->ifree; +} + +/* Determine whether an index is inuse or free */ +bool +bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 wordix, bitmap; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + ASSERT(bitix < mwbmap_p->total); + + wordix = BCM_MWBMAP_DIVOP(bitix); + bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); + + return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); +} + +/* Debug dump a multiword bitmap allocator */ +void +bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) +{ + uint32 ix, count; + bcm_mwbmap_t * mwbmap_p; + + BCM_MWBMAP_AUDIT(mwbmap_hdl); + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p, + mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total); + for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { + printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]); + bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); + printf("\n"); + } + for (ix = 0U; ix < mwbmap_p->imaps; ix++) { +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[ix]; + MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count); + bcm_bitprint32(mwbmap_p->id_bitmap[ix]); + printf("\n"); + } + + return; +} + +/* Audit a hierarchical multiword bitmap */ +void +bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) +{ + bcm_mwbmap_t * mwbmap_p; + uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; + + mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); + + for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { + + bitmap_p = &mwbmap_p->wd_bitmap[wordix]; + + for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { + if ((*bitmap_p) & (1 << bitix)) { + idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; +#if defined(BCM_MWBMAP_USE_CNTSETBITS) + count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); +#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ + count = mwbmap_p->wd_count[idmap_ix]; + ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); +#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ + ASSERT(count != 0U); + free_cnt += count; + } + } + } + + ASSERT(free_cnt == mwbmap_p->ifree); +} +/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ + +#endif /* BCMDRIVER */ + +/* calculate a >> b; and returns only lower 32 bits */ +void +bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) +{ + uint32 a1 = a_high, a0 = a_low, r0 = 0; + + if (b == 0) { + r0 = a_low; + *r = r0; + return; + } + + if (b < 32) { + a0 = a0 >> b; + a1 = a1 & ((1 << b) - 1); + a1 = a1 << (32 - b); + r0 = a0 | a1; + *r = r0; + return; + } else { + r0 = a1 >> (b - 32); + *r = r0; + return; + } + +} + +/* calculate a + b where a is a 64 bit number and b is a 32 bit number */ +void +bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset) +{ + uint32 r1_lo = *r_lo; + (*r_lo) += offset; + if (*r_lo < r1_lo) + (*r_hi) ++; +} + +/* calculate a - b where a is a 64 bit number and b is a 32 bit number */ +void +bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset) +{ + uint32 r1_lo = *r_lo; + (*r_lo) -= offset; + if (*r_lo > r1_lo) + (*r_hi) --; +} + +#ifdef DEBUG_COUNTER +#if (OSL_SYSUPTIME_SUPPORT == TRUE) +void counter_printlog(counter_tbl_t *ctr_tbl) +{ + uint32 now; + + if (!ctr_tbl->enabled) + return; + + now = OSL_SYSUPTIME(); + + if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) { + uint8 i = 0; + printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print); + + for (i = 0; i < ctr_tbl->needed_cnt; i++) { + printf(" %u", ctr_tbl->cnt[i]); + } + printf("\n"); + + ctr_tbl->prev_log_print = now; + bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint)); + } +} +#else +/* OSL_SYSUPTIME is not supported so no way to get time */ +#define counter_printlog(a) do {} while (0) +#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */ +#endif /* DEBUG_COUNTER */
diff --git a/src/shared/bcmwifi/include/bcmwifi_channels.h b/src/shared/bcmwifi/include/bcmwifi_channels.h new file mode 100644 index 0000000..6da2e25 --- /dev/null +++ b/src/shared/bcmwifi/include/bcmwifi_channels.h
@@ -0,0 +1,300 @@ +/* + * Misc utility routines for WL and Apps + * This header file housing the define and function prototype use by + * both the wl driver, tools & Apps. + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ + */ + +#ifndef _bcmwifi_channels_h_ +#define _bcmwifi_channels_h_ + + + +typedef uint16 chanspec_t; + + +#define CH_UPPER_SB 0x01 +#define CH_LOWER_SB 0x02 +#define CH_EWA_VALID 0x04 +#define CH_80MHZ_APART 16 +#define CH_40MHZ_APART 8 +#define CH_20MHZ_APART 4 +#define CH_10MHZ_APART 2 +#define CH_5MHZ_APART 1 +#define CH_MAX_2G_CHANNEL 14 +#define MAXCHANNEL 224 +#define CHSPEC_CTLOVLP(sp1, sp2, sep) (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < \ + (sep)) + + +#undef D11AC_IOTYPES +#define D11AC_IOTYPES + +#define WL_CHANSPEC_CHAN_MASK 0x00ff +#define WL_CHANSPEC_CHAN_SHIFT 0 +#define WL_CHANSPEC_CHAN1_MASK 0x000f +#define WL_CHANSPEC_CHAN1_SHIFT 0 +#define WL_CHANSPEC_CHAN2_MASK 0x00f0 +#define WL_CHANSPEC_CHAN2_SHIFT 4 + +#define WL_CHANSPEC_CTL_SB_MASK 0x0700 +#define WL_CHANSPEC_CTL_SB_SHIFT 8 +#define WL_CHANSPEC_CTL_SB_LLL 0x0000 +#define WL_CHANSPEC_CTL_SB_LLU 0x0100 +#define WL_CHANSPEC_CTL_SB_LUL 0x0200 +#define WL_CHANSPEC_CTL_SB_LUU 0x0300 +#define WL_CHANSPEC_CTL_SB_ULL 0x0400 +#define WL_CHANSPEC_CTL_SB_ULU 0x0500 +#define WL_CHANSPEC_CTL_SB_UUL 0x0600 +#define WL_CHANSPEC_CTL_SB_UUU 0x0700 +#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL +#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU +#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL +#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU +#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL + +#define WL_CHANSPEC_BW_MASK 0x3800 +#define WL_CHANSPEC_BW_SHIFT 11 +#define WL_CHANSPEC_BW_5 0x0000 +#define WL_CHANSPEC_BW_10 0x0800 +#define WL_CHANSPEC_BW_20 0x1000 +#define WL_CHANSPEC_BW_40 0x1800 +#define WL_CHANSPEC_BW_80 0x2000 +#define WL_CHANSPEC_BW_160 0x2800 +#define WL_CHANSPEC_BW_8080 0x3000 + +#define WL_CHANSPEC_BAND_MASK 0xc000 +#define WL_CHANSPEC_BAND_SHIFT 14 +#define WL_CHANSPEC_BAND_2G 0x0000 +#define WL_CHANSPEC_BAND_3G 0x4000 +#define WL_CHANSPEC_BAND_4G 0x8000 +#define WL_CHANSPEC_BAND_5G 0xc000 +#define INVCHANSPEC 255 + + +#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ + ((channel) - CH_10MHZ_APART) : 0) +#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ + ((channel) + CH_10MHZ_APART) : 0) + +#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) +#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ + ((channel) + 3 * CH_10MHZ_APART) : 0) +#define LU_20_SB(channel) LOWER_20_SB(channel) +#define UL_20_SB(channel) UPPER_20_SB(channel) + +#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) +#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) +#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) +#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ + (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) +#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ + ((channel) + CH_20MHZ_APART) : 0) +#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ + ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ + WL_CHANSPEC_BAND_5G)) +#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | \ + WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) +#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ + ((channel) | (ctlsb) | \ + WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) + + +#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) +#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT +#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT +#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) +#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) +#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) + +#ifdef WL11N_20MHZONLY + +#define CHSPEC_IS10(chspec) 0 +#define CHSPEC_IS20(chspec) 1 +#ifndef CHSPEC_IS40 +#define CHSPEC_IS40(chspec) 0 +#endif +#ifndef CHSPEC_IS80 +#define CHSPEC_IS80(chspec) 0 +#endif +#ifndef CHSPEC_IS160 +#define CHSPEC_IS160(chspec) 0 +#endif +#ifndef CHSPEC_IS8080 +#define CHSPEC_IS8080(chspec) 0 +#endif + +#else + +#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) +#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) +#ifndef CHSPEC_IS40 +#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) +#endif +#ifndef CHSPEC_IS80 +#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) +#endif +#ifndef CHSPEC_IS160 +#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) +#endif +#ifndef CHSPEC_IS8080 +#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) +#endif + +#endif + +#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) +#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) +#define CHSPEC_SB_UPPER(chspec) \ + ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) +#define CHSPEC_SB_LOWER(chspec) \ + ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) +#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) + + +#define CHANSPEC_STR_LEN 20 + + +#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ + CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) + + +#define CHSPEC_BW_GE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) >= bw)) + +#define CHSPEC_BW_LE(chspec, bw) \ + ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) ||\ + (CHSPEC_BW(chspec) <= bw)) + +#define CHSPEC_BW_GT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) > bw)) + +#define CHSPEC_BW_LT(chspec, bw) \ + (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ + (bw == WL_CHANSPEC_BW_160 || bw == WL_CHANSPEC_BW_8080)) &&\ + (CHSPEC_BW(chspec) < bw)) + + +#define WL_LCHANSPEC_CHAN_MASK 0x00ff +#define WL_LCHANSPEC_CHAN_SHIFT 0 + +#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 +#define WL_LCHANSPEC_CTL_SB_SHIFT 8 +#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 +#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 +#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 + +#define WL_LCHANSPEC_BW_MASK 0x0C00 +#define WL_LCHANSPEC_BW_SHIFT 10 +#define WL_LCHANSPEC_BW_10 0x0400 +#define WL_LCHANSPEC_BW_20 0x0800 +#define WL_LCHANSPEC_BW_40 0x0C00 + +#define WL_LCHANSPEC_BAND_MASK 0xf000 +#define WL_LCHANSPEC_BAND_SHIFT 12 +#define WL_LCHANSPEC_BAND_5G 0x1000 +#define WL_LCHANSPEC_BAND_2G 0x2000 + +#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) +#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) +#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) +#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) +#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) +#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) +#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) +#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) +#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) + +#define LCHSPEC_SB_UPPER(chspec) \ + ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \ + (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) +#define LCHSPEC_SB_LOWER(chspec) \ + ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \ + (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) + +#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) + +#define CH20MHZ_LCHSPEC(channel) \ + (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ + WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ + WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) + + + + +#define WF_CHAN_FACTOR_2_4_G 4814 + + +#define WF_CHAN_FACTOR_5_G 10000 + + +#define WF_CHAN_FACTOR_4_G 8000 + +#define WLC_2G_25MHZ_OFFSET 5 + + +extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); + + +extern chanspec_t wf_chspec_aton(const char *a); + + +extern bool wf_chspec_malformed(chanspec_t chanspec); + + +extern bool wf_chspec_valid(chanspec_t chanspec); + + +extern uint8 wf_chspec_ctlchan(chanspec_t chspec); + + +extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); + + +extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); + + +extern int wf_mhz2channel(uint freq, uint start_factor); + + +extern int wf_channel2mhz(uint channel, uint start_factor); + + +extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); + +extern uint wf_channel2freq(uint channel); +extern uint wf_freq2channel(uint freq); + + + +extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, +uint8 chan1_80Mhz, uint8 chan2_80Mhz); + + +extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec); + + +extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec); + + +extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec); + + +#endif
diff --git a/src/shared/bcmwifi/include/bcmwifi_rates.h b/src/shared/bcmwifi/include/bcmwifi_rates.h new file mode 100644 index 0000000..b95da33 --- /dev/null +++ b/src/shared/bcmwifi/include/bcmwifi_rates.h
@@ -0,0 +1,422 @@ +/* + * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: bcmwifi_rates.h 5187 2012-06-29 06:17:50Z $ + */ + +#ifndef _bcmwifi_rates_h_ +#define _bcmwifi_rates_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#define WL_RATESET_SZ_DSSS 4 +#define WL_RATESET_SZ_OFDM 8 +#define WL_RATESET_SZ_HT_MCS 8 +#define WL_RATESET_SZ_VHT_MCS 10 + +#define WL_TX_CHAINS_MAX 3 + +#define WL_RATE_DISABLED (-128) + + +typedef enum wl_tx_bw { + WL_TX_BW_20, + WL_TX_BW_40, + WL_TX_BW_80, + WL_TX_BW_160, + WL_TX_BW_20IN40, + WL_TX_BW_20IN80, + WL_TX_BW_40IN80, + WL_TX_BW_20IN160, + WL_TX_BW_40IN160, + WL_TX_BW_80IN160, + WL_TX_BW_ALL +} wl_tx_bw_t; + + + +typedef enum wl_tx_mode { + WL_TX_MODE_NONE, + WL_TX_MODE_STBC, + WL_TX_MODE_CDD, + WL_TX_MODE_TXBF, + WL_NUM_TX_MODES +} wl_tx_mode_t; + + + +typedef enum wl_tx_chains { + WL_TX_CHAINS_1 = 1, + WL_TX_CHAINS_2, + WL_TX_CHAINS_3 +} wl_tx_chains_t; + + + +typedef enum wl_tx_nss { + WL_TX_NSS_1 = 1, + WL_TX_NSS_2, + WL_TX_NSS_3 +} wl_tx_nss_t; + + +typedef enum clm_rates { + + + + WL_RATE_1X1_DSSS_1 = 0, + WL_RATE_1X1_DSSS_2 = 1, + WL_RATE_1X1_DSSS_5_5 = 2, + WL_RATE_1X1_DSSS_11 = 3, + + WL_RATE_1X1_OFDM_6 = 4, + WL_RATE_1X1_OFDM_9 = 5, + WL_RATE_1X1_OFDM_12 = 6, + WL_RATE_1X1_OFDM_18 = 7, + WL_RATE_1X1_OFDM_24 = 8, + WL_RATE_1X1_OFDM_36 = 9, + WL_RATE_1X1_OFDM_48 = 10, + WL_RATE_1X1_OFDM_54 = 11, + + WL_RATE_1X1_MCS0 = 12, + WL_RATE_1X1_MCS1 = 13, + WL_RATE_1X1_MCS2 = 14, + WL_RATE_1X1_MCS3 = 15, + WL_RATE_1X1_MCS4 = 16, + WL_RATE_1X1_MCS5 = 17, + WL_RATE_1X1_MCS6 = 18, + WL_RATE_1X1_MCS7 = 19, + + WL_RATE_1X1_VHT0SS1 = 12, + WL_RATE_1X1_VHT1SS1 = 13, + WL_RATE_1X1_VHT2SS1 = 14, + WL_RATE_1X1_VHT3SS1 = 15, + WL_RATE_1X1_VHT4SS1 = 16, + WL_RATE_1X1_VHT5SS1 = 17, + WL_RATE_1X1_VHT6SS1 = 18, + WL_RATE_1X1_VHT7SS1 = 19, + WL_RATE_1X1_VHT8SS1 = 20, + WL_RATE_1X1_VHT9SS1 = 21, + + + + + + WL_RATE_1X2_DSSS_1 = 22, + WL_RATE_1X2_DSSS_2 = 23, + WL_RATE_1X2_DSSS_5_5 = 24, + WL_RATE_1X2_DSSS_11 = 25, + + WL_RATE_1X2_CDD_OFDM_6 = 26, + WL_RATE_1X2_CDD_OFDM_9 = 27, + WL_RATE_1X2_CDD_OFDM_12 = 28, + WL_RATE_1X2_CDD_OFDM_18 = 29, + WL_RATE_1X2_CDD_OFDM_24 = 30, + WL_RATE_1X2_CDD_OFDM_36 = 31, + WL_RATE_1X2_CDD_OFDM_48 = 32, + WL_RATE_1X2_CDD_OFDM_54 = 33, + + WL_RATE_1X2_CDD_MCS0 = 34, + WL_RATE_1X2_CDD_MCS1 = 35, + WL_RATE_1X2_CDD_MCS2 = 36, + WL_RATE_1X2_CDD_MCS3 = 37, + WL_RATE_1X2_CDD_MCS4 = 38, + WL_RATE_1X2_CDD_MCS5 = 39, + WL_RATE_1X2_CDD_MCS6 = 40, + WL_RATE_1X2_CDD_MCS7 = 41, + + WL_RATE_1X2_VHT0SS1 = 34, + WL_RATE_1X2_VHT1SS1 = 35, + WL_RATE_1X2_VHT2SS1 = 36, + WL_RATE_1X2_VHT3SS1 = 37, + WL_RATE_1X2_VHT4SS1 = 38, + WL_RATE_1X2_VHT5SS1 = 39, + WL_RATE_1X2_VHT6SS1 = 40, + WL_RATE_1X2_VHT7SS1 = 41, + WL_RATE_1X2_VHT8SS1 = 42, + WL_RATE_1X2_VHT9SS1 = 43, + + + WL_RATE_2X2_STBC_MCS0 = 44, + WL_RATE_2X2_STBC_MCS1 = 45, + WL_RATE_2X2_STBC_MCS2 = 46, + WL_RATE_2X2_STBC_MCS3 = 47, + WL_RATE_2X2_STBC_MCS4 = 48, + WL_RATE_2X2_STBC_MCS5 = 49, + WL_RATE_2X2_STBC_MCS6 = 50, + WL_RATE_2X2_STBC_MCS7 = 51, + + WL_RATE_2X2_STBC_VHT0SS1 = 44, + WL_RATE_2X2_STBC_VHT1SS1 = 45, + WL_RATE_2X2_STBC_VHT2SS1 = 46, + WL_RATE_2X2_STBC_VHT3SS1 = 47, + WL_RATE_2X2_STBC_VHT4SS1 = 48, + WL_RATE_2X2_STBC_VHT5SS1 = 49, + WL_RATE_2X2_STBC_VHT6SS1 = 50, + WL_RATE_2X2_STBC_VHT7SS1 = 51, + WL_RATE_2X2_STBC_VHT8SS1 = 52, + WL_RATE_2X2_STBC_VHT9SS1 = 53, + + WL_RATE_2X2_SDM_MCS8 = 54, + WL_RATE_2X2_SDM_MCS9 = 55, + WL_RATE_2X2_SDM_MCS10 = 56, + WL_RATE_2X2_SDM_MCS11 = 57, + WL_RATE_2X2_SDM_MCS12 = 58, + WL_RATE_2X2_SDM_MCS13 = 59, + WL_RATE_2X2_SDM_MCS14 = 60, + WL_RATE_2X2_SDM_MCS15 = 61, + + WL_RATE_2X2_VHT0SS2 = 54, + WL_RATE_2X2_VHT1SS2 = 55, + WL_RATE_2X2_VHT2SS2 = 56, + WL_RATE_2X2_VHT3SS2 = 57, + WL_RATE_2X2_VHT4SS2 = 58, + WL_RATE_2X2_VHT5SS2 = 59, + WL_RATE_2X2_VHT6SS2 = 60, + WL_RATE_2X2_VHT7SS2 = 61, + WL_RATE_2X2_VHT8SS2 = 62, + WL_RATE_2X2_VHT9SS2 = 63, + + + + + WL_RATE_1X3_DSSS_1 = 64, + WL_RATE_1X3_DSSS_2 = 65, + WL_RATE_1X3_DSSS_5_5 = 66, + WL_RATE_1X3_DSSS_11 = 67, + + WL_RATE_1X3_CDD_OFDM_6 = 68, + WL_RATE_1X3_CDD_OFDM_9 = 69, + WL_RATE_1X3_CDD_OFDM_12 = 70, + WL_RATE_1X3_CDD_OFDM_18 = 71, + WL_RATE_1X3_CDD_OFDM_24 = 72, + WL_RATE_1X3_CDD_OFDM_36 = 73, + WL_RATE_1X3_CDD_OFDM_48 = 74, + WL_RATE_1X3_CDD_OFDM_54 = 75, + + WL_RATE_1X3_CDD_MCS0 = 76, + WL_RATE_1X3_CDD_MCS1 = 77, + WL_RATE_1X3_CDD_MCS2 = 78, + WL_RATE_1X3_CDD_MCS3 = 79, + WL_RATE_1X3_CDD_MCS4 = 80, + WL_RATE_1X3_CDD_MCS5 = 81, + WL_RATE_1X3_CDD_MCS6 = 82, + WL_RATE_1X3_CDD_MCS7 = 83, + + WL_RATE_1X3_VHT0SS1 = 76, + WL_RATE_1X3_VHT1SS1 = 77, + WL_RATE_1X3_VHT2SS1 = 78, + WL_RATE_1X3_VHT3SS1 = 79, + WL_RATE_1X3_VHT4SS1 = 80, + WL_RATE_1X3_VHT5SS1 = 81, + WL_RATE_1X3_VHT6SS1 = 82, + WL_RATE_1X3_VHT7SS1 = 83, + WL_RATE_1X3_VHT8SS1 = 84, + WL_RATE_1X3_VHT9SS1 = 85, + + + WL_RATE_2X3_STBC_MCS0 = 86, + WL_RATE_2X3_STBC_MCS1 = 87, + WL_RATE_2X3_STBC_MCS2 = 88, + WL_RATE_2X3_STBC_MCS3 = 89, + WL_RATE_2X3_STBC_MCS4 = 90, + WL_RATE_2X3_STBC_MCS5 = 91, + WL_RATE_2X3_STBC_MCS6 = 92, + WL_RATE_2X3_STBC_MCS7 = 93, + + WL_RATE_2X3_STBC_VHT0SS1 = 86, + WL_RATE_2X3_STBC_VHT1SS1 = 87, + WL_RATE_2X3_STBC_VHT2SS1 = 88, + WL_RATE_2X3_STBC_VHT3SS1 = 89, + WL_RATE_2X3_STBC_VHT4SS1 = 90, + WL_RATE_2X3_STBC_VHT5SS1 = 91, + WL_RATE_2X3_STBC_VHT6SS1 = 92, + WL_RATE_2X3_STBC_VHT7SS1 = 93, + WL_RATE_2X3_STBC_VHT8SS1 = 94, + WL_RATE_2X3_STBC_VHT9SS1 = 95, + + WL_RATE_2X3_SDM_MCS8 = 96, + WL_RATE_2X3_SDM_MCS9 = 97, + WL_RATE_2X3_SDM_MCS10 = 98, + WL_RATE_2X3_SDM_MCS11 = 99, + WL_RATE_2X3_SDM_MCS12 = 100, + WL_RATE_2X3_SDM_MCS13 = 101, + WL_RATE_2X3_SDM_MCS14 = 102, + WL_RATE_2X3_SDM_MCS15 = 103, + + WL_RATE_2X3_VHT0SS2 = 96, + WL_RATE_2X3_VHT1SS2 = 97, + WL_RATE_2X3_VHT2SS2 = 98, + WL_RATE_2X3_VHT3SS2 = 99, + WL_RATE_2X3_VHT4SS2 = 100, + WL_RATE_2X3_VHT5SS2 = 101, + WL_RATE_2X3_VHT6SS2 = 102, + WL_RATE_2X3_VHT7SS2 = 103, + WL_RATE_2X3_VHT8SS2 = 104, + WL_RATE_2X3_VHT9SS2 = 105, + + + WL_RATE_3X3_SDM_MCS16 = 106, + WL_RATE_3X3_SDM_MCS17 = 107, + WL_RATE_3X3_SDM_MCS18 = 108, + WL_RATE_3X3_SDM_MCS19 = 109, + WL_RATE_3X3_SDM_MCS20 = 110, + WL_RATE_3X3_SDM_MCS21 = 111, + WL_RATE_3X3_SDM_MCS22 = 112, + WL_RATE_3X3_SDM_MCS23 = 113, + + WL_RATE_3X3_VHT0SS3 = 106, + WL_RATE_3X3_VHT1SS3 = 107, + WL_RATE_3X3_VHT2SS3 = 108, + WL_RATE_3X3_VHT3SS3 = 109, + WL_RATE_3X3_VHT4SS3 = 110, + WL_RATE_3X3_VHT5SS3 = 111, + WL_RATE_3X3_VHT6SS3 = 112, + WL_RATE_3X3_VHT7SS3 = 113, + WL_RATE_3X3_VHT8SS3 = 114, + WL_RATE_3X3_VHT9SS3 = 115, + + + + + + + WL_RATE_1X2_TXBF_OFDM_6 = 116, + WL_RATE_1X2_TXBF_OFDM_9 = 117, + WL_RATE_1X2_TXBF_OFDM_12 = 118, + WL_RATE_1X2_TXBF_OFDM_18 = 119, + WL_RATE_1X2_TXBF_OFDM_24 = 120, + WL_RATE_1X2_TXBF_OFDM_36 = 121, + WL_RATE_1X2_TXBF_OFDM_48 = 122, + WL_RATE_1X2_TXBF_OFDM_54 = 123, + + WL_RATE_1X2_TXBF_MCS0 = 124, + WL_RATE_1X2_TXBF_MCS1 = 125, + WL_RATE_1X2_TXBF_MCS2 = 126, + WL_RATE_1X2_TXBF_MCS3 = 127, + WL_RATE_1X2_TXBF_MCS4 = 128, + WL_RATE_1X2_TXBF_MCS5 = 129, + WL_RATE_1X2_TXBF_MCS6 = 130, + WL_RATE_1X2_TXBF_MCS7 = 131, + + WL_RATE_1X2_TXBF_VHT0SS1 = 124, + WL_RATE_1X2_TXBF_VHT1SS1 = 125, + WL_RATE_1X2_TXBF_VHT2SS1 = 126, + WL_RATE_1X2_TXBF_VHT3SS1 = 127, + WL_RATE_1X2_TXBF_VHT4SS1 = 128, + WL_RATE_1X2_TXBF_VHT5SS1 = 129, + WL_RATE_1X2_TXBF_VHT6SS1 = 130, + WL_RATE_1X2_TXBF_VHT7SS1 = 131, + WL_RATE_1X2_TXBF_VHT8SS1 = 132, + WL_RATE_1X2_TXBF_VHT9SS1 = 133, + + + + WL_RATE_2X2_TXBF_SDM_MCS8 = 134, + WL_RATE_2X2_TXBF_SDM_MCS9 = 135, + WL_RATE_2X2_TXBF_SDM_MCS10 = 136, + WL_RATE_2X2_TXBF_SDM_MCS11 = 137, + WL_RATE_2X2_TXBF_SDM_MCS12 = 138, + WL_RATE_2X2_TXBF_SDM_MCS13 = 139, + WL_RATE_2X2_TXBF_SDM_MCS14 = 140, + WL_RATE_2X2_TXBF_SDM_MCS15 = 141, + + WL_RATE_2X2_TXBF_VHT0SS2 = 134, + WL_RATE_2X2_TXBF_VHT1SS2 = 135, + WL_RATE_2X2_TXBF_VHT2SS2 = 136, + WL_RATE_2X2_TXBF_VHT3SS2 = 137, + WL_RATE_2X2_TXBF_VHT4SS2 = 138, + WL_RATE_2X2_TXBF_VHT5SS2 = 139, + WL_RATE_2X2_TXBF_VHT6SS2 = 140, + WL_RATE_2X2_TXBF_VHT7SS2 = 141, + + + + + + + WL_RATE_1X3_TXBF_OFDM_6 = 142, + WL_RATE_1X3_TXBF_OFDM_9 = 143, + WL_RATE_1X3_TXBF_OFDM_12 = 144, + WL_RATE_1X3_TXBF_OFDM_18 = 145, + WL_RATE_1X3_TXBF_OFDM_24 = 146, + WL_RATE_1X3_TXBF_OFDM_36 = 147, + WL_RATE_1X3_TXBF_OFDM_48 = 148, + WL_RATE_1X3_TXBF_OFDM_54 = 149, + + WL_RATE_1X3_TXBF_MCS0 = 150, + WL_RATE_1X3_TXBF_MCS1 = 151, + WL_RATE_1X3_TXBF_MCS2 = 152, + WL_RATE_1X3_TXBF_MCS3 = 153, + WL_RATE_1X3_TXBF_MCS4 = 154, + WL_RATE_1X3_TXBF_MCS5 = 155, + WL_RATE_1X3_TXBF_MCS6 = 156, + WL_RATE_1X3_TXBF_MCS7 = 157, + + WL_RATE_1X3_TXBF_VHT0SS1 = 150, + WL_RATE_1X3_TXBF_VHT1SS1 = 151, + WL_RATE_1X3_TXBF_VHT2SS1 = 152, + WL_RATE_1X3_TXBF_VHT3SS1 = 153, + WL_RATE_1X3_TXBF_VHT4SS1 = 154, + WL_RATE_1X3_TXBF_VHT5SS1 = 155, + WL_RATE_1X3_TXBF_VHT6SS1 = 156, + WL_RATE_1X3_TXBF_VHT7SS1 = 157, + WL_RATE_1X3_TXBF_VHT8SS1 = 158, + WL_RATE_1X3_TXBF_VHT9SS1 = 159, + + + + WL_RATE_2X3_TXBF_SDM_MCS8 = 160, + WL_RATE_2X3_TXBF_SDM_MCS9 = 161, + WL_RATE_2X3_TXBF_SDM_MCS10 = 162, + WL_RATE_2X3_TXBF_SDM_MCS11 = 163, + WL_RATE_2X3_TXBF_SDM_MCS12 = 164, + WL_RATE_2X3_TXBF_SDM_MCS13 = 165, + WL_RATE_2X3_TXBF_SDM_MCS14 = 166, + WL_RATE_2X3_TXBF_SDM_MCS15 = 167, + + WL_RATE_2X3_TXBF_VHT0SS2 = 160, + WL_RATE_2X3_TXBF_VHT1SS2 = 161, + WL_RATE_2X3_TXBF_VHT2SS2 = 162, + WL_RATE_2X3_TXBF_VHT3SS2 = 163, + WL_RATE_2X3_TXBF_VHT4SS2 = 164, + WL_RATE_2X3_TXBF_VHT5SS2 = 165, + WL_RATE_2X3_TXBF_VHT6SS2 = 166, + WL_RATE_2X3_TXBF_VHT7SS2 = 167, + WL_RATE_2X3_TXBF_VHT8SS2 = 168, + WL_RATE_2X3_TXBF_VHT9SS2 = 169, + + + + WL_RATE_3X3_TXBF_SDM_MCS16 = 170, + WL_RATE_3X3_TXBF_SDM_MCS17 = 171, + WL_RATE_3X3_TXBF_SDM_MCS18 = 172, + WL_RATE_3X3_TXBF_SDM_MCS19 = 173, + WL_RATE_3X3_TXBF_SDM_MCS20 = 174, + WL_RATE_3X3_TXBF_SDM_MCS21 = 175, + WL_RATE_3X3_TXBF_SDM_MCS22 = 176, + WL_RATE_3X3_TXBF_SDM_MCS23 = 177, + + WL_RATE_3X3_TXBF_VHT0SS3 = 170, + WL_RATE_3X3_TXBF_VHT1SS3 = 171, + WL_RATE_3X3_TXBF_VHT2SS3 = 172, + WL_RATE_3X3_TXBF_VHT3SS3 = 173, + WL_RATE_3X3_TXBF_VHT4SS3 = 174, + WL_RATE_3X3_TXBF_VHT5SS3 = 175, + WL_RATE_3X3_TXBF_VHT6SS3 = 176, + WL_RATE_3X3_TXBF_VHT7SS3 = 177 +} clm_rates_t; + + +#define WL_NUMRATES 178 + +#ifdef __cplusplus +} +#endif + +#endif
diff --git a/src/shared/bcmwifi/src/bcmwifi_channels.c b/src/shared/bcmwifi/src/bcmwifi_channels.c new file mode 100644 index 0000000..d00fec4 --- /dev/null +++ b/src/shared/bcmwifi/src/bcmwifi_channels.c
@@ -0,0 +1,989 @@ +/* + * Misc utility routines used by kernel or app-level. + * Contents are wifi-specific, used by any kernel or app-level + * software that might want wifi things as it grows. + * + * $Copyright Open Broadcom Corporation$ + * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ + */ + +#include <bcm_cfg.h> +#include <typedefs.h> +#include <bcmutils.h> + +#ifdef BCMDRIVER +#include <osl.h> +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) +#else +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#ifndef ASSERT +#define ASSERT(exp) +#endif +#endif + +#include <bcmwifi_channels.h> + +#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) +#include <bcmstdlib.h> +#endif + + + + + + +static const char *wf_chspec_bw_str[] = +{ + "5", + "10", + "20", + "40", + "80", + "160", + "80+80", + "na" +}; + +static const uint8 wf_chspec_bw_mhz[] = +{5, 10, 20, 40, 80, 160, 160}; + +#define WF_NUM_BW \ + (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) + + +static const uint8 wf_5g_40m_chans[] = +{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; +#define WF_NUM_5G_40M_CHANS \ + (sizeof(wf_5g_40m_chans)/sizeof(uint8)) + + +static const uint8 wf_5g_80m_chans[] = +{42, 58, 106, 122, 138, 155}; +#define WF_NUM_5G_80M_CHANS \ + (sizeof(wf_5g_80m_chans)/sizeof(uint8)) + + +static const uint8 wf_5g_160m_chans[] = +{50, 114}; +#define WF_NUM_5G_160M_CHANS \ + (sizeof(wf_5g_160m_chans)/sizeof(uint8)) + + + +static uint +bw_chspec_to_mhz(chanspec_t chspec) +{ + uint bw; + + bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; + return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); +} + + +static uint8 +center_chan_to_edge(uint bw) +{ + + return (uint8)(((bw - 20) / 2) / 5); +} + + +static uint8 +channel_low_edge(uint center_ch, uint bw) +{ + return (uint8)(center_ch - center_chan_to_edge(bw)); +} + + +static int +channel_to_sb(uint center_ch, uint ctl_ch, uint bw) +{ + uint lowest = channel_low_edge(center_ch, bw); + uint sb; + + if ((ctl_ch - lowest) % 4) { + + return -1; + } + + sb = ((ctl_ch - lowest) / 4); + + + if (sb >= (bw / 20)) { + + return -1; + } + + return sb; +} + + +static uint8 +channel_to_ctl_chan(uint center_ch, uint bw, uint sb) +{ + return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); +} + + +static int +channel_80mhz_to_id(uint ch) +{ + uint i; + for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { + if (ch == wf_5g_80m_chans[i]) + return i; + } + + return -1; +} + + +char * +wf_chspec_ntoa(chanspec_t chspec, char *buf) +{ + const char *band; + uint ctl_chan; + + if (wf_chspec_malformed(chspec)) + return NULL; + + band = ""; + + + if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || + (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) + band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; + + + ctl_chan = wf_chspec_ctlchan(chspec); + + + if (CHSPEC_IS20(chspec)) { + snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); + } else if (!CHSPEC_IS8080(chspec)) { + const char *bw; + const char *sb = ""; + + bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; + +#ifdef CHANSPEC_NEW_40MHZ_FORMAT + + if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { + sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; + } + + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); +#else + + if (CHSPEC_IS40(chspec)) { + sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; + snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); + } else { + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); + } +#endif + + } else { + + uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; + uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; + + + chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; + chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; + + + snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); + } + + return (buf); +} + +static int +read_uint(const char **p, unsigned int *num) +{ + unsigned long val; + char *endp = NULL; + + val = strtoul(*p, &endp, 10); + + if (endp == *p) + return 0; + + + *p = endp; + + *num = (unsigned int)val; + + return 1; +} + + +chanspec_t +wf_chspec_aton(const char *a) +{ + chanspec_t chspec; + uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; + uint num, ctl_ch; + uint ch1, ch2; + char c, sb_ul = '\0'; + int i; + + bw = 20; + chspec_sb = 0; + chspec_ch = ch1 = ch2 = 0; + + + if (!read_uint(&a, &num)) + return 0; + + + c = tolower((int)a[0]); + if (c == 'g') { + a ++; + + + if (num == 2) + chspec_band = WL_CHANSPEC_BAND_2G; + else if (num == 5) + chspec_band = WL_CHANSPEC_BAND_5G; + else + return 0; + + + if (!read_uint(&a, &ctl_ch)) + return 0; + + c = tolower((int)a[0]); + } + else { + + ctl_ch = num; + chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + } + + if (c == '\0') { + + chspec_bw = WL_CHANSPEC_BW_20; + goto done_read; + } + + a ++; + + + if (c == 'u' || c == 'l') { + sb_ul = c; + chspec_bw = WL_CHANSPEC_BW_40; + goto done_read; + } + + + if (c != '/') + return 0; + + + if (!read_uint(&a, &bw)) + return 0; + + + if (bw == 20) { + chspec_bw = WL_CHANSPEC_BW_20; + } else if (bw == 40) { + chspec_bw = WL_CHANSPEC_BW_40; + } else if (bw == 80) { + chspec_bw = WL_CHANSPEC_BW_80; + } else if (bw == 160) { + chspec_bw = WL_CHANSPEC_BW_160; + } else { + return 0; + } + + + + c = tolower((int)a[0]); + + + if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { + if (c == 'u' || c == 'l') { + a ++; + sb_ul = c; + goto done_read; + } + } + + + if (c == '+') { + + static const char *plus80 = "80/"; + + + chspec_bw = WL_CHANSPEC_BW_8080; + + a ++; + + + for (i = 0; i < 3; i++) { + if (*a++ != *plus80++) { + return 0; + } + } + + + if (!read_uint(&a, &ch1)) + return 0; + + + if (a[0] != '-') + return 0; + a ++; + + + if (!read_uint(&a, &ch2)) + return 0; + } + +done_read: + + while (a[0] == ' ') { + a ++; + } + + + if (a[0] != '\0') + return 0; + + + + + if (sb_ul != '\0') { + if (sb_ul == 'l') { + chspec_ch = UPPER_20_SB(ctl_ch); + chspec_sb = WL_CHANSPEC_CTL_SB_LLL; + } else if (sb_ul == 'u') { + chspec_ch = LOWER_20_SB(ctl_ch); + chspec_sb = WL_CHANSPEC_CTL_SB_LLU; + } + } + + else if (chspec_bw == WL_CHANSPEC_BW_20) { + chspec_ch = ctl_ch; + chspec_sb = WL_CHANSPEC_CTL_SB_NONE; + } + + else if (chspec_bw != WL_CHANSPEC_BW_8080) { + + const uint8 *center_ch = NULL; + int num_ch = 0; + int sb = -1; + + if (chspec_bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + } else { + return 0; + } + + for (i = 0; i < num_ch; i ++) { + sb = channel_to_sb(center_ch[i], ctl_ch, bw); + if (sb >= 0) { + chspec_ch = center_ch[i]; + chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; + break; + } + } + + + if (sb < 0) { + return 0; + } + } + + else { + int ch1_id = 0, ch2_id = 0; + int sb; + + ch1_id = channel_80mhz_to_id(ch1); + ch2_id = channel_80mhz_to_id(ch2); + + + if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0) + return 0; + + + chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | + ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); + + + + + sb = channel_to_sb(ch1, ctl_ch, bw); + if (sb < 0) { + + sb = channel_to_sb(ch2, ctl_ch, bw); + if (sb < 0) { + + return 0; + } + + sb += 4; + } + + chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; + } + + chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); + + if (wf_chspec_malformed(chspec)) + return 0; + + return chspec; +} + + +bool +wf_chspec_malformed(chanspec_t chanspec) +{ + uint chspec_bw = CHSPEC_BW(chanspec); + uint chspec_ch = CHSPEC_CHANNEL(chanspec); + + + if (CHSPEC_IS2G(chanspec)) { + + if (chspec_bw != WL_CHANSPEC_BW_20 && + chspec_bw != WL_CHANSPEC_BW_40) { + return TRUE; + } + } else if (CHSPEC_IS5G(chanspec)) { + if (chspec_bw == WL_CHANSPEC_BW_8080) { + uint ch1_id, ch2_id; + + + ch1_id = CHSPEC_CHAN1(chanspec); + ch2_id = CHSPEC_CHAN2(chanspec); + if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) + return TRUE; + + + if (ch2_id <= ch1_id) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || + chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { + + if (chspec_ch > MAXCHANNEL) { + return TRUE; + } + } else { + + return TRUE; + } + } else { + + return TRUE; + } + + + if (chspec_bw == WL_CHANSPEC_BW_20) { + if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_40) { + if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_80) { + if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) + return TRUE; + } + + return FALSE; +} + + +bool +wf_chspec_valid(chanspec_t chanspec) +{ + uint chspec_bw = CHSPEC_BW(chanspec); + uint chspec_ch = CHSPEC_CHANNEL(chanspec); + + if (wf_chspec_malformed(chanspec)) + return FALSE; + + if (CHSPEC_IS2G(chanspec)) { + + if (chspec_bw == WL_CHANSPEC_BW_20) { + if (chspec_ch >= 1 && chspec_ch <= 14) + return TRUE; + } else if (chspec_bw == WL_CHANSPEC_BW_40) { + if (chspec_ch >= 3 && chspec_ch <= 11) + return TRUE; + } + } else if (CHSPEC_IS5G(chanspec)) { + if (chspec_bw == WL_CHANSPEC_BW_8080) { + uint16 ch1, ch2; + + ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; + ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; + + + if (ch2 > ch1 + CH_80MHZ_APART) + return TRUE; + } else { + const uint8 *center_ch; + uint num_ch, i; + + if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + } else if (chspec_bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + } else { + + return FALSE; + } + + + if (chspec_bw == WL_CHANSPEC_BW_20) { + + for (i = 0; i < num_ch; i ++) { + if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || + chspec_ch == (uint)UPPER_20_SB(center_ch[i])) + break; + } + + if (i == num_ch) { + + if (chspec_ch == 165) + i = 0; + + + if (chspec_ch == 34 || chspec_ch == 38 || + chspec_ch == 42 || chspec_ch == 46) + i = 0; + } + } else { + + for (i = 0; i < num_ch; i ++) { + if (chspec_ch == center_ch[i]) + break; + } + } + + if (i < num_ch) { + + return TRUE; + } + } + } + + return FALSE; +} + + +uint8 +wf_chspec_ctlchan(chanspec_t chspec) +{ + uint center_chan; + uint bw_mhz; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + + + if (CHSPEC_IS20(chspec)) { + return CHSPEC_CHANNEL(chspec); + } else { + sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; + + if (CHSPEC_IS8080(chspec)) { + bw_mhz = 80; + + if (sb < 4) { + center_chan = CHSPEC_CHAN1(chspec); + } + else { + center_chan = CHSPEC_CHAN2(chspec); + sb -= 4; + } + + + center_chan = wf_5g_80m_chans[center_chan]; + } + else { + bw_mhz = bw_chspec_to_mhz(chspec); + center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; + } + + return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); + } +} + + +chanspec_t +wf_chspec_ctlchspec(chanspec_t chspec) +{ + chanspec_t ctl_chspec = chspec; + uint8 ctl_chan; + + ASSERT(!wf_chspec_malformed(chspec)); + + + if (!CHSPEC_IS20(chspec)) { + ctl_chan = wf_chspec_ctlchan(chspec); + ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; + ctl_chspec |= CHSPEC_BAND(chspec); + } + return ctl_chspec; +} + + +uint16 +wf_channel2chspec(uint ctl_ch, uint bw) +{ + uint16 chspec; + const uint8 *center_ch = NULL; + int num_ch = 0; + int sb = -1; + int i = 0; + + chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + + chspec |= bw; + + if (bw == WL_CHANSPEC_BW_40) { + center_ch = wf_5g_40m_chans; + num_ch = WF_NUM_5G_40M_CHANS; + bw = 40; + } else if (bw == WL_CHANSPEC_BW_80) { + center_ch = wf_5g_80m_chans; + num_ch = WF_NUM_5G_80M_CHANS; + bw = 80; + } else if (bw == WL_CHANSPEC_BW_160) { + center_ch = wf_5g_160m_chans; + num_ch = WF_NUM_5G_160M_CHANS; + bw = 160; + } else if (bw == WL_CHANSPEC_BW_20) { + chspec |= ctl_ch; + return chspec; + } else { + return 0; + } + + for (i = 0; i < num_ch; i ++) { + sb = channel_to_sb(center_ch[i], ctl_ch, bw); + if (sb >= 0) { + chspec |= center_ch[i]; + chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); + break; + } + } + + + if (sb < 0) { + return 0; + } + + return chspec; +} + + +extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) +{ + chanspec_t chspec40 = chspec; + uint center_chan; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + + if (CHSPEC_IS80(chspec)) { + center_chan = CHSPEC_CHANNEL(chspec); + sb = CHSPEC_CTL_SB(chspec); + + if (sb == WL_CHANSPEC_CTL_SB_UL) { + + sb = WL_CHANSPEC_CTL_SB_L; + center_chan += CH_20MHZ_APART; + } else if (sb == WL_CHANSPEC_CTL_SB_UU) { + + sb = WL_CHANSPEC_CTL_SB_U; + center_chan += CH_20MHZ_APART; + } else { + + + center_chan -= CH_20MHZ_APART; + } + + + chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | + sb | center_chan); + } + + return chspec40; +} + + +int +wf_mhz2channel(uint freq, uint start_factor) +{ + int ch = -1; + uint base; + int offset; + + + if (start_factor == 0) { + if (freq >= 2400 && freq <= 2500) + start_factor = WF_CHAN_FACTOR_2_4_G; + else if (freq >= 5000 && freq <= 6000) + start_factor = WF_CHAN_FACTOR_5_G; + } + + if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) + return 14; + + base = start_factor / 2; + + + if ((freq < base) || (freq > base + 1000)) + return -1; + + offset = freq - base; + ch = offset / 5; + + + if (offset != (ch * 5)) + return -1; + + + if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) + return -1; + + return ch; +} + + +int +wf_channel2mhz(uint ch, uint start_factor) +{ + int freq; + + if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || + (ch > 200)) + freq = -1; + else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) + freq = 2484; + else + freq = ch * 5 + start_factor / 2; + + return freq; +} + + + +chanspec_t +wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan1, uint8 chan2) +{ + int sb = 0; + uint16 chanspec = 0; + int chan1_id = 0, chan2_id = 0; + + + sb = channel_to_sb(chan1, primary_20mhz, 80); + if (sb < 0) { + + sb = channel_to_sb(chan2, primary_20mhz, 80); + if (sb < 0) { + + return INVCHANSPEC; + } + + sb += 4; + } + chan1_id = channel_80mhz_to_id(chan1); + chan2_id = channel_80mhz_to_id(chan2); + if (chan1_id == -1 || chan2_id == -1) + return INVCHANSPEC; + + chanspec = (chan1_id << WL_CHANSPEC_CHAN1_SHIFT)| + (chan2_id << WL_CHANSPEC_CHAN2_SHIFT)| + (sb << WL_CHANSPEC_CTL_SB_SHIFT)| + (WL_CHANSPEC_BW_8080)| + (WL_CHANSPEC_BAND_5G); + + return chanspec; + +} + + +static uint8 +wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id) +{ + if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS) + return wf_5g_80m_chans[chan_80Mhz_id]; + + return 0; +} + + + +uint8 +wf_chspec_primary80_channel(chanspec_t chanspec) +{ + uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, primary80_chan = 0; + int sb = 0; + + primary_20mhz = wf_chspec_ctlchan(chanspec); + + if (CHSPEC_IS80(chanspec)) { + primary80_chan = CHSPEC_CHANNEL(chanspec); + } + else if (CHSPEC_IS8080(chanspec)) { + chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); + chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); + + + sb = channel_to_sb(chan1, primary_20mhz, 80); + if (sb < 0) { + + sb = channel_to_sb(chan2, primary_20mhz, 80); + if (!(sb < 0)) { + primary80_chan = chan2; + } + } + else { + primary80_chan = chan1; + } + } + else if (CHSPEC_IS160(chanspec)) { + chan1 = CHSPEC_CHANNEL(chanspec); + sb = channel_to_sb(chan1, primary_20mhz, 160); + if (!(sb < 0)) { + + if (sb < 4) { + primary80_chan = chan1 - CH_40MHZ_APART; + } + + else + { + primary80_chan = chan1 + CH_40MHZ_APART; + } + } + } + else { + + primary80_chan = -1; + } + return primary80_chan; +} + + +uint8 +wf_chspec_secondary80_channel(chanspec_t chanspec) +{ + uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, secondary80_chan = 0; + int sb = 0; + + primary_20mhz = wf_chspec_ctlchan(chanspec); + if (CHSPEC_IS80(chanspec)) { + secondary80_chan = -1; + } + else if (CHSPEC_IS8080(chanspec)) { + chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); + chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); + + + sb = channel_to_sb(chan1, primary_20mhz, 80); + if (sb < 0) { + + sb = channel_to_sb(chan2, primary_20mhz, 80); + if (!(sb < 0)) { + secondary80_chan = chan1; + } + } + else { + secondary80_chan = chan2; + } + } + else if (CHSPEC_IS160(chanspec)) { + chan1 = CHSPEC_CHANNEL(chanspec); + sb = channel_to_sb(chan1, primary_20mhz, 160); + if (!(sb < 0)) { + + if (sb < 4) { + secondary80_chan = chan1 + CH_40MHZ_APART; + } + + else + { + secondary80_chan = chan1 - CH_40MHZ_APART; + } + } + } + else { + + secondary80_chan = -1; + } + return secondary80_chan; +} + + +chanspec_t +wf_chspec_primary80_chspec(chanspec_t chspec) +{ + chanspec_t chspec80; + uint center_chan, chan1 = 0, chan2 = 0; + uint sb; + + ASSERT(!wf_chspec_malformed(chspec)); + if (CHSPEC_IS8080(chspec)) { + chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); + chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec)); + + sb = CHSPEC_CTL_SB(chspec); + + if (sb < 4) { + + center_chan = chan1; + } + else + { + + center_chan = chan2; + sb -= 4; + } + + chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 |sb | center_chan); + } + else if (CHSPEC_IS160(chspec)) { + center_chan = CHSPEC_CHANNEL(chspec); + sb = CHSPEC_CTL_SB(chspec); + + if (sb < 4) { + + center_chan -= CH_40MHZ_APART; + } + else + { + + center_chan += CH_40MHZ_APART; + sb -= 4; + } + + chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); + } + else + { + chspec80 = INVCHANSPEC; + } + return chspec80; +}
diff --git a/src/shared/miniopt.c b/src/shared/miniopt.c new file mode 100644 index 0000000..57ffa1b --- /dev/null +++ b/src/shared/miniopt.c
@@ -0,0 +1,145 @@ +/* + * Description. + * + * $Copyright Open Broadcom Corporation$ + * $Id: miniopt.c 310902 2012-01-26 19:45:33Z $ + */ + +/* ---- Include Files ---------------------------------------------------- */ + +#include <typedefs.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <miniopt.h> + + +/* ---- Public Variables ------------------------------------------------- */ +/* ---- Private Constants and Types -------------------------------------- */ + + + +/* ---- Private Variables ------------------------------------------------ */ +/* ---- Private Function Prototypes -------------------------------------- */ +/* ---- Functions -------------------------------------------------------- */ + +/* ----------------------------------------------------------------------- */ +void +miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags) +{ + static const char *null_flags = ""; + + memset(t, 0, sizeof(miniopt_t)); + t->name = name; + if (flags == NULL) + t->flags = null_flags; + else + t->flags = flags; + t->longflags = longflags; +} + + +/* ----------------------------------------------------------------------- */ +int +miniopt(miniopt_t *t, char **argv) +{ + int keylen; + char *p, *eq, *valstr, *endptr = NULL; + int err = 0; + + t->consumed = 0; + t->positional = FALSE; + memset(t->key, 0, MINIOPT_MAXKEY); + t->opt = '\0'; + t->valstr = NULL; + t->good_int = FALSE; + valstr = NULL; + + if (*argv == NULL) { + err = -1; + goto exit; + } + + p = *argv++; + t->consumed++; + + if (!t->opt_end && !strcmp(p, "--")) { + t->opt_end = TRUE; + if (*argv == NULL) { + err = -1; + goto exit; + } + p = *argv++; + t->consumed++; + } + + if (t->opt_end) { + t->positional = TRUE; + valstr = p; + } + else if (!strncmp(p, "--", 2)) { + eq = strchr(p, '='); + if (eq == NULL && !t->longflags) { + fprintf(stderr, + "%s: missing \" = \" in long param \"%s\"\n", t->name, p); + err = 1; + goto exit; + } + keylen = eq ? (eq - (p + 2)) : (int)strlen(p) - 2; + if (keylen > 63) keylen = 63; + memcpy(t->key, p + 2, keylen); + + if (eq) { + valstr = eq + 1; + if (*valstr == '\0') { + fprintf(stderr, + "%s: missing value after \" = \" in long param \"%s\"\n", + t->name, p); + err = 1; + goto exit; + } + } + } + else if (!strncmp(p, "-", 1)) { + t->opt = p[1]; + if (strlen(p) > 2) { + fprintf(stderr, + "%s: only single char options, error on param \"%s\"\n", + t->name, p); + err = 1; + goto exit; + } + if (strchr(t->flags, t->opt)) { + /* this is a flag option, no value expected */ + valstr = NULL; + } else { + if (*argv == NULL) { + fprintf(stderr, + "%s: missing value parameter after \"%s\"\n", t->name, p); + err = 1; + goto exit; + } + valstr = *argv; + argv++; + t->consumed++; + } + } else { + t->positional = TRUE; + valstr = p; + } + + /* parse valstr as int just in case */ + if (valstr) { + t->uval = (uint)strtoul(valstr, &endptr, 0); + t->val = (int)t->uval; + t->good_int = (*endptr == '\0'); + } + + t->valstr = valstr; + +exit: + if (err == 1) + t->opt = '?'; + + return err; +}
diff --git a/src/tools/Wifi_ASD_test/Makefile b/src/tools/Wifi_ASD_test/Makefile new file mode 100644 index 0000000..455777c --- /dev/null +++ b/src/tools/Wifi_ASD_test/Makefile
@@ -0,0 +1,37 @@ +ifndef SRCBASE + SRCBASE = ../.. +endif + +include ../../Makerules +include Makefile.inc + + + +ifneq ($(findstring x86,$(TARGETARCH)), x86) + DIRS= ${LIB} + else + DIRS= ${LIB} ${CA} ${CLI} +endif + +# Make exception for android +ifneq ($(findstring android_ndk,$(TARGETARCH)), ) + DIRS= ${LIB} +endif + +all: + for i in ${DIRS}; do \ + $(MAKE) -C $$i || exit 1; \ + done + +clean: + for i in ${DIRS}; do \ + $(MAKE) -C $$i clean || exit 1; \ + done + rm -rf ./dut/x86_mmx ./dut/arm_le + +release_bins: + for i in ${DIRS}; do \ + $(MAKE) -C $$i release_bins; \ + done + +.phony: all clean release_bins
diff --git a/src/tools/Wifi_ASD_test/Makefile.inc b/src/tools/Wifi_ASD_test/Makefile.inc new file mode 100755 index 0000000..ba21556 --- /dev/null +++ b/src/tools/Wifi_ASD_test/Makefile.inc
@@ -0,0 +1,42 @@ +ifndef SRCBASE + SRCBASE = ../.. +endif + +#include ../../Makerules + +LIB=lib +CA=ca +CLI=cli +UCC=ucc +MAKE=make + +CFLAGS = -g -O2 -D_REENTRANT -DWFA_WMM_EXT -DWFA_WMM_AC -DWFA_WMM_VOICE -DWFA_WMM_PS_EXT -Wall -I../inc $(GCINCS) -I$(SRCBASE)/wl/exe +CFLAGS += $(GCFLAGS) + +# include when DUT becomes test bed +#CFLAGS += -DWFA_STA_TB +ifeq ($(TARGETENV), android) +CFLAGS += -DTARGETENV_android +endif + +ifeq ($(TARGETENV), android_ndk_r6b) +CFLAGS += -DTARGETENV_android +CFLAGS += -fno-short-enums +endif + +CALIBS = ../lib/$(TARGETARCH)/libwfa_ca.a -lpthread +RANLIB := $(if $(findstring android,$(TARGETENV)),$(TARGET_PREFIX))ranlib + +LIBWFA_NAME_CA =./$(TARGETARCH)/libwfa_ca.a +LIBWFA_NAME =./$(TARGETARCH)/libwfa.a + + +LIB_OBJS = ./$(TARGETARCH)/wfa_sock.o ./$(TARGETARCH)/wfa_tg.o ./$(TARGETARCH)/wfa_miscs_linux.o ./$(TARGETARCH)/wfa_cs.o ./$(TARGETARCH)/wfa_ca_resp.o ./$(TARGETARCH)/wfa_tlv.o ./$(TARGETARCH)/wfa_cmdtbl.o ./$(TARGETARCH)/wfa_cmdproc.o ./$(TARGETARCH)/wfa_miscs.o ./$(TARGETARCH)/wfa_thr.o ./$(TARGETARCH)/wfa_wmmps.o ./$(TARGETARCH)/wfa_wmmps_linux.o ../dut/$(TARGETARCH)/wfa_dut.o ../dut/$(TARGETARCH)/wfa_dut_init.o ./$(TARGETARCH)/wfa_typestr.o + + +LIB_OBJS_CA = wfa_sock.o wfa_tlv.o wfa_ca.o wfa_ca_resp.o wfa_cmdproc.o wfa_miscs.o wfa_miscs_linux.o wfa_cmdtbl.o wfa_thr.o wfa_wmmps.o wfa_wmmps_linux.o wfa_typestr.o + + +CLEANFILES = core core.* *.core.* *.o *.a + +INSTALL_DIR ?= apps
diff --git a/src/tools/Wifi_ASD_test/ca/Makefile b/src/tools/Wifi_ASD_test/ca/Makefile new file mode 100644 index 0000000..13c862b --- /dev/null +++ b/src/tools/Wifi_ASD_test/ca/Makefile
@@ -0,0 +1,24 @@ +ifndef SRCBASE + SRCBASE = ../../.. +endif + +include ../../../Makerules +include ../Makefile.inc + +# This should be one of values recognized in src/Makerules + +PROGS = wfa_ca + +all: ${PROGS} + +wfa_ca: wfa_ca.o wfa_ca_linux.o + ${CC} ${CFLAGS} -DDEBUG=1 -o $@ wfa_ca.o wfa_ca_linux.o ${CALIBS} + +clean: + rm -f ${PROGS} ${CLEANFILES} + +release_bins: + @mkdir -p $(INSTALL_DIR) + install ${PROGS} $(INSTALL_DIR) + +.phony: all clean release_bins
diff --git a/src/tools/Wifi_ASD_test/ca/wfa_ca.c b/src/tools/Wifi_ASD_test/ca/wfa_ca.c new file mode 100644 index 0000000..deeb131 --- /dev/null +++ b/src/tools/Wifi_ASD_test/ca/wfa_ca.c
@@ -0,0 +1,450 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +/* + * File: wfa_ca.c + * This is the main program for Control Agent. + * + * Revision History: + * 2006/06/01 -- BETA Release by qhu + * 2006/06/13 -- 00.02 Release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/09/01 -- 01.05 Release by qhu + * 2007/01/11 -- 01.10 released by qhu + * 2007/02/15 -- WMM beta released by qhu, mkaroshi + * 2007/03/21 -- 01.40 WPA2 and Official WMM Beta release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * -- on the calls wfaCtrlSend(), the string len is replaced with strlen() + */ +#include <stdio.h> /* for printf() and fprintf() */ +#include <stdlib.h> /* for atoi() and exit() */ +#include <string.h> + +#include "wfa_debug.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_cmds.h" +#include "wfa_sock.h" +#include "wfa_miscs.h" +#include "wfa_ca.h" +#include "wfa_agtctrl.h" +#include "wfa_agt.h" +#include "wfa_rsp.h" +#include "wfa_wmmps.h" + + +#define MAC_ADDR_LEN 18 +#define DEVICE_NAME_LEN 20 +#define TRANSPORT_TYPE_LEN 10 +#define SERVER_IP_LEN 20 +#define INTERFACE_NAME_LEN 31 +#define RESPONSE_SIZE 256 + +char gnetIf[WFA_BUFF_32]; /* specify the interface to use */ +int adj_latency; /* adjust sleep time due to latency */ +int isExit = 1; +int gRegSec = 1; /* regularly periodical timeout */ +int gtimeOut = 0; /* timeout value for select call in usec */ +int gSock = -1,xcSockfd = -1, gtgSend, gtgRecv, gtgTransac; +int rwl_wifi_flag = 0; /*Flag to check wheather the transport is wifi */ +BYTE *xcCmdBuf = NULL, *parmsVal = NULL, *trafficBuf = NULL, *respBuf = NULL; + +/* stream table */ +tgStream_t *gStreams; +struct timeval *toutvalp; + +#ifdef WFA_WMM_EXT +/* + * Thread Synchronize flags + */ +tgWMM_t wmm_thr[WFA_THREADS_NUM]; +extern void *wfa_wmm_thread(void *thr_param); +extern void *wfa_wmmps_thread(); +BOOL gtgStartSync = 0; /* flag to sync End2End Time handshaking */ +BOOL gtgFinishSync = 0; /* flag to sync End2End Time handshaking */ +double min_rttime = 0xFFFFFFFF; + +#ifdef WFA_WMM_PS_EXT +BOOL gtgWmmPS = 0; +unsigned long psTxMsg[WFA_BUFF_512]; +unsigned long psRxMsg[WFA_BUFF_512]; +extern int psSockfd ; +extern struct apts_msg apts_msgs[]; +extern void BUILD_APTS_MSG(int msg, unsigned long *txbuf); +extern int wfaWmmPowerSaveProcess(int sockfd); +void *g_wl_handle = NULL; + +int wl_set(void *wl, int cmd, void *buf, int len) +{ + return 0; +} +#endif /* WFA_WMM_PS_EXT */ +#endif /* WFA_WMM_EXT */ + + +#ifndef DONE +#define DONE 1 +#endif + +extern typeNameStr_t nameLocalStr[]; +/* For integration */ +extern dutCommandRespFuncPtr wfaCmdRespProcFuncTbl[]; +extern void buildDutCommandRespProcessTable(void); +extern typeNameStr_t nameStr[]; +extern char gRespStr[]; +extern sockfd_t gCaSockfd; +extern unsigned short wfa_defined_debug; +extern char* rwl_client_path; +extern xcCommandFuncPtr gWfaCmdFuncTbl[]; /* command process functions */ +extern char gCmdStr[]; +extern dutCmdResponse_t gGenericResp; +extern int clock_drift_ps; +extern int error_check(int errno_defined); +/* + * the output format can be redefined for file output. + */ +int +main(int argc, char *argv[]) +{ + char command[WFA_BUFF_1K], respStr[WFA_BUFF_128], cmdName[WFA_BUFF_32]; + char *pcmdStr, *trafficPath; + unsigned short myport; + int maxfdn1 = -1, nfds, i, isFound, DutCmd, nbytes = 0, tag, slen; + int cmdLen = WFA_BUFF_1K, respLen = 0; + int errno_defined; + int length_client_path; + sockfd_t tmsockfd; + BYTE xcCmdBuf[WFA_BUFF_1K], xcCmdTag, pcmdBuf[WFA_BUFF_1K]; + BYTE *respBuf = NULL, *parmsVal = NULL; + FILE* fp = NULL; + fd_set sockSet; + char *rwl_exe_path; + rwl_exe_path = malloc(WFA_BUFF_1K); + +/* CA assumes that wl.exe will be stored in the current working directory */ + get_rwl_exe_path(rwl_exe_path, WFA_BUFF_1K); + if (argc < 3) { + DPRINT_ERR(WFA_ERR, "Usage: %s <control agent IP (Win XP)/interface(linux) > <control port no> <--socket/--dongle/--wifi> <serverIp port/clientComport/serverMacaddr>\n", argv[0]); + return 0; + } + + /* isdigit() is not working with the build server tagged build + * so isdigit is replaced with isNumber() function call */ + + if (isNumber(argv[2]) == FALSE) { + DPRINT_ERR(WFA_ERR, "incorrect port number\n"); + return 0; + } + + myport = atoi(argv[2]); + + /* interface_validation call checks isString() for linux and + * isIPV4() for win32 OS + */ + if (interface_validation(argv[1]) == FALSE) { + DPRINT_ERR(WFA_ERR, "incorrect network interface\n"); + return 0; + } + + if((errno_defined = Start_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Start_Socket_Service failed\n"); + return 0; + } + + strncpy(gnetIf, argv[1], INTERFACE_NAME_LEN); /* For integration */ + + if ((rwl_client_path = malloc(WFA_BUFF_256))== NULL) { + DPRINT_ERR(WFA_ERR, "malloc failed\r\n"); + if((errno_defined = Stop_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Stop_Socket_Service failed\n"); + } + return 0; + } + + /* get the command line args to get the rwl exe working on different + * transport links - socket/dongle/wifi */ + + argv += 3; + strcpy(rwl_client_path, rwl_exe_path); + while (*argv) { + strncat(rwl_client_path, " ", 1); + strncat(rwl_client_path, *argv, strlen(*argv)); + *argv++; + } + length_client_path = strlen(rwl_client_path); + /* Look for wifi transport */ + if(strstr(rwl_client_path, "--wifi") != NULL) { + rwl_wifi_flag = 1; + } else { + rwl_wifi_flag = 0; + } + /* Allocate buffers */ + if ((parmsVal = malloc(MAX_PARMS_BUFF))== NULL) { + DPRINT_ERR(WFA_ERR, "malloc failed allocating parmsVal\n"); + if((errno_defined = Stop_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Stop_Socket_Service failed\n"); + } + return 0; + } + + if ((respBuf = malloc(WFA_BUFF_512))== NULL) { + DPRINT_ERR(WFA_ERR, "malloc failed allocating respBuf\n"); + if((errno_defined = Stop_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Stop_Socket_Service failed\n"); + } + free(parmsVal); + return 0; + } + DPRINT_INFO(WFA_OUT, "rwl_client_path = %s\n", rwl_client_path); + + + /* Create TCP socket for getting the commands from tc_cli */ + if ((tmsockfd = wfaCreateTCPServSock(myport))== -1) { + DPRINT_ERR(WFA_ERR, "Failed to open socket\n"); + if((errno_defined = Stop_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Stop_Socket_Service failed\n"); + } + return 0; + } + + maxfdn1 = tmsockfd + 1; + FD_ZERO(&sockSet); + + for (;;) + { + FD_ZERO(&sockSet); + FD_SET(tmsockfd, &sockSet); + maxfdn1 = tmsockfd + 1; + + if (gCaSockfd != -1) { + FD_SET(gCaSockfd, &sockSet); + if (maxfdn1 < (int)gCaSockfd) + maxfdn1 = gCaSockfd + 1; + } + /* + * The timer will be set for transaction traffic if no echo is back + * The timeout from the select call force to send a new packet + */ + nfds = 0; + if ((nfds = select(maxfdn1, &sockSet, NULL, NULL, NULL)) < 0) { + if (error_check(errno_defined)) + continue; + else + DPRINT_WARNING(WFA_WNG, "select error %i", errno_defined); + } + + DPRINT_INFO(WFA_OUT, "new event \n"); + + if (FD_ISSET(tmsockfd, &sockSet)) { + gCaSockfd = wfaAcceptTCPConn(tmsockfd); + DPRINT_INFO(WFA_OUT, "accept new connection\n"); + FD_SET(gCaSockfd, &sockSet); + } + + + if (gCaSockfd > 0 && FD_ISSET(gCaSockfd, &sockSet)) { + memset(xcCmdBuf, 0, WFA_BUFF_1K); + memset(gRespStr, 0, WFA_BUFF_512); + nbytes = wfaCtrlRecv(gCaSockfd, xcCmdBuf); + if (nbytes <= 0) { + asd_shutDown(gCaSockfd); + asd_closeSocket(gCaSockfd); + gCaSockfd = -1; + continue; + } + + memset(respStr, 0, WFA_BUFF_128); + sprintf(respStr, "status,RUNNING\r\n"); + wfaCtrlSend(gCaSockfd, (BYTE *)respStr, strlen(respStr)); + /* WFA Comment :having this is for slowing down unexpected + * output result on CLI command sometimes + */ + asd_sleep(1); + DPRINT_INFO(WFA_OUT, "%s\n", respStr); + DPRINT_INFO(WFA_OUT, "message %s %i\n", xcCmdBuf, nbytes); + slen = (int )strlen((char *)xcCmdBuf); + strncpy(command, (char*)xcCmdBuf, strlen((char*)xcCmdBuf)); + /* The carriage return and newline character need to be + * removed before sending the command to the DUT for the TCL + * scripts to run correctly. + */ + strtok(command, "\r\n"); + DPRINT_INFO(WFA_OUT, "last %x last-1 %x last-2 %x last-3 %x\n", cmdName[slen], cmdName[slen-1], cmdName[slen-2], cmdName[slen-3]); + + xcCmdBuf[slen-3] = '\0'; + + isFound = 0; + DutCmd = 0; + /* tokenize for the command name. Rest of the command buffer + * is copied to pcmdStr for command processing later. + */ + memcpy(cmdName, strtok_r((char *)xcCmdBuf, ",", (char **)&pcmdStr), 32); + i = 0; + /* Check if we need to execute the command using rwl client */ + while (nameStr[i].type != -1) { + if ((strcmp(nameStr[i].name, cmdName) == 0)) { + DutCmd = 1; /* Execute the command on the server e.g tg commands */ + break; + } + i++; + } + + /* Search for the command to be executed using rwl client */ + if (!DutCmd) { + i = 0; + while (nameLocalStr[i].type != -1) { + if ((strcmp(nameLocalStr[i].name, cmdName) == 0)) { + /* Found a command to be executed using rwl client */ + isFound = 1; + break; + } + i++; + } + } /* !DutCmd */ + + DPRINT_INFO(WFA_OUT, "cmdName is %s\n", cmdName); + + memset(pcmdBuf, 0, WFA_BUFF_1K); + + /* Check for the valid command and the valid arguements for the command + * and return STATUS INVLID for commands that do not exist or if the arguements + * for the command are invalid. + */ + if ((!isFound && !DutCmd) + || (DutCmd && (nameStr[i].cmdProcFunc(pcmdStr, pcmdBuf, &cmdLen)==FALSE)) + || (!DutCmd && (nameLocalStr[i].cmdProcFunc(pcmdStr, pcmdBuf, &cmdLen)==FALSE))) { + asd_sleep(1); + sprintf(respStr, "status,INVALID\r\n"); + wfaCtrlSend(gCaSockfd, (BYTE *)respStr, WFA_BUFF_128);/* Buffer size modified from strlen(respStr) on 21/11/07 */ + DPRINT_WARNING(WFA_WNG, "Incorrect command syntax\n"); + continue; + } + /* + * Decode the command that is parsed above to find the actual function pointer + * that needs to be executed. (decode for xcCmdTag ) + * Commands that use rwl client are processed here. + */ + if (!DutCmd && isFound) { + /* reset two commond storages used by control functions */ + wfaDecodeTLV(pcmdBuf, cmdLen, &xcCmdTag, &cmdLen, parmsVal); + memset(respBuf, 0, WFA_BUFF_512); + respLen = 0; + + /* reset two commond storages used by control functions */ + memset(gCmdStr, 0, WFA_CMD_STR_SZ); + /* command process function defined in wfa_cs.c or wfa_tg.c */ + gWfaCmdFuncTbl[xcCmdTag](cmdLen, parmsVal, &respLen, (BYTE *)respBuf); + + tag = ((wfaTLV *)respBuf)->tag; + + DPRINT_INFO(WFA_OUT, "bytes=%i,%i,%x %x %x %x \n", ((wfaTLV *)respBuf)->tag,((wfaTLV *)respBuf)->len, *(respBuf+4), *(respBuf+5), *(respBuf+6), *(respBuf+7)); + + DPRINT_INFO(WFA_OUT, "tag %i \n", tag-WFA_STA_COMMANDS_END); + + /* Response for the executed command is updated using the below function pointer + * table + */ + if ((tag != 0 && tag < WFA_STA_RESPONSE_END) && + wfaCmdRespProcFuncTbl[tag-WFA_STA_COMMANDS_END] != NULL) { + wfaCmdRespProcFuncTbl[tag-WFA_STA_COMMANDS_END](respBuf); + } else { + DPRINT_WARNING(WFA_WNG, "function not defined\n"); + memset(respBuf, 0, sizeof (respBuf)); + memset(pcmdBuf, 0, sizeof (pcmdBuf)); + } + } else { + /* Commands that need to be executed at DUT are processed here + * TG commands for example + */ + /*In case of Multiple streams the commands will have space after each + * streamid. So Look for \n for the end of command. + */ + strtok(command, "\n"); + trafficPath = malloc(WFA_BUFF_1K); + strcpy(trafficPath, rwl_client_path); + + /* e.g wl --socket <IP Addr> <Port no> asd ca_get_version */ + strncat(trafficPath, " asd ", 5); + strncat(trafficPath, command, strlen(command)); + strncat(trafficPath, " > ", 3); + if ((fp = asd_cmd_exec(trafficPath)) == NULL) + continue; + memset(trafficPath, 0, WFA_BUFF_1K); + + if (fread(trafficPath, sizeof(char), RESPONSE_SIZE, fp) <= 0) + strcpy(trafficPath, "status,ERROR\r\n"); + + DPRINT_INFO(WFA_OUT, "%s %d\n", trafficPath, strlen(trafficPath)); + + wfaCtrlSend(gCaSockfd, (BYTE *)trafficPath, strlen(trafficPath)); + file_cleanup(fp); + + memset(command, 0, strlen(command)); + free(trafficPath); + + } /* DutCmd */ + } /* done with if(gCaSockfd) */ + } /* for */ + if((errno_defined = Stop_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Stop_Socket_Service failed\n"); + } + asd_closeSocket(gCaSockfd); + return 0; +}
diff --git a/src/tools/Wifi_ASD_test/ca/wfa_ca_linux.c b/src/tools/Wifi_ASD_test/ca/wfa_ca_linux.c new file mode 100755 index 0000000..1ac0e65 --- /dev/null +++ b/src/tools/Wifi_ASD_test/ca/wfa_ca_linux.c
@@ -0,0 +1,78 @@ +/* + * Linux port of asd command line utility + * + * Copyright 2002, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied or + * duplicated in any form, in whole or in part, without the prior written + * permission of Broadcom Corporation. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "wfa_debug.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_cmds.h" +#include "wfa_miscs.h" +#include "wfa_sock.h" +#include "wfa_ca.h" +#include "wfa_agtctrl.h" +#include "wfa_agt.h" +#include "wfa_rsp.h" +#include "wfa_wmmps.h" + +void +get_rwl_exe_path(char *rwl_exe_path, int exe_path_len) +{ + strncpy(rwl_exe_path, "./wl", exe_path_len); +} + +int +error_check(int errno_defined) +{ + if (errno == EINTR) + return TRUE; + else + return FALSE; +} + +FILE* +asd_cmd_exec(char * trafficPath) +{ + /* Execute the command through "wl" on the DUT, + * read the response into trafficPath and return the response + */ + FILE *fp; + strncat(trafficPath,TEMP_FILE_PATH, strlen(TEMP_FILE_PATH)); + system(trafficPath); + if ((fp = fopen(TEMP_FILE_PATH, "r+")) == NULL) { + DPRINT_ERR(WFA_ERR, "failed to open temp_file_path\n"); + free(trafficPath); + } + return fp; +} +void +file_cleanup(FILE *fp) +{ + char *trafficPath; + trafficPath = malloc(WFA_BUFF_1K); + fclose(fp); + strcpy(trafficPath,"rm -f "); + strncat(trafficPath,TEMP_FILE_PATH, strlen(TEMP_FILE_PATH)); + exec_process(trafficPath); + free(trafficPath); +} + +int +interface_validation(char *interfac) +{ + return isString(interfac); +}
diff --git a/src/tools/Wifi_ASD_test/ca/wfa_ca_win32.c b/src/tools/Wifi_ASD_test/ca/wfa_ca_win32.c new file mode 100755 index 0000000..4f7274b --- /dev/null +++ b/src/tools/Wifi_ASD_test/ca/wfa_ca_win32.c
@@ -0,0 +1,77 @@ +/* + * Windows port of asd command line utility + * + * Copyright 2002, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied or + * duplicated in any form, in whole or in part, without the prior written + * permission of Broadcom Corporation. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "wfa_debug.h" +#include "wfa_sock.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_cmds.h" +#include "wfa_miscs.h" +#include "wfa_ca.h" +#include "wfa_agtctrl.h" +#include "wfa_agt.h" +#include "wfa_rsp.h" +#include "wfa_wmmps.h" + +void +get_rwl_exe_path(char *rwl_exe_path, int exe_path_len) +{ + char *trafficPath; + trafficPath = malloc(WFA_BUFF_1K); + if(GetCurrentDirectory(WFA_BUFF_128,trafficPath) == 0) { + DPRINT_ERR(WFA_ERR, "Failed to get the Current path\n"); + free(trafficPath); + exit(1); + } + _snprintf(rwl_exe_path, exe_path_len, " \"%s/wl\" ", trafficPath); + free(trafficPath); +} + +int +error_check(int unused_err) +{ + DPRINT_ERR(WFA_ERR, "Doing error check %d\n", unused_err); + if (WSAGetLastError() == WSAEINTR) + return TRUE; + else + return FALSE; +} + +FILE* +asd_cmd_exec(char *trafficPath) +{ + FILE *fp; + if((fp = asd_Config(trafficPath,TEMP_FILE_PATH)) == NULL){ + DPRINT_ERR(WFA_ERR, "Command Execution Failed\n"); + free(trafficPath); + } + return fp; +} + +void +file_cleanup(FILE *fp) +{ + Cleanup_File(fp); +} + +int +interface_validation(char *interfac) +{ + return isIpV4Addr(interfac); +}
diff --git a/src/tools/Wifi_ASD_test/cli/Makefile b/src/tools/Wifi_ASD_test/cli/Makefile new file mode 100644 index 0000000..7e487e7 --- /dev/null +++ b/src/tools/Wifi_ASD_test/cli/Makefile
@@ -0,0 +1,25 @@ +ifndef SRCBASE + SRCBASE = ../../.. +endif + +include ../../../Makerules +include ../Makefile.inc + +PROGS = ca_cli tc_cli + +all: ${PROGS} + +ca_cli: ca_cli.o + ${CC} ${CFLAGS} -o $@ ca_cli.o ${CALIBS} + +tc_cli: tc_cli.o + ${CC} ${CFLAGS} -o $@ tc_cli.o ${CALIBS} + +clean: + rm -f ${PROGS} ${CLEANFILES} + +release_bins: + @mkdir -p $(INSTALL_DIR) + install ${PROGS} $(INSTALL_DIR) + +.phony: all clean release_bins
diff --git a/src/tools/Wifi_ASD_test/cli/ca_cli.c b/src/tools/Wifi_ASD_test/cli/ca_cli.c new file mode 100644 index 0000000..92d0281 --- /dev/null +++ b/src/tools/Wifi_ASD_test/cli/ca_cli.c
@@ -0,0 +1,213 @@ + +/**************************************************************************** + * (c) Copyright 2006 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated Wi-Fi + * contractors ("Authorized Licensees"). Authorized Licensees are hereby + * granted the limited right to use this software solely for noncommercial + * applications and solely for testing Wi-Fi equipment. Authorized Licensees + * may embed this software into their proprietary equipment and distribute this + * software with such equipment under a license with at least the same + * restrictions as contained in this License, including, without limitation, + * the disclaimer of warranty and limitation of liability, below. Other than + * expressly granted herein, this License is not transferable or sublicensable, + * and it does not extend to and may not be used with non-Wi-Fi applications. + * + * Commercial derivative works of this software or applications that use the + * Wi-Fi scripts generated by this software are NOT AUTHORIZED without specific + * prior written permission from Wi-Fi Alliance. + * + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi with a copy of such + * derivative works under a perpetual, payment-free license to use, modify, + * and distribute such derivative works for purposes of testing Wi-Fi equipment. + * + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +****************************************************************************** + */ + + +/* + * File: ca_cli.c + * This is the main program for sending a text string based command to + * Control Agent (see reference document). + * + * Revision History: + * 06/30/2006 -- 00.10 Release by qhu + * 09/01/2006 -- 01.05 Release by qhu + * 03/30/2007 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 04/20/2007 -- 02.00 WPA2 and Official WMM Release by qhu + */ + /* + * All the buffer size changed from 512 to MAX_CMD_BUFF(1024) + * + */ + +#ifndef WIN32 +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <errno.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#include "wfa_types.h" +#include "wfa_debug.h" +#include "wfa_sock.h" +#include "wfa_main.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_ca_resp.h" +#include "wfa_cmds.h" +#include "wfa_miscs.h" + +#define WFA_ENV_AGENT_IPADDR "WFA_ENV_CA_IPADDR" +#define WFA_ENV_CA_PORT "WFA_ENV_CA_PORT" + +extern int xcCmdProcGetVersion(unsigned char *parms); +unsigned short wfa_defined_debug = WFA_DEBUG_ERR; +int sock; + +char gnetIf[32]; +int gtgTransac; + +int +main(int argc, char *argv[]) +{ + struct sockaddr_in servAddr; + unsigned short servPort; + char *servIP = NULL, *tstr = NULL; + int bytesRcvd; + char cmdName[MAX_CMD_BUFF]; /* Modified as per BRCM ASD 1.3 */ + int isFound = 0; + int done, errno; + int byteSent; + int rspCnt = 0; + BYTE caCmdBuf[MAX_CMD_BUFF]; /* Modified as per BRCM ASD 1.3 */ + memset(caCmdBuf, 0, 512); + if ((argc != 2)) + { + DPRINT_ERR(WFA_ERR, "Usage: %s <command string>\n", argv[0]); + exit(1); + } + + if ((tstr = getenv("WFA_ENV_CA_IPADDR")) == NULL) + { + DPRINT_ERR(WFA_ERR, "Environment variable WFA_ENV_CA_IPADDR not set\n"); + exit(1); + } + + if (isIpV4Addr(tstr) == FALSE){ + DPRINT_ERR(WFA_ERR, "incorrect IP number\n"); + exit(1); + } + + servIP = tstr; + + + if ((tstr = getenv("WFA_ENV_CA_PORT")) == NULL) + { + DPRINT_ERR(WFA_ERR, "Environment variable WFA_ENV_CA_PORT not set\n"); + exit(1); + } + + if (isNumber(tstr) == FALSE){ + DPRINT_ERR(WFA_ERR, "incorrect port number\n"); + exit(1); + } + + if((errno = Start_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Start_Socket_Service failed\n"); + return 0; + } + + servPort = atoi(tstr); + + if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + DPRINT_ERR(WFA_ERR, "socket() failed"); + if((errno = Stop_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Stop_Socket_Service failed\n"); + } + return 0; + } + + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = inet_addr(servIP); + servAddr.sin_port = htons(servPort); + + if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) + { + DPRINT_ERR(WFA_ERR, "connect() failed"); + if((errno = Stop_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Stop_Socket_Service failed\n"); + } + return 0; + } + + isFound = 0; + + memset(cmdName, 0, MAX_CMD_BUFF); + + memcpy(cmdName, argv[1], MAX_CMD_BUFF); /* Modified as per BRCM ASD 1.3 */ + + strcat(cmdName, " \r\n"); + + byteSent = wfaCtrlSend(sock, (BYTE *)cmdName, strlen(cmdName)); + /* Modified as per BRCM ASD 1.3 */ + memset(caCmdBuf, 0, MAX_CMD_BUFF); + bytesRcvd = recv(sock, caCmdBuf, MAX_CMD_BUFF, 0); /* Modified as per BRCM ASD 1.3 */ + rspCnt++; + asd_sleep(1); + done = 1; + while (done) + { + printf("=======Response======\n"); + printf("%s\n", caCmdBuf); + asd_sleep(1); + if (strncmp("status,COMPLETE", (char *)caCmdBuf, 15) == 0 || + strncmp("status,INVALID", (char *)caCmdBuf, 14) == 0 || + strncmp("status,ERROR", (char *)caCmdBuf, 12) == 0) + { + break; + } + + if (rspCnt == 3) + break; + + + memset(caCmdBuf, 0, MAX_CMD_BUFF); + bytesRcvd = recv(sock, caCmdBuf, MAX_CMD_BUFF, 0); + /* Modified as per BRCM ASD 1.3 */ + rspCnt++; + } + asd_closeSocket(sock); + + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + if((errno = Stop_Socket_Service()) != 0){ + DPRINT_ERR(WFA_ERR, "Stop_Socket_Service failed\n"); + } + return 0; +}
diff --git a/src/tools/Wifi_ASD_test/cli/tc_cli.c b/src/tools/Wifi_ASD_test/cli/tc_cli.c new file mode 100644 index 0000000..e669d3f --- /dev/null +++ b/src/tools/Wifi_ASD_test/cli/tc_cli.c
@@ -0,0 +1,209 @@ +/**************************************************************************** + * (c) Copyright 2006 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated Wi-Fi + * contractors ("Authorized Licensees"). Authorized Licensees are hereby + * granted the limited right to use this software solely for noncommercial + * applications and solely for testing Wi-Fi equipment. Authorized Licensees + * may embed this software into their proprietary equipment and distribute this + * software with such equipment under a license with at least the same + * restrictions as contained in this License, including, without limitation, + * the disclaimer of warranty and limitation of liability, below. Other than + * expressly granted herein, this License is not transferable or sublicensable, + * and it does not extend to and may not be used with non-Wi-Fi applications. + * + * Commercial derivative works of this software or applications that use the + * Wi-Fi scripts generated by this software are NOT AUTHORIZED without specific + * prior written permission from Wi-Fi Alliance. + * + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi with a copy of such + * derivative works under a perpetual, payment-free license to use, modify, + * and distribute such derivative works for purposes of testing Wi-Fi equipment. + * + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +****************************************************************************** + */ + + +/* + * File: tc_cli.c + * This is the main program for sending a text string based command to + * Control Agent (see reference document). + * + * Revision History: + * 06/30/2006 -- 00.10 Release by qhu + * 09/01/2006 -- 01.01 Release by qhu + * 03/30/2007 -- 01.41 WPA2 and Official WMM Beta Release by qhu + * 04/20/2007 -- 02.00 WPA2 and Official WMM Release by qhu + */ +#ifndef WIN32 +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#include "wfa_debug.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_ca_resp.h" +#include "wfa_cmds.h" +#include "wfa_miscs.h" +#include "wfa_sock.h" + +#define WFA_ENV_TC_IPADDR "WFA_ENV_TC_IPADDR" +#define WFA_ENV_TC_PORT "WFA_ENV_TC_PORT" + +unsigned short wfa_defined_debug = WFA_DEBUG_ERR; + +extern int xcCmdProcGetVersion(unsigned char *parms); +int sock; +char gnetIf[32]; +int gtgTransac; + +int main(int argc, char *argv[]) +{ + struct sockaddr_in servAddr; + unsigned short servPort; + char *servIP = NULL, *tstr = NULL; + int bytesRcvd; + char cmdName[512]; + int isFound = 0; + int done; + int byteSent; + int rspCnt = 0; + + BYTE caCmdBuf[512]; + + /* Fixed buffer size by ISAAC EZER in Epson */ + int MAX_MESSAGE = 512; + + int MAX_RECEIVE = 512; + +#ifdef WIN32 + WORD wVersionRequested; + WSADATA wsaData; + int err; + memset(caCmdBuf, 0, 512); + wVersionRequested = MAKEWORD(1, 1); + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + return; + } +#endif + + + if ((argc != 2)) + { + fprintf(stderr, "Usage: %s <command string>\n", argv[0]); + exit(1); + } + + if ((tstr = getenv("WFA_ENV_TC_IPADDR")) == NULL) + { + printf("Environment variable WFA_ENV_TC_IPADDR not set\n"); + exit(1); + } + + if (isIpV4Addr(tstr) == FALSE) + return FALSE; + + servIP = tstr; + + + if ((tstr = getenv("WFA_ENV_TC_PORT")) == NULL) + printf("Environment variable WFA_ENV_TC_PORT not set\n"); + + if (isNumber(tstr) == FALSE) + return FALSE; + + servPort = atoi(tstr); + + if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + perror("socket() failed"); + exit(1); + } + + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = inet_addr(servIP); + servAddr.sin_port = htons(servPort); + + if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) + { + perror("connect() failed"); + exit(1); + } + + isFound = 0; + + memcpy(cmdName, argv[1], MAX_MESSAGE); + + /* Fixed by ISAAC - EZER */ + strcat(cmdName, " \r\n"); + byteSent = wfaCtrlSend(sock, (BYTE *)cmdName, MAX_MESSAGE); + + memset(caCmdBuf, '\0', sizeof(caCmdBuf)); + + bytesRcvd = recv(sock, caCmdBuf, MAX_RECEIVE, 0); + done = 1; + while (done) + { + + printf("=======Response======\n"); + printf("%s\n", caCmdBuf); + + if (strncmp("status,COMPLETE", (char *)caCmdBuf, 15) == 0 || + strncmp("status,INVALID", (char *)caCmdBuf, 14) == 0 || + strncmp("status,ERROR", (char *)caCmdBuf, 12) == 0) + break; + + if (rspCnt == 3) + break; + + /* ISAAC EZER - I modified this section */ + + bytesRcvd = recv(sock, caCmdBuf, MAX_RECEIVE, 0); + rspCnt++; + + if (bytesRcvd == -1) + { + perror("Error receiving message from Test Console.\n"); + break; + } + } + asd_closeSocket(sock); + + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ +#ifdef WIN32 + WSACleanup(); +#endif + exit(0); +}
diff --git a/src/tools/Wifi_ASD_test/dut/Makefile b/src/tools/Wifi_ASD_test/dut/Makefile new file mode 100644 index 0000000..751340d --- /dev/null +++ b/src/tools/Wifi_ASD_test/dut/Makefile
@@ -0,0 +1,16 @@ +ifndef SRCBASE + SRCBASE = ../../../ +endif + +include ../../../Makerules +include ../Makefile.inc + +DUT_OBJ= ./$(TARGETARCH)/wfa_dut.o ./$(TARGETARCH)/wfa_dut_init.o +all: ${DUT_OBJ} + +$(TARGETARCH)/%.o: %.c + @mkdir -p $(TARGETARCH) + $(CC) -c $(CFLAGS) -o $@ $^ + +clean: + rm -f ${PROGS} ${CLEANFILES}
diff --git a/src/tools/Wifi_ASD_test/dut/wfa_dut.c b/src/tools/Wifi_ASD_test/dut/wfa_dut.c new file mode 100644 index 0000000..6b76126 --- /dev/null +++ b/src/tools/Wifi_ASD_test/dut/wfa_dut.c
@@ -0,0 +1,1035 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors (“Authorized Licenseesâ€). Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee’s proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below. The distribution rights + * granted in clause (ii), above, include distribution to third party + * companies who will redistribute the Authorized Licensee’s product to their + * customers with or without such third party’s private label. Other than + * expressly granted herein, this License is not transferable or sublicensable, + * and it does not extend to and may not be used with non-Wi-Fi applications. + * Wi-Fi Alliance reserves all rights not expressly granted herein. + * + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. Non-Commercial derivative works of this software for + * internal use are authorized and are limited by the same restrictions; + * provided, however, that the Authorized Licensee shall provide Wi-Fi Alliance + * with a copy of such derivative works under a perpetual, payment-free license + * to use, modify, and distribute such derivative works for purposes of testing + * Wi-Fi equipment. + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * **************************************************************************** + */ + +/* + * File: wfa_dut.c - The main program for DUT agent. + * This is the top level of traffic control. It initializes a local TCP + * socket for command and control link and waits for a connect request + * from a Control Agent. Once the the connection is established, it + * will process the commands from the Control Agent. For details, please + * reference the architecture documents. + * + * Revision History: + * 2006/03/10 -- Initially created by qhu. + * 2006/06/01 -- BETA Release by qhu + * 2006/06/13 -- 00.02 Release by qhu + * 2006/06/30 -- 00.10 Official Release 00.10 by qhu + * 2006/07/10 -- 01.00 Official Release 01.00 by qhu + * 2006/09/01 -- 01.05 Release by qhu + * 2006/10/20 -- bug fix 1. replace MAX_TRAFFIC_BUG_SZ with MAX_UDP_LEN + * that could cause crash by mismatch buf size + * 2006/10/26 -- 01.06 replace all hardcoded buff sizes with global macro + * 2007/01/11 -- 01.10 released by qhu + * 2007/02/15 -- WMM-Extention Beta released by qhu, mkaroshi + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * + */ + +#ifndef WIN32 +#include <pthread.h> +#include <signal.h> +#include <time.h> +#include <semaphore.h> +#endif + +#include "wfa_debug.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_sock.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_miscs.h" +#include "wfa_agt.h" +#include "wfa_rsp.h" +#include "wfa_wmmps.h" +#include "wfa_cmds.h" +#include "wfa_agtctrl.h" +#include "wfa_ca.h" + + +char gRespStr[WFA_BUFF_1K], gnetIf[WFA_BUFF_32], gCmdStr[WFA_BUFF_512]; +char* rwl_client_path; + +unsigned short wfa_defined_debug = WFA_DEBUG_ERR | WFA_DEBUG_WARNING; +unsigned short dfd_lvl = WFA_DEBUG_DEFAULT | WFA_DEBUG_ERR; + + +int respLen = -1, tag = -1, ret_status = -1, bytesRcvd = -1, gRegSec, gtimeOut, adj_latency, g_pthrCreate =1, IPTVprof = 0, clock_drift_ps; +int gTCPsock = 0; +/* the agent local Socket, Agent Control socket and baseline test socket*/ +int gagtSockfd =-1 , gxcSockfd =-1, gCaSockfd = -1, btSockfd=-1 , psSockfd =-1, btRecvSockfd = -1, gTcpRecvSockfd = -1; +/* the WMM traffic streams socket fds - Socket Handler table */ +int tgSockfds[WFA_MAX_TRAFFIC_STREAMS]; +int e2eCnt; +int rwl_wifi_flag; + +unsigned long psTxMsg[WFA_BUFF_512], psRxMsg[WFA_BUFF_512]; + +double min_rttime ; + +/* Global flags for synchronizing the TG functions */ + +BOOL gtgSend ; /* flag to sync Send traffic */ +BOOL gtgRecv ; /* flag to sync Recv traffic */ +BOOL gtgTransac ; /* flag to sync Transaction traffic */ +BOOL gtgWmmPS ; +BOOL gtgStartSync ; /* flag to sync End2End Time handshaking */ +BOOL gtgFinishSync; /* flag to sync End2End Time handshaking */ +volatile int gTransactrunLoop; +extern struct apts_msg apts_msgs[]; +void tmout_stop_send(int); +int wfaWmmPowerSaveProcess(int sockfd); + +#ifdef WIN32 +HANDLE thr_flag_cond; +HANDLE thr_stop_cond; +xcCommandFuncPtr gWfaCmdFuncTbl[]; /* command process functions */ +dutCommandRespFuncPtr wfaCmdRespProcFuncTbl[]; /* command process functions */ +typeNameStr_t nameStr[]; +extern HANDLE g_recvEvent[] ; +extern HANDLE g_IPTVSndThr[]; +extern HANDLE send_event; +extern int usedThread ; +HANDLE g_RecvhThread; +HANDLE g_IPTVRecvhThread[WFA_MAX_TRAFFIC_STREAMS]; +void wfaRecvStart(); +extern HANDLE g_hRecvEvent ; +extern DWORD Win32_tmout_stop_send(LPVOID num ) ; +void wfaSetIPTVThreadPrio(HANDLE tid, short class); +void wfaIPTVRecvStart(LPVOID tblidx); +void SendIPTVFile(LPVOID strid); +extern void wfaTxSleepTime(int profile, int rate, int *sleepTime, int *throttledRate); +extern BYTE Send_dutResp[]; +#else +extern xcCommandFuncPtr gWfaCmdFuncTbl[]; /* command process functions */ +extern dutCommandRespFuncPtr wfaCmdRespProcFuncTbl[]; /* command process functions */ +extern typeNameStr_t nameStr[]; +#define THREAD_SLEEP_TIME 1000 +pthread_t Thread1 = -1; +void wfaIPTVRecvStart(void* tblidx); +void SendIPTVFile(void* strid); +extern void wfaSetThreadPrio(int tid, int class); +#endif + +dutCmdResponse_t gGenericResp; +tgStream_t *findStreamProfile(int); +tgStream_t *gStreams; /* streams' buffers */ +tgSyncTime_t gtgStartSyncTime; /* End2End Start Sync record */ +tgSyncTime_t gtgFinishSyncTime; /* End2End Finish Sync Record */ +tgE2EStats_t *e2eStats; + +#ifdef WFA_WMM_EXT +#ifndef WIN32 +extern void *wfa_wmm_thread(void *thr_param); +extern void *wfa_wmmps_thread();/* Added as per BRCM ASD 2.1 */ +sem_t sem_wmm; +sem_t sem_wmm_resp; +sem_t sem_gtgrecv; +sem_t sem_iptv_gtgrecv[WFA_MAX_TRAFFIC_STREAMS]; +#else +extern void Uapsd_Recv_Thread(void *thr_param); +#endif +tgWMM_t wmm_thr[WFA_THREADS_NUM]; +wfaWmmPS_t wmmps_info; +#endif + +int wfa_estimate_timer_latency(); +void wfaRecvThrCreate(void); +extern int wfaTGSetPrio(int sockfd, int tgClass); +void wfaSentStatsResp( BYTE *buf); +void wfaIPTVRecvThrCreate(int ); + +#ifdef WIN32 +void SendFile(LPVOID strid); +#else +void SendFile(void); +#endif +void bcmWfaInit(void); /* Added as per BRCM 1.3 ASD */ + +int maxfdn1 = -1; + + +fd_set sockSet; /* Set of socket descriptors for select() */ +struct sockfds fds; + +/* streams' buffers */ +extern BYTE *xcCmdBuf, *parmsVal , *trafficBuf, *respBuf ; +extern struct timeval *toutvalp; +extern char gRespStr[]; +extern int isString(char *); +extern int isNumber(char *); +extern unsigned short wfa_defined_debug; + +#ifndef DONE +#define DONE 1 +#endif + + +/* This is the main function that gets called from wl server + * command buffer (e.g) ca_get_version and length of the command. + * This is replacement of earlier main() function in the DUT + * However some of the earlier main function code is moved into + * different functions + */ +int remote_asd_exec(unsigned char* command, int* cmd_len) +{ + int cmdLen = WFA_BUFF_1K, index, isFound; + BYTE xcCmdTag, pcmdBuf[WFA_BUFF_1K]; + char *pcmdStr; + char tempbuf[WFA_BUFF_256], cmdName[WFA_BUFF_32]; + + DPRINT_INFO(WFA_OUT, " received: command %s. len %d.\n", command, *cmd_len); + + maxfdn1 = gagtSockfd + 1; + + /* set socket file descriptors. For baseline, there are only + * three sockets required. They are an agent main socket, + * Control Agent link socket and Traffic Generator Socket. + */ + fds.agtfd = &gagtSockfd; + fds.tgfd = &btSockfd; + /*btRecvSockfd added to receive the traffic for all the profiles + * and also support the Bi-directional profiles + */ + fds.tgRevfd = &btRecvSockfd; + fds.cafd = &gCaSockfd; + fds.wmmfds = tgSockfds; + +#ifdef WFA_WMM_PS_EXT + fds.psfd = &psSockfd; +#endif +#ifndef WIN32 + sem_init(&sem_wmm,0,0); + sem_init(&sem_wmm_resp,0,0); + sem_init(&sem_gtgrecv,0,0); + for(index=0; index < WFA_MAX_TRAFFIC_STREAMS; index++) { + sem_init(&sem_iptv_gtgrecv[index],0,0); + } +#endif + DPRINT_INFO(WFA_OUT, "gtgsend = %d, gtgrecv = %d, btSockfd = %d, btRecvSockfd = %d \n", gtgSend, gtgRecv, btSockfd, btRecvSockfd); + + + /* Receive the asd command here and then tokenize for the command name. Rest of the + * command buffer is copied to pcmdStr for command processing later. + */ + memset(xcCmdBuf, 0, WFA_BUFF_1K); + /*Look for the \n for the end of command*/ + strtok((char *)command, "\n"); + DPRINT_INFO(WFA_OUT, "message %s. %d\n", command, strlen((char *)command)); + strcpy(tempbuf, (char *)command); + strtok(tempbuf, ","); + memcpy(cmdName, strtok_r((char *)command, ",", (char **)&pcmdStr), strlen(tempbuf)); + /* The cmdName is appended with '\0' to get rid of the '\r\n' in the command*/ + cmdName[strlen(tempbuf)] = '\0'; + index = 0; + isFound = 0; + DPRINT_INFO(WFA_OUT, "cmdName %s\n pcmdStr is %s.\n", cmdName, pcmdStr); + /* To check for the command that needs to be executed + * we loop through a function pointer table and mark that as found. + */ + while (nameStr[index].type != -1) { + if (strcmp(nameStr[index].name, cmdName) == 0) { + isFound = 1; + break; + } + index++; + } + + memset(pcmdBuf, 0, WFA_BUFF_1K); + + /* If the command is not found or if the arguments are invalid, we return + * with invalid response. Otherwise, call for command proc functions where + * the parsing and encoding of the commands take place. + * The function definitions are found in wfa_cmdproc.c file + */ + if (!isFound || (nameStr[index].cmdProcFunc(pcmdStr, pcmdBuf, &cmdLen) == FALSE)) { + asd_sleep(1); + sprintf(gRespStr, "status,INVALID\n"); + DPRINT_INFO(WFA_OUT, "Incorrect command syntax\n"); + *cmd_len = strlen(gRespStr); + memcpy(command, gRespStr, *cmd_len); + return -1; + } + + /* Decode the command to get the tag of the command */ + wfaDecodeTLV(pcmdBuf, cmdLen, &xcCmdTag, &cmdLen, parmsVal); + memset(respBuf, 0, WFA_BUFF_512); + respLen = 0; + + DPRINT_INFO(WFA_OUT, "total %i cmdLen %i tag %i\n", cmdLen, cmdLen, xcCmdTag); + + /* reset two command storages used by control functions */ + memset(gCmdStr, 0, WFA_CMD_STR_SZ); + memset(&gGenericResp, 0, sizeof(dutCmdResponse_t)); + memset(gRespStr, 0, WFA_BUFF_1K); + + /* command process function defined in wfa_cs.c OR wfa_tg.c */ + gWfaCmdFuncTbl[xcCmdTag](cmdLen, parmsVal, &respLen, (BYTE *)respBuf); + + wfaSetSockFiDesc(&sockSet, &maxfdn1, &fds); + + /* If command is other than traffic send command then the reply goes + * from function pointer table in wfaCmdRespProcFuncTbl + * gRespStr variable gets updated there. + */ + + tag = ((wfaTLV *)respBuf)->tag; + memcpy(&ret_status, respBuf+4, 4); + DPRINT_INFO(WFA_OUT, "bytes=%i, %i,%i,%x %x %x %x \n", bytesRcvd, ((wfaTLV *)respBuf)->tag,((wfaTLV *)respBuf)->len, *(respBuf+4), *(respBuf+5), *(respBuf+6), *(respBuf+7)); + DPRINT_INFO(WFA_OUT, "tag %i \n", tag-WFA_STA_COMMANDS_END); + if ((tag != 0 && tag < WFA_STA_RESPONSE_END) && \ + wfaCmdRespProcFuncTbl[tag-WFA_STA_COMMANDS_END] != NULL) { + wfaCmdRespProcFuncTbl[tag-WFA_STA_COMMANDS_END](respBuf); + } + + /*Update the command with response buffer and cmd_Len with the response length */ + *cmd_len = strlen(gRespStr); + memset(command, 0, *cmd_len); + strncpy((char *)command, gRespStr, (size_t)strlen(gRespStr)); + DPRINT_INFO(WFA_OUT, " %s\n", command); + return 0; +} + +/* Dut receive is moved into this thread for waiting for the + * UDP packets to arrive in case of file transfer/Multicast (TG) + */ +void wfaRecvStart() +{ + int sn, n; + struct timeval ttval; +#ifndef WIN32 + struct timeval currTimeVal; +#else + unsigned long nonblocking = 1; + SYSTEMTIME currTimeVal; +#endif + +#ifdef WFA_DUT_SYNC + int traffic_start_drift; +#endif + +#ifdef WFA_WMM_EXT +#ifdef WFA_WMM_PS_EXT + /*Receiver for WMMPS traffic*/ + if(gtgWmmPS > 0){ + while (gtgWmmPS > 0) + if(psSockfd > 0 && FD_ISSET(psSockfd, &sockSet)) + wfaWmmPowerSaveProcess(psSockfd); + +#ifdef WIN32 + if(SetEvent(g_hRecvEvent) == 0){ + DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError()); + } + while ((WaitForSingleObject(g_RecvhThread, INFINITE) != WAIT_OBJECT_0)); + if(g_hRecvEvent != NULL) + CloseHandle(g_hRecvEvent); +#endif /* WIN32 */ + } + +#endif +#endif + /* calling accept for tcp conection */ + if(gTCPsock == 1 && btRecvSockfd == -1) + btRecvSockfd = wfaAcceptTCPConn(gTcpRecvSockfd); + +#ifdef WIN32 +#else + /*Recieve the traffic untill the user stops the traffic and resets gtgRecv flag*/ + while (gtgRecv) +#endif + { + int i = gtgRecv?gtgRecv:gtgTransac; + memset(trafficBuf, 0 , sizeof(trafficBuf)); + n = wfaRecvFile(btRecvSockfd, i, (char *)trafficBuf); + /* If it is testing transaction, once it receives a packet + * send a new one right away. + */ + if(n > 0) + { + if(gtgTransac != 0) + { + memset(respBuf, 0, WFA_BUFF_512); + respLen = 0; + + if(wfaSendShortFile(btRecvSockfd, gtgTransac, + trafficBuf, n, respBuf, &respLen) == DONE) + { + DPRINT_INFO(WFA_OUT,"Inform to stop\n"); + } + } + } + + if ((IPTVprof == 1) && (n !=0 )) { + sn = bigEndianBuff2Int(&((tgHeader_t *)trafficBuf)->hdr[8]); + ttval.tv_sec = bigEndianBuff2Int(&((tgHeader_t *)trafficBuf)->hdr[12]); + ttval.tv_usec = bigEndianBuff2Int(&((tgHeader_t *)trafficBuf)->hdr[16]); +#ifndef WIN32 + gettimeofday(&currTimeVal, NULL); +#else + GetSystemTime(&currTimeVal); +#endif + +#ifdef WFA_DUT_SYNC + /* + * If this is the beginning of the test from packet 10, + * re-adjust the clock for drifting + */ + if (sn >= 10 && sn < 15) + { + double bdftime = wfa_timeval2double(&currTimeVal) - gtgStartSyncTime.dut_time; + + if (bdftime > 10.00) + { + //Set the clock to the TM clock again (with delay) + currTimeVal.tv_sec = ttval.tv_sec; + currTimeVal.tv_usec = ttval.tv_usec + gtgStartSyncTime.dtime/2 * 1000000; + // plus drift + traffic_start_drift = clock_drift_ps * bdftime; + currTimeVal.tv_usec += traffic_start_drift; + if(currTimeVal.tv_usec < 0) + { + currTimeVal.tv_sec -=1; + currTimeVal.tv_usec += 1000000; + } + else if(currTimeVal.tv_usec >= 1000000) + { + currTimeVal.tv_sec += 1; + currTimeVal.tv_usec -= 1000000; + } + // clock reset + settimeofday(&currTimeVal, NULL); + } + } +#endif + /* + * take the end2end stats + */ + if (e2eCnt < 6000) + { + tgE2EStats_t *ep = &e2eStats[e2eCnt++]; + ep->seqnum = sn; + ep->rsec = ttval.tv_sec; + ep->rusec = ttval.tv_usec; +#ifndef WIN32 + ep->lsec = currTimeVal.tv_sec; + ep->lusec = currTimeVal.tv_usec; +#else + ep->lsec = currTimeVal.wSecond;; + ep->lusec = currTimeVal.wMilliseconds * 1000; +#endif + if(ep->lusec < 0) + { + ep->lsec -=1; + ep->lusec += 1000000; + } + else if(ep->lusec >= 1000000) + { + ep->lsec += 1; + ep->lusec -= 1000000; + } + } + } /* if(IPTVprof) */ + }/* while (gtgRecv) */ +#ifndef WIN32 + /* Sending signal to wfaTGRecvStop to close the socket + * since the receive is complete + */ + sem_post(&sem_gtgrecv); + + if ((pthread_kill(Thread1, 0)) < 0) + DPRINT_INFO(WFA_OUT,"\nRecvStart thread kill failed\n"); +#endif + if(btRecvSockfd != -1){ + DPRINT_INFO(WFA_OUT, "cloasing the recv socket \n"); + asd_closeSocket( btRecvSockfd); + btRecvSockfd = -1; + } + +} + +/*Create the thread for receiving the traffic from the TG in the case if File transfer, Multicast and Transaction profiles*/ +void wfaRecvThrCreate(void) +{ +#ifndef WIN32 + //pthread_t Thread1 = -1; + int thrId = -1; + /* Start the thread to receive */ + if((thrId = pthread_create(&Thread1, NULL, (void *)wfaRecvStart, NULL)) != 0) + { + DPRINT_ERR(WFA_OUT, "Error created Recv Thread\n"); + return; + } + DPRINT_INFO(WFA_OUT, "Created thread %d\n", thrId); +#else + DWORD RecvGenericThread; + g_RecvhThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wfaRecvStart, NULL, 0, &RecvGenericThread); + + if (g_RecvhThread == NULL){ + DPRINT_INFO(WFA_OUT, "g_RecvhThread not created\n"); + } else { + DPRINT_INFO(WFA_OUT, "thread priority = %d\n", GetThreadPriority(g_RecvhThread)); + SetThreadPriority(g_RecvhThread, THREAD_PRIORITY_NORMAL + 1); + } +#endif +} + + +/* Called by send commands of TG */ +#ifdef WIN32 +void SendFile(LPVOID strid) +#else +void SendFile(void) +#endif +{ +#ifdef WIN32 + DWORD errnum = 0; + unsigned long nonBlocking = 1; + int sleepTime = 0; + int throttledRate = 0; + int counter = -1; + int throttled_est_cost; + int act_sleep_time; + tgProfile_t *theProf = NULL; +#else + struct timeval lstime; +#endif + + int asn = 1, bytesrecv, i; + + int nfds; + struct timeval *tovalp; + fd_set socketSet; + tgStream_t *myStream = NULL; + /* + * If the profile is set for file transfer, this will run to + * complete (blocking). + */ +#ifdef WIN32 + gtgSend = (BOOL)strid; +#endif + if (gtgSend != 0 && gtgTransac == 0) { + + memset(respBuf, 0, WFA_BUFF_512); + respLen = 0; + myStream = findStreamProfile(gtgSend); + + if (myStream->profile.startdelay > 0 && myStream->profile.startdelay < 50) { + DPRINT_INFO(WFA_OUT, "sleeping for %d\n", myStream->profile.startdelay); + asd_sleep(myStream->profile.startdelay); + } +#ifndef WIN32 + signal(SIGALRM, tmout_stop_send); + alarm(myStream->profile.duration); +#endif + DPRINT_INFO(WFA_OUT, "sendlongfile btsockfd = %d gtgsend = %d\n", btSockfd, gtgSend); + /* For frame rate of zero pump data at high speed. */ + if (myStream->profile.rate != 0) + wfaSendLongFile(btSockfd, gtgSend, respBuf, &respLen ); + else + wfaImprovePerfSendLongFile(btSockfd, gtgSend, respBuf, &respLen ); + + if(btSockfd != -1){ + asd_closeSocket(btSockfd); + btSockfd= -1; + } + } + /* For transaction test, if it times out without receive a packet, + * here it should initiate/send the next transac packet and count + * a packet loss for the previous one + */ + if (gtgTransac != 0 ) { + gTransactrunLoop = 1; + memset(respBuf, 0, WFA_BUFF_512); + respLen = 0; + myStream = findStreamProfile(gtgSend); + + if (myStream->profile.startdelay > 0 && myStream->profile.startdelay < 50) { + DPRINT_INFO(WFA_OUT, "sleeping for %d\n", myStream->profile.startdelay); + asd_sleep(myStream->profile.startdelay); + } +#ifdef WIN32 + theProf = &myStream->profile; + if(theProf->duration != 0) + { + DPRINT_INFO(WFA_OUT, "duration %i\n", theProf->duration); + /* + * use this to decide periodical interval sleep time and frames to send + * int the each interval. + * Each device should adopt a own algorithm for better performance + */ + wfaTxSleepTime(theProf->profile, theProf->rate, &sleepTime, &throttledRate); + + /* + * Here assumes it takes 20 usec to send a packet and 20 usec to receive one + * Must estimate the cost per packet + * reused concept in SendLongFile in wfa_tg.c + */ + throttled_est_cost = throttledRate * 40; // MUST estimate the cost per ppk + act_sleep_time = sleepTime - throttled_est_cost; + if (act_sleep_time <= 0) + act_sleep_time = sleepTime; + + DPRINT_INFO(WFA_OUT, "sleep time %i act_sleep_time %i\n", sleepTime, act_sleep_time); + } +#endif + + while(gTransactrunLoop) + { + tovalp = NULL; + if(gtimeOut != 0 || gRegSec != 0) { + /* + * The timer will be set for transaction traffic if no echo is back + * The timeout from the select call force to send a new packet + */ + tovalp = wfaSetTimer(gRegSec, gtimeOut*1000, toutvalp); + } + + nfds = 0; + FD_ZERO(&socketSet); +#ifndef WIN32 + FD_SET(btSockfd, &socketSet); +#else + FD_SET((u_int)btSockfd, &socketSet); +#endif + if ( (nfds = select(maxfdn1, &socketSet, NULL, NULL, tovalp)) < 0) { +#ifndef WIN32 + if (errno == EINTR) +#else + if (WSAGetLastError() == WSAEINTR) +#endif + continue; /* back to for() */ + else +#ifndef WIN32 + DPRINT_WARNING(WFA_WNG, "select error: %i", errno); +#else + DPRINT_WARNING(WFA_WNG, "select error: %i", WSAGetLastError()); +#endif + } + bytesrecv = 0; +#ifdef WFA_WMM_EXT +#ifndef WIN32 + /* + * handle end to end time syc + */ + gettimeofday(&lstime, NULL); + /* If your device is BIG ENDIAN, you need to + * modify the the function calls + */ + int2BuffBigEndian(asn++, &((tgHeader_t *)trafficBuf)->hdr[8]); + int2BuffBigEndian(lstime.tv_sec, &((tgHeader_t *)trafficBuf)->hdr[12]); + int2BuffBigEndian(lstime.tv_usec, &((tgHeader_t *)trafficBuf)->hdr[16]); +#endif +#endif + memset(respBuf, 0, WFA_BUFF_512); + respLen = 0; + /* Careful: Since gtgTransac can change outside the scope of this thread + * as 0 we still need to check for this. Otherwise we will end up getting + * no statistics. + */ +#ifdef WIN32 + /* + * counter is kept to check the number of frames sending + * If the number of frames sent more than expected (rate*duration) + * do nothing till time out + */ + counter++; + if (counter >= theProf->duration * theProf->rate) + continue; +#endif + if(gtgTransac != 0) { + if(wfaSendShortFile(btSockfd, gtgTransac, + trafficBuf, 0, respBuf, &respLen) == DONE) { + } + } + + memset(trafficBuf, 0, sizeof(trafficBuf)); + respLen = 0; + + i = gtgRecv?gtgRecv:gtgTransac; +#ifdef WIN32 + /* Unblock the socket to make wfaRecvFile() non-blocking call in the case of + * Transaction Profile*/ + if(ioctlsocket(btSockfd, FIONBIO, &nonBlocking) != 0) { + DPRINT_INFO(WFA_OUT, "Non-Blocking socket failed\n"); + } +#endif + if(i!=0) { + bytesrecv = wfaRecvFile(btSockfd, i, (char*)trafficBuf); + if(bytesrecv == 0){ + DPRINT_INFO(WFA_OUT, "No packets received\n"); + } + } +#ifdef WIN32 + /* + * Sleep added to reduce the amount of frame sending + * by dut in case of transaction rpofile + */ + usleep(act_sleep_time); +#endif + } // While + if(btSockfd != -1){ + asd_closeSocket(btSockfd); + btSockfd = -1; + } + } // gtgTransac +} + +void wfa_dut_deinit() +{ +#ifdef WFA_WMM_EXT + int cntThr; +#endif + + /* free the buffer that are used in DUT */ + free(gStreams); + free(trafficBuf); + free(toutvalp); + free(respBuf); + free(xcCmdBuf); + free(parmsVal); + free(e2eStats); + + /* Close sockets */ + asd_closeSocket(gagtSockfd); + asd_closeSocket(btSockfd); + asd_closeSocket(btRecvSockfd); + +#ifdef WFA_WMM_EXT + for(cntThr = 0; cntThr < WFA_MAX_TRAFFIC_STREAMS; cntThr++) + { + if( tgSockfds[cntThr] != -1 ) + { + asd_closeSocket(tgSockfds[cntThr]); + tgSockfds[cntThr] = -1; + } + } +#ifdef WFA_WMM_PS_EXT + asd_closeSocket(psSockfd); +#endif /* WFA_WMM_PS_EXT */ + +#endif /* WFA_WMM_EXT */ +} + +/*Create the thread for receiving the WMM traffic from the TG*/ +void wfaIPTVRecvThrCreate(int tblIndex) +{ +#ifndef WIN32 + pthread_t Thread1 = -1; + int thrId = -1; + pthread_attr_t attr; + struct sched_param param; + pthread_attr_init(&attr); + pthread_attr_getschedparam(&attr, ¶m); + /* Recv thread priority decreased */ + param.sched_priority = 10; + pthread_attr_setschedparam(&attr, ¶m); + /* Start the thread to receive */ + if((thrId = pthread_create(&Thread1, &attr, (void *)wfaIPTVRecvStart, &tblIndex)) != 0) + { + DPRINT_ERR(WFA_OUT, "Error created Recv Thread\n"); + return; + } + sleep(1); + DPRINT_INFO(WFA_OUT, "Created thread %d\n", thrId); + return; +#else + DWORD RecvGenericThread; + /*Create the thread event for multiple streams and hold the thread handles in the array*/ + g_IPTVRecvhThread[tblIndex] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wfaIPTVRecvStart, (LPVOID)tblIndex, 0, &RecvGenericThread); + if (g_IPTVRecvhThread[tblIndex] == NULL){ + DPRINT_INFO(WFA_OUT, "g_RecvhThread not created\n"); + } else { + DPRINT_INFO(WFA_OUT, "thread priority = %d\n", GetThreadPriority(g_IPTVRecvhThread[tblIndex])); + SetThreadPriority(g_IPTVRecvhThread[tblIndex], THREAD_PRIORITY_NORMAL+1); + } +#endif +} + + +/* This is the receive thread function that receives the traffic in the case of + * IPTV. In the case of multiple streams the the receive happens on multiple sockets + * and waits on multiple events to stop the receive operation. + */ +#ifdef WIN32 +void wfaIPTVRecvStart(LPVOID tblidx) +#else +void wfaIPTVRecvStart(void* tblidx) +#endif +{ + int sn, n; + struct timeval ttval; +#ifndef WIN32 + struct timeval currTimeVal; +#else + unsigned long nonblocking = 1; + SYSTEMTIME currTimeVal; +#endif + +#ifdef WFA_DUT_SYNC + int traffic_start_drift; +#endif + int index; +#ifdef WIN32 + index = (int)tblidx ; +#else + index = *(int*)tblidx ; +#endif +#ifdef WIN32 + DPRINT_INFO(WFA_OUT, "g_recvEvent[index] %i , tblindex = %d, streamid = %d\n ", g_recvEvent[index], + index, gStreams[index].id); +#endif + +#ifdef WIN32 + /* Each Stream in the WMM is associated with particular event. + * Wait for the particular event to be signalled for that corresponding + * stream. + */ + if (ioctlsocket(tgSockfds[index], FIONBIO, &nonblocking) != 0) + DPRINT_ERR(WFA_OUT, "Error in blocking socket\n"); + + while ((WaitForSingleObject(g_recvEvent[index],0) != WAIT_OBJECT_0)) +#else + /*Recieve the traffic untill the user stops the traffic and resets gtgRecv flag*/ + while (gtgRecv) +#endif + { + memset(trafficBuf, 0 , sizeof(trafficBuf)); + n = wfaRecvFile(tgSockfds[index], gStreams[index].id, (char *)trafficBuf); + if ((IPTVprof == 1) && (n !=0 )) { + sn = bigEndianBuff2Int(&((tgHeader_t *)trafficBuf)->hdr[8]); + ttval.tv_sec = bigEndianBuff2Int(&((tgHeader_t *)trafficBuf)->hdr[12]); + ttval.tv_usec = bigEndianBuff2Int(&((tgHeader_t *)trafficBuf)->hdr[16]); +#ifndef WIN32 + gettimeofday(&currTimeVal, NULL); +#else + GetSystemTime(&currTimeVal); +#endif + /* + * take the end2end stats + */ + if (e2eCnt < 6000) + { + tgE2EStats_t *ep = &e2eStats[e2eCnt++]; + ep->seqnum = sn; + ep->rsec = ttval.tv_sec; + ep->rusec = ttval.tv_usec; +#ifndef WIN32 + ep->lsec = currTimeVal.tv_sec; + ep->lusec = currTimeVal.tv_usec; +#else + ep->lsec = currTimeVal.wSecond;; + ep->lusec = currTimeVal.wMilliseconds * 1000; +#endif + if(ep->lusec < 0) + { + ep->lsec -=1; + ep->lusec += 1000000; + } + else if(ep->lusec >= 1000000) + { + ep->lsec += 1; + ep->lusec -= 1000000; + } + } + } /* if(IPTVprof) */ + }/* while (gtgRecv) */ +#ifndef WIN32 + /* Sending signal to wfaTGRecvStop to close the socket + * since the receive is complete + */ + sem_post(&sem_iptv_gtgrecv[index]); + + pthread_exit(NULL); +#endif + if(tgSockfds[index] != -1){ + asd_closeSocket(tgSockfds[index]); + tgSockfds[index] = -1; + } + return ; +} + +/* + * wfaSetThreadPrio(): + * Set thread priorities for different threads depending on the traffic-class + * Voice- Highest Priority + * Video- One lower than highest + * BackGround- 2 lower than highest + * Best-Effort-3 Lower than highest + * + */ +#ifdef WIN32 +void wfaSetIPTVThreadPrio(HANDLE tid, short class) +{ + DWORD thrPriority; + + switch(class) + { + case TG_WMM_AC_VO: + thrPriority = THREAD_PRIORITY_NORMAL-3; + break; + case TG_WMM_AC_BK: + thrPriority = THREAD_PRIORITY_NORMAL-1; + break; + case TG_WMM_AC_BE: + thrPriority = THREAD_PRIORITY_NORMAL; + break; + case TG_WMM_AC_VI: + thrPriority = THREAD_PRIORITY_NORMAL-2; + default: + /* default */ + ; + } + DPRINT_INFO(WFA_OUT, " thrPriority = %d\n", thrPriority ); + + SetThreadPriority(tid, thrPriority); +} +#endif + +/* Thread function that is called when we want to send the WMM traffic. + * This thread function sets the TOS bits for the traffic class, sets the priority + * depending on traffic class and then sends the WMM streams + */ +#ifdef WIN32 +void SendIPTVFile(LPVOID strid) +#else +void SendIPTVFile(void * strid) +#endif +{ + tgStream_t *myStream = NULL; + tgProfile_t *theProfile; + int status = STATUS_COMPLETE; + int mySock = -1; + int streamid; +#ifdef WIN32 + streamid = (int)strid; +#else + streamid = *(int*)strid; +#endif + /* + * If the profile is set for file transfer, this will run to + * complete (blocking). + */ + DPRINT_INFO(WFA_OUT, "streamid WMM %d , strid = %d\n", streamid, (int)strid); + memset(respBuf, 0, WFA_BUFF_512); + respLen = 0; + myStream = findStreamProfile(streamid); + if(myStream == NULL) + { + status = STATUS_INVALID; + return ; + } + + theProfile = &myStream->profile; + if(theProfile == NULL) + { + status = STATUS_INVALID; + return ; + } + + mySock = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport); + mySock = wfaConnectUDPPeer(mySock, theProfile->dipaddr, theProfile->dport); + /* + * Set packet/socket priority TOS field + */ + wfaTGSetPrio(mySock, theProfile->trafficClass); +#ifdef WIN32 + wfaSetIPTVThreadPrio(GetCurrentThread(),theProfile->trafficClass); +#else + wfaSetThreadPrio(pthread_self(), theProfile->trafficClass); +#endif + DPRINT_INFO(WFA_OUT, "mySock %d , index =%d\n", mySock, myStream->tblidx); + + if (theProfile->startdelay > 0 && theProfile->startdelay < 50) { + DPRINT_INFO(WFA_OUT, "sleeping for %d\n", theProfile->startdelay); + asd_sleep(theProfile->startdelay); + } + DPRINT_INFO(WFA_OUT, "sendlongfile mySock = %d gtgsend = %d\n", mySock, streamid); + + if (theProfile->rate != 0) + wfaSendLongFile(mySock, streamid, respBuf, &respLen ); + else + wfaImprovePerfSendLongFile(mySock, streamid, respBuf, &respLen ); + + if(mySock != -1) { + asd_closeSocket(mySock); + } +} + +/* This function is specific to IPTV. + * We take the response from all the streams and update the buffer + * will all the statistics. + */ + +void wfaSentStatsResp( BYTE *buf) +{ + int i; + tgStream_t *allStreams = gStreams; + dutCmdResponse_t *sendStatsResp = (dutCmdResponse_t *)buf; + + if(sendStatsResp == NULL) + return; + + for(i = 0; i < WFA_MAX_TRAFFIC_STREAMS; i++) { + if((allStreams->id != 0) && (allStreams->profile.direction == DIRECT_SEND)) { + sendStatsResp->status = STATUS_COMPLETE; + sendStatsResp->streamId = allStreams->id; + memcpy(&sendStatsResp->cmdru.stats, &allStreams->stats, sizeof(tgStats_t)); + + sendStatsResp++; + } + allStreams++; + } + + return; +}
diff --git a/src/tools/Wifi_ASD_test/dut/wfa_dut.h b/src/tools/Wifi_ASD_test/dut/wfa_dut.h new file mode 100644 index 0000000..948b25c --- /dev/null +++ b/src/tools/Wifi_ASD_test/dut/wfa_dut.h
@@ -0,0 +1,47 @@ + +/**************************************************************************** + * (c) Copyright 2006 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated Wi-Fi + * contractors ("Authorized Licensees"). Authorized Licensees are hereby + * granted the limited right to use this software solely for noncommercial + * applications and solely for testing Wi-Fi equipment. Authorized Licensees + * may embed this software into their proprietary equipment and distribute this + * software with such equipment under a license with at least the same + * restrictions as contained in this License, including, without limitation, + * the disclaimer of warranty and limitation of liability, below. Other than + * expressly granted herein, this License is not transferable or sublicensable, + * and it does not extend to and may not be used with non-Wi-Fi applications. + * + * Commercial derivative works of this software or applications that use the + * Wi-Fi scripts generated by this software are NOT AUTHORIZED without specific + * prior written permission from Wi-Fi Alliance. + * + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi with a copy of such + * derivative works under a perpetual, payment-free license to use, modify, + * and distribute such derivative works for purposes of testing Wi-Fi equipment. + * + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************** + */ + + +#define WFA_DUT_AGENT
diff --git a/src/tools/Wifi_ASD_test/dut/wfa_dut_init.c b/src/tools/Wifi_ASD_test/dut/wfa_dut_init.c new file mode 100644 index 0000000..086418e --- /dev/null +++ b/src/tools/Wifi_ASD_test/dut/wfa_dut_init.c
@@ -0,0 +1,160 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause (ii), above, include distribution to third party + * companies who will redistribute the Authorized Licensee$B!G(Bs product to their + * customers with or without such third party$B!G(Bs private label. Other than + * expressly granted herein, this License is not transferable or sublicensable, + * and it does not extend to and may not be used with non-Wi-Fi applications..AN + * Wi-Fi Alliance reserves all rights not expressly granted herein..AN + * + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance..AN Non-Commercial derivative works of this software for + * internal use are authorized and are limited by the same restrictions; + * provided, however, that the Authorized Licensee shall provide Wi-Fi Alliance + * with a copy of such derivative works under a perpetual, payment-free license + * to use, modify, and distribute such derivative works for purposes of testing + * Wi-Fi equipment. + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * **************************************************************************** + * + * Revision History: + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * + */ + +#include <stdio.h> +#include <stdlib.h> +#ifndef WIN32 +#include <pthread.h> +#include <time.h> +#endif +#include "wfa_debug.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_sock.h" +#include "wfa_tg.h" +#include "wfa_miscs.h" + +extern tgStream_t *gStreams; +extern tgE2EStats_t *e2eStats; +extern int adj_latency; /* adjust sleep time due to latency */ +extern int gagtSockfd; +#ifdef WFA_WMM_EXT +extern tgWMM_t wmm_thr[]; +extern void *wfa_wmm_thread(void *thr_param); +extern void init_thr_flag(); +extern int wfa_estimate_timer_latency(); +#endif /* WFA_WMM_EXT */ + +#define LOCAL_PORT 11000 + +void wfa_dut_init(BYTE **tBuf, BYTE **rBuf, BYTE **paBuf, BYTE **cBuf, struct timeval **timerp) +{ + /* allocate the traffic stream table */ + gStreams = (tgStream_t *) malloc(WFA_MAX_TRAFFIC_STREAMS*sizeof(tgStream_t)); + if(gStreams == NULL) + { + DPRINT_ERR(WFA_ERR, "Failed to malloc theStreams\n"); + exit(1); + } + + /* a buffer used to carry receive and send test traffic */ + *tBuf = (BYTE *) malloc(MAX_UDP_LEN+1); /* alloc a traffic buffer */ + if(*tBuf == NULL) + { + DPRINT_ERR(WFA_ERR, "Failed to malloc traffic buffer\n"); + exit(1); + } + + /* a buffer used for response of control command */ + *rBuf = (BYTE *)malloc(WFA_BUFF_512); + if(*rBuf == NULL) + { + DPRINT_ERR(WFA_ERR, "Failed to malloc response buffer\n"); + exit(1); + } + + /* timer used in select call */ + *timerp = malloc(sizeof(struct timeval)); + if(*timerp == NULL) + { + DPRINT_ERR(WFA_ERR, "Failed to malloc timer val\n"); + exit(1); + } + + /* control command buf */ + *cBuf = malloc(WFA_BUFF_1K); + if(*cBuf == NULL) + { + DPRINT_ERR(WFA_ERR, "Failed to malloc control command buf\n"); + exit(1); + } + + /* parameters buff */ + *paBuf = malloc(MAX_PARMS_BUFF); + if(*paBuf == NULL) + { + DPRINT_ERR(WFA_ERR, "Failed to malloc parms value buff\n"); + exit(1); + } +#ifndef WIN32 +#ifdef WFA_WMM_EXT + /* allocate for End2End stats */ + init_thr_flag(); +#endif /* WFA_WMM_EXT */ +#endif /* WIN32 */ + + e2eStats = malloc(6144*sizeof(tgE2EStats_t)); + if(e2eStats == NULL) + { + DPRINT_ERR(WFA_ERR, "Failed to malloc e2eStats\n"); + exit(1); + } + + +#ifdef WIN32 + adj_latency = wfa_Win_estimate_timer_latency() + 4000; /* four more mini */ +#else + adj_latency = wfa_estimate_timer_latency() + 4000; /* four more mini */ +#endif + + /* 4create listening TCP socket */ + gagtSockfd = wfaCreateTCPServSock(LOCAL_PORT); + + if(gagtSockfd == -1) + { + DPRINT_ERR(WFA_ERR, "Failed to open socket\n"); + exit(1); + } +}
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_agt.h b/src/tools/Wifi_ASD_test/inc/wfa_agt.h new file mode 100644 index 0000000..602a74f --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_agt.h
@@ -0,0 +1,58 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ +#ifndef WFA_AGT_H +#define WFA_AGT_H + +typedef int (*xcCommandFuncPtr)(int len, BYTE *parms, int *respLen, BYTE *respBuf); + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_agtctrl.h b/src/tools/Wifi_ASD_test/inc/wfa_agtctrl.h new file mode 100644 index 0000000..8494e0f --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_agtctrl.h
@@ -0,0 +1,70 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + +#ifndef WFA_AGTCTRL_H +#define WFA_AGTCTRL_H + +typedef int (*commandStrProcFuncPtr)(char *, BYTE *, int *); + +typedef struct type_name_str_table +{ + int type; + char name[32]; + commandStrProcFuncPtr cmdProcFunc; +} typeNameStr_t; + +extern int buildCommandProcessTable(void); + +typedef int (*dutCommandRespFuncPtr)(BYTE *cmdBuf); + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_ca.h b/src/tools/Wifi_ASD_test/inc/wfa_ca.h new file mode 100644 index 0000000..65bd02b --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_ca.h
@@ -0,0 +1,113 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +#ifndef _WFA_CA_H_ +#define _WFA_CA_H_ + +#define ENCRYPT_NONE 0 +#define ENCRYPT_WEP 1 +#define ENCRYPT_TKIP 2 +#define ENCRYPT_AESCCMP 3 +#define WMMAC_UPLINK 0 +#define WMMAC_DOWNLINK 1 +#define WMMAC_BIDIR 3 +#define GROUP_WMMAC 0 +#define GROUP_WMMCONF 1 +#define WMMAC_ADDTS 0 +#define WMMAC_DELTS 1 +#define WMMAC_AC_BE 0 +#define WMMAC_AC_BK 1 +#define WMMAC_AC_VI 2 +#define WMMAC_AC_VO 3 + +extern int wfaStaAssociate(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaIsConnected(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaGetIpConfig(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetIpConfig(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaVerifyIpConnection(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaGetMacAddress(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetMacAddress(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); + +extern int wfaStaGetBSSID(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaGetStats(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaSetEncryption(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetEapTLS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetPSK(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaGetInfo(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaDeviceGetInfo(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaDeviceListIF(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetEapTTLS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetEapSim(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetPEAP(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetEapSIM(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetPEAP(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetUAPSD(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetIBSS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaDebugSet(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetMode(int, BYTE *, int *, BYTE *); +extern int wfaStaSetWMM(int, BYTE *, int *, BYTE *); +extern int wfaStaSendNeigreq(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetSystime(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSet11n(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetRifsTest(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetWireless(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSendAddba(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSendCoexistMgmt(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetDisconnect(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetEapFAST(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaSetEapAKA(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaResetDefault(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaStaReAssociate(int, BYTE*, int*, BYTE*); +extern int wfaStaSetPwrSave(int, BYTE *, int *, BYTE *); +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_ca_resp.h b/src/tools/Wifi_ASD_test/inc/wfa_ca_resp.h new file mode 100644 index 0000000..e70ba47 --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_ca_resp.h
@@ -0,0 +1,108 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + ****************************************************************************** + */ + + +#ifndef WFA_CA_RESP_H +#define WFA_CA_RESP_H + +typedef int (*dutCommandRespFuncPtr)(BYTE *cmdBuf); + +int caCmdNotDefinedYet(BYTE *cmdBuf); +int wfaStaVerifyIpConnectResp(BYTE *cmdBuf); +int wfaStaSetIpConfigResp(BYTE *cmdBuf); +int wfaStaIsConnectedResp(BYTE *cmdBuf); +int wfaStaGetIpConfigResp(BYTE *cmdBuf); +int wfaGetVersionResp(BYTE *cmdBuf); +int wfaStaGetInfoResp(BYTE *cmdBuf); +int wfaTrafficAgentConfigResp(BYTE *cmdBuf); +int wfaTrafficAgentSendResp(BYTE *cmdBuf); +int wfaTrafficAgentRecvStartResp(BYTE *cmdBuf); +int wfaTrafficAgentRecvStopResp(BYTE *cmdBuf); +int wfaTrafficAgentResetResp(BYTE *cmdBuf); +int wfaTrafficAgentPingStartResp(BYTE *cmdBuf); +int wfaTrafficAgentPingStopResp(BYTE *cmdBuf); +int wfaStaGetMacAddressResp(BYTE *cmdBuf); +int wfaStaGetBSSIDResp(BYTE *cmdBuf); +int wfaStaSetEncryptionResp(BYTE *cmdBuf); +int wfaStaSetEapTLSResp(BYTE *cmdBuf); +int wfaStaSetPSKResp(BYTE *cmdBuf); +int wfaStaSetEapTTLSResp(BYTE *cmdBuf); +int wfaStaSetEapSIMResp(BYTE *cmdBuf); +int wfaStaSetEapPEAPResp(BYTE *cmdBuf); +int wfaStaAssociateResp(BYTE *cmdBuf); +int wfaStaSetIBSSResp(BYTE *cmdBuf); +int wfaStaGetStatsResp(BYTE *cmdBuf); +int wfaDeviceGetInfoResp(BYTE *cmdBuf); +int wfaDeviceListIFResp(BYTE *cmdBuf); +int wfaStaDebugSetResp(BYTE *cmdBuf); +void wfaStaDebugHexDump(BYTE *cmdBuf); +int wfaStaSetModeResp(BYTE *cmdBuf); +int wfaStaSetWMMResp(BYTE *cmdBuf); + +int wfaStaSetUAPSDResp(BYTE *cmdBuf); /* Added as per BRCM 1.3 ASD */ +int wfaStaSendNeigreqResp(BYTE *cmdBuf); +int wfaStaSetSystimeResp(BYTE *cmdBuf); +int wfaStaSet11nResp(BYTE *cmdBuf); +int wfaStaSetRifsTestResp(BYTE *cmdBuf); +int wfaStaSetWirelessResp(BYTE *cmdBuf); +int wfaStaSendAddbaResp(BYTE *cmdBuf); +int wfaStaSendCoexistMgmtResp(BYTE *cmdBuf); +int wfaStaDisconnectResp(BYTE *cmdBuf); +int wfaStaSetEapFASTResp(BYTE *cmdBuf); +int wfaStaSetEapAKAResp(BYTE *cmdBuf); +int wfaStaResetDefaultResp(BYTE * cmdBuf); +int wfaStaSetPwrsaveResp(BYTE *cmdBuf); +int wfaStaReassociateResp(BYTE *cmdBuf); + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_cmds.h b/src/tools/Wifi_ASD_test/inc/wfa_cmds.h new file mode 100644 index 0000000..48354d1 --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_cmds.h
@@ -0,0 +1,380 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + ****************************************************************************** + */ + + +/* + * wfa_cmds.h: + * definitions of command types. + */ +#ifndef _WFA_CMDS_H +#define _WFA_CMDS_H + +typedef struct _tg_ping_start +{ + char dipaddr[IPV4_ADDRESS_STRING_LEN]; /* destination/remote ip address */ + int frameSize; + int frameRate; + int duration; + int type; + int qos; +} tgPingStart_t; + +typedef struct ca_sta_set_ip_config +{ + char intf[WFA_IF_NAME_LEN]; + int isDhcp; + char ipaddr[WFA_IP_ADDR_STR_LEN]; + char mask[WFA_IP_MASK_STR_LEN]; + char defGateway[WFA_IP_ADDR_STR_LEN]; + char pri_dns[WFA_IP_ADDR_STR_LEN]; + char sec_dns[WFA_IP_ADDR_STR_LEN]; +} caStaSetIpConfig_t; + +typedef struct ca_sta_verify_ip_connection +{ + char dipaddr[WFA_IP_ADDR_STR_LEN]; + int timeout; +} caStaVerifyIpConnect_t; + +typedef struct ca_sta_set_encryption +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + int encpType; + char keys[4][32]; /* 26 hex */ + int activeKeyIdx; +} caStaSetEncryption_t; + +typedef struct ca_sta_set_mode +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + char mode; + int encpType; + int channel; + char keys[4][32]; /* 26 hex */ + int activeKeyIdx; +} caStaSetMode_t; + + +typedef struct ca_sta_set_psk +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + BYTE passphrase[64]; + char keyMgmtType[8]; /* WPA-PSK */ + int encpType; /* TKIP */ +} caStaSetPSK_t; + +typedef struct ca_sta_set_eaptls +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + char keyMgmtType[8]; + char encrptype[8]; + char trustedRootCA[128]; + char clientCertificate[128]; +} caStaSetEapTLS_t; + +typedef struct ca_sta_set_eapttls +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + char username[32]; + char passwd[16]; + char keyMgmtType[8]; + char encrptype[8]; + char trustedRootCA[32]; + char clientCertificate[32]; +} caStaSetEapTTLS_t; + +typedef struct ca_sta_set_eapsim +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + char username[32]; + char passwd[16]; + char keyMgmtType[8]; + char encrptype[8]; +} caStaSetEapSIM_t; + +typedef struct ca_sta_set_eappeap +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + char username[32]; + char passwd[16]; + char keyMgmtType[8]; + char encrptype[8]; + char trustedRootCA[32]; + char innerEAP[16]; + int peapVersion; +} caStaSetEapPEAP_t; +typedef struct ca_sta_set_eapfast +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + char username[32]; + char passwd[16]; + char keyMgmtType[8]; + char encrptype[9]; + char trustedRootCA[32]; + char innerEAP[16]; + char validateServer; + char pacFileName[32]; +} caStaSetEapFAST_t; + +typedef struct ca_sta_set_eapaka +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + char username[32]; + char passwd[96]; + char keyMgmtType[8]; + char encrptype[9]; + char tripletCount; + char tripletSet[3][96]; +} caStaSetEapAKA_t; + +typedef struct ca_sta_set_uapsd +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + int maxSPLength; + BYTE acBE; + BYTE acBK; + BYTE acVI; + BYTE acVO; +} caStaSetUAPSD_t; + +typedef struct ca_sta_set_ibss +{ + char intf[WFA_IF_NAME_LEN]; + char ssid[WFA_SSID_NAME_LEN]; + int channel; + int encpType; + char keys[4][32]; + int activeKeyIdx; +} caStaSetIBSS_t; + +typedef struct sta_get_testdata +{ + int type; + int next; /* sequence number, 0 is the last one */ +} caStaGetTestData_t; + +typedef struct sta_debug_set +{ + unsigned short level; + unsigned short state; +} staDebugSet_t; +typedef struct config +{ + BYTE wmm; + int rts_thr ; + int frag_thr ; +} wmmconf_t; + +typedef struct wmm_tsinfo +{ +unsigned int Reserved1 :1; +unsigned int TID :4; +unsigned int direction :2; +unsigned int dummy1 :1; +unsigned int dummy2 :1; +unsigned int Reserved2 :1; +unsigned int PSB :1; +unsigned int UP :3; +unsigned int Reserved3 :2; +unsigned int Reserved4 :1; +unsigned int Reserved5 :7; +}wmmtsinfo_t; +typedef struct wmm_tspec +{ +wmmtsinfo_t tsinfo; +BOOL Fixed;//The MSDU Fixed Bit +unsigned short size;//The MSDU Size +unsigned short maxsize;//MAximum MSDU Size +unsigned int min_srvc;//The minimum Service Interval +unsigned int max_srvc;//The maximum Service Interval +unsigned int inactivity;//Inactivity Interval +unsigned int suspension;//The Suspension Interval +unsigned int srvc_strt_tim;//The Service Start Time +unsigned int mindatarate;//The Minimum Data Rate +unsigned int meandatarate;//The Minimum Data Rate +unsigned int peakdatarate;//The Minimum Data Rate +unsigned int burstsize;//The Maximum Burst Size +unsigned int delaybound;//The Delay Bound +unsigned int PHYrate;//The minimum PHY Rate +float sba;//The Surplus Bandwidth Allownce +unsigned short medium_time;//The medium time + +}wmmtspec_t; +typedef struct wmmac_addts +{ + BYTE dialog_token; + BYTE accesscat; + wmmtspec_t tspec; +} wmmacadd_t; + +typedef struct ca_sta_set_wmm +{ + char intf[WFA_IF_NAME_LEN]; + BYTE group; + BYTE action; + BYTE send_trig; + char dipaddr[WFA_IP_ADDR_STR_LEN]; + BYTE trig_ac; + union _action + { + wmmconf_t config; + wmmacadd_t addts; + BYTE delts; + } actions; +} caStaSetWMM_t; + +typedef struct ca_sta_set_pwrsave +{ + char intf[WFA_IF_NAME_LEN]; + int mode; +} caStaSetPwrSave_t; + +typedef struct ca_sta_reset_default +{ + char intf[WFA_IF_NAME_LEN]; + char prog[WFA_DEFAULT_PROG_NAME]; +} caStaResetDefault_t; + +typedef struct ca_dev_info +{ + BYTE fw; +} caDevInfo_t; + +typedef struct sta_time { + int month; + int date; + int year; + int hours; + int minutes; + int seconds; +} caStaTime_t; + +#ifdef WFA_STA_TB +typedef struct sta_set_11n { + short int intolerant_40; + short int addba_reject; + short int ampdu; + short int amsdu; + short int greenfield; + short int sgi20; + short int stbc_rx; + short int width; /* if auto set it to -1 */ + short int mcs_fixedrate; + short int mcs32; /* Ignore as of now */ + short int smps; + int txsp_stream; + int rxsp_stream; +} caStaSet11n_t; + +typedef struct coexist_mgmt +{ + char Mhz[INTOLERANT_LEN]; + char bss[INTOLERANT_LEN]; + char ChnlRepo[CHNL_LIST]; +} caStaSendCoexistmgmt_t; +#endif /* WFA_STA_TB */ +typedef struct dut_commands +{ + char intf[WFA_IF_NAME_LEN]; + char mac[WFA_MAC_ADDR_STR_LEN]; + union _cmds + { + int streamId; + int iftype; + tgProfile_t profile; + tgPingStart_t startPing; + char ssid[WFA_SSID_NAME_LEN]; + char bssid[WFA_MAC_ADDR_STR_LEN]; + caStaSetIpConfig_t ipconfig; + caStaVerifyIpConnect_t verifyIp; + caStaSetEncryption_t wep; + caStaSetPSK_t psk; + caStaSetEapTLS_t tls; + caStaSetEapTTLS_t ttls; + caStaSetEapSIM_t sim; + caStaSetEapPEAP_t peap; + caStaSetUAPSD_t uapsd; + caStaSetIBSS_t ibss; + caStaGetTestData_t tdata; + caStaSetWMM_t setwmm; + staDebugSet_t dbg; + caDevInfo_t dev; + caStaTime_t stime; +#ifdef WFA_STA_TB + short int action_rifs; + short int tid; + char wireless_band[WIRELESS_BAND]; + caStaSet11n_t set11n; + caStaSendCoexistmgmt_t coexistmgmt; +#endif + } cmdsu; +} dutCommand_t; + +extern int buildCommandProcessTable(void); +#ifdef WIN32 +extern BOOL IPProperties(caStaSetIpConfig_t*, DWORD*); +extern void ResetIP(caStaSetIpConfig_t * ); + +#endif +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_debug.h b/src/tools/Wifi_ASD_test/inc/wfa_debug.h new file mode 100644 index 0000000..ea0062b --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_debug.h
@@ -0,0 +1,79 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +#ifndef WFA_DEBUG_H +#define WFA_DEBUG_H + +#define WFA_ERR stderr /* error: can be redefined to a log file */ +#define WFA_OUT stdout /* info: can be redefined to a log file */ +#define WFA_WNG stdout /* warning: can be redefined to a log file */ + +#define WFA_DEBUG_DEFAULT 0x0001 +#define WFA_DEBUG_ERR 0x0001 +#define WFA_DEBUG_INFO 0x0002 +#define WFA_DEBUG_WARNING 0x0004 + +#define WFA_DEBUG 1 + +#define DPRINT_ERR fprintf(WFA_ERR, "File %s, Line %ld: ", \ + __FILE__, (long)__LINE__); \ + fprintf + +#define DPRINT_INFO if(wfa_defined_debug & WFA_DEBUG_INFO) \ + fprintf + +#define DPRINT_WARNING if(wfa_defined_debug & WFA_DEBUG_WARNING) \ + fprintf + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_main.h b/src/tools/Wifi_ASD_test/inc/wfa_main.h new file mode 100644 index 0000000..8890cd0 --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_main.h
@@ -0,0 +1,104 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +#ifndef _WFA_MAIN_H +#define _WFA_MAIN_H + +#define WFA_MAX_TRAFFIC_STREAMS 6 + +/* maximum number of streams to support */ +#define WFA_MAX_WMM_STREAMS 4 + +#define MAX_CMD_BUFF 1024 +#define MAX_PARMS_BUFF 512 + +#define MAX_TRAFFIC_BUF_SZ 1536 + +#define WFA_BUFF_32 32 +#define WFA_BUFF_64 64 +#define WFA_BUFF_128 128 +#define WFA_BUFF_256 256 +#define WFA_BUFF_512 512 +#define WFA_BUFF_1K 1024 + +#define WFA_CMD_STR_SZ 512 + +/* WMM TRAFFIC CLASS LEVEL */ +#define WFA_TRAFFIC_CLASS_NUM 6 + +/* Threads to handle WMM traffic */ +#define WFA_THREADS_NUM 6 + +char* path; + +enum tg_port +{ + UDP_PORT_BE1 = 0, + UDP_PORT_BE2 = 1, + UDP_PORT_BK1 = 2, + UDP_PORT_BK2 = 3, + UDP_PORT_VI1 = 4, + UDP_PORT_VI2 = 5, + UDP_PORT_VO1 = 6, + UDP_PORT_VO2 = 7, + UDP_PORT_ND1 = 8, + UDP_PORT_ND2 = 9 +}; + +#ifndef WIN32 +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_miscs.h b/src/tools/Wifi_ASD_test/inc/wfa_miscs.h new file mode 100644 index 0000000..f011c08 --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_miscs.h
@@ -0,0 +1,176 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +#ifndef _WFA_MISCS_H_ +#define _WFA_MISCS_H_ + +#ifdef WIN32 +#define inline __inline +#define uint unsigned int +#define PING_STATUS_FILE_PATH "temp\\RWL\\pingstatus.txt" +ULONG exitcode ; +extern int wfa_Winitime_diff(SYSTEMTIME *t1,SYSTEMTIME *t2); +extern int ChangeGateWay(GateWay); +extern int GetPingStat(FILE* pFile, const wchar_t* lpszSearchString , unsigned int *pos,unsigned int *sent, const char* delim) ; +extern int GetStats(FILE* pFile, const wchar_t* lpszSearchString , unsigned int *pos, const char* delim) ; +extern int FileSearch(FILE* pFile, const wchar_t* lpszSearchString, unsigned int *pos) ; +extern unsigned int uGetLocalIP(void); +extern char* GetHostName(char* buf, int len) ; +extern char* GetDutIP(char* ); +extern DWORD PingStart( ); +extern char * strtok_r(char *s1, const char *s2, char **lasts); +extern int strncasecmp(const char *s1, const char *s2, unsigned int length); +extern int strcasecmp(const char *s1, const char *s2); +extern FILE* asd_Config(char* , char*); +extern HANDLE processHandle; +extern HANDLE processThread; +extern int wfa_Win_estimate_timer_latency(); +typedef unsigned long GateWay; //new gateway +#endif/*WIN32*/ +extern int wfaTGSetPrio(int sockfd, int tgClass); + +/* 802.1x Defines */ +#define KEY_FILE "key.pem" +#define TTLS_innerEAP "mschapv2" +#define AES_ENCPTYPE "aes" +#define AES_LEN 0x4 +/* defines for EAP types */ +#define BCM_DEFAULT_SEC_MODE 0x0 +#define BCM_EAP_TYPE_TLS 0x1 +#define BCM_EAP_TYPE_TTLS 0x2 +#define BCM_EAP_TYPE_SIM 0x3 +#define BCM_EAP_TYPE_PEAP 0x4 +#define BCM_EAP_TYPE_FAST 0x5 +#define BCM_EAP_TYPE_AKA 0x6 + +#define STD_ERR 2 +#define TEMP_FILE_PATH "tempr.txt" +#define TEMP_STD_ERR_FILE "temp_err.dat" +#define TEMP_STD_OUT_FILE "temp_out.dat" + +#if defined(WIN32) +#define DUP _dup +#define DUP2 _dup2 +#else +#define DUP dup +#define DUP2 dup2 +#endif + +#ifndef WIN32 +#define S_N_PRINTF snprintf +#else +#define S_N_PRINTF _snprintf +#endif +extern int Start_Socket_Service(); +extern int Stop_Socket_Service(); +extern int isString(char *); +extern int isNumber(char *); +extern int isIpV4Addr(char *); +extern inline double wfa_timeval2double(struct timeval *tval); +extern inline void wfa_double2timeval(struct timeval *tval, double dval); +extern inline double wfa_ftime_diff(struct timeval *t1, struct timeval *t2); +extern int wfa_itime_diff(struct timeval *t1, struct timeval *t2); +void p_error(char *errorString); +/* OS abstraction APIs*/ +extern void asd_sleep(int sleepTime); +extern void uapsd_sleep(int sleepTime); +extern void asd_closeSocket(int Sockfd); +extern void asd_shutDown(int Sockfd); +extern void exec_process(char* command); +extern int exec_wmmCmd(char* command); +extern int asd_Config_wmm(char *strFunct, char *strstrParams); +extern inline void int2BuffBigEndian(int val, char *buf); +extern inline int bigEndianBuff2Int(char *buff); +extern char* rwl_client_path; +extern int rwl_wifi_flag; +extern int gagtSockfd; +extern void Cleanup_File(FILE *fp); +extern unsigned short wfa_defined_debug; +extern void GetWirelessAdapter(char *adapter_name); +extern void get_rwl_exe_path(char *rwl_exe_path, int exe_path_len); +extern FILE *asd_cmd_exec(char * trafficPath); +extern int interface_validation(char *interfac); +extern void file_cleanup(FILE *fp); +extern FILE *asd_Config(char *strFunct, char *strstrParams); +extern int exec_process_cnclient(char *buf, char *rwl_client_path, int rwl_wifi_flag); + +/* + * Following declarations are separated for LINUX and ANDROID + * The default path given for Linux are not taken in Android + */ +#ifndef WIN32 +#ifdef TARGETENV_android +#define SH_PATH "/data/busybox/sh" +#define PING_PATH "/data/busybox/ping" +#define IFCONFIG_PATH "/data/busybox/ifconfig" +#define ROUTE_PATH "/data/busybox/route" +#define DHCLIENT_PATH "/data/busybox/dhclient" +#define TMP_FILE_PATH "/data/local/temp.txt" +#define RESOLV_FILE_PATH "/data/local/resolv.conf.bak" +#define PINGOUT_FILE_PATH "/data/local/pingout.txt" +#define SPOUT_FILE_PATH "/data/local/spout.txt" +#else +#define PING_PATH "/bin/ping" +#define SH_PATH "/bin/sh" +#define IFCONFIG_PATH "/sbin/ifconfig" +#define ROUTE_PATH "/sbin/route" +#define DHCLIENT_PATH "/sbin/dhclient" +#define TMP_FILE_PATH "/tmp/temp.txt" +#define RESOLV_FILE_PATH "/tmp/resolv.conf.bak" +#define PINGOUT_FILE_PATH "/tmp/pingout.txt" +#define SPOUT_FILE_PATH "/tmp/spout.txt" +#endif +#endif +#endif/*_WFA_MISCS_H_*/
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_rsp.h b/src/tools/Wifi_ASD_test/inc/wfa_rsp.h new file mode 100644 index 0000000..1ccd8c2 --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_rsp.h
@@ -0,0 +1,127 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +#ifndef WFA_RSP_H +#define WFA_RSP_H + +#ifdef WFA_WMM_VOICE +#define WFA_INFO_BUFSIZE 128 /* used to upload test data */ +#else +#define WFA_INFO_BUFSIZE 128 +#endif +typedef struct _tg_ping_stop_resp +{ + int sendCnt; + int repliedCnt; +} tgPingStopResp_t; + +typedef struct ca_sta_get_ipconfig_resp +{ + int isDhcp; + char ipaddr[WFA_IP_ADDR_STR_LEN]; + char mask[WFA_IP_MASK_STR_LEN]; + char dns[WFA_MAX_DNS_NUM][WFA_IP_ADDR_STR_LEN]; +} caStaGetIpConfigResp_t; + +typedef struct ca_sta_get_stats_resp +{ + int status; + int txFrames; + int rxFrames; + int txMulticast; + int rxMulticast; + int fcsErrors ; + int txRetries; +} caStaGetStatsResp_t; + +typedef struct ca_device_get_info_resp +{ + char vendor[16]; + char model[16]; + char version[16]; + char firmware[16]; +} caDeviceGetInfoResp_t; + +typedef struct ca_device_list_if_resp +{ + int status; +#define IF_80211 1 +#define IF_ETH 2 + int iftype; + char ifs[3][16]; +} caDeviceListIFResp_t; + + + +typedef struct dut_cmd_response +{ + int status; + int streamId; + union _cmdru + { + tgStats_t stats; + tgPingStopResp_t pingStp; + caStaGetIpConfigResp_t getIfconfig; + caStaGetStatsResp_t ifStats; + caDeviceGetInfoResp_t devInfo; + caDeviceListIFResp_t ifList; + char version[WFA_VERSION_LEN]; + char info[WFA_INFO_BUFSIZE]; + char bssid[WFA_MAC_ADDR_STR_LEN]; + char mac[WFA_MAC_ADDR_STR_LEN]; + int connected; + } cmdru; +}dutCmdResponse_t; + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_sock.h b/src/tools/Wifi_ASD_test/inc/wfa_sock.h new file mode 100644 index 0000000..12a05a0 --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_sock.h
@@ -0,0 +1,157 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +#ifndef _WFA_SOCK_H +#define _WFA_SOCK_H + + +#ifndef WIN32 +#include <stdio.h> /* for printf() and fprintf() */ +#include <sys/socket.h> /* for socket(), bind(), and connect() */ +#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */ +#include <stdlib.h> /* for atoi() and exit() */ +#include <string.h> /* for memset() */ +#include <unistd.h> /* for close() */ +#include <sys/time.h> /* for struct timeval {} */ +#include <fcntl.h> /* for fcntl() */ +#include <errno.h> +#include <typedefs.h> /* for android compilation */ +#else +#include <winsock2.h> +#include <ws2tcpip.h> +#include <stdio.h> /* for printf() and fprintf() */ +#include <stdlib.h> /* for atoi() and exit() */ +#include <string.h> /* for memset() */ + +typedef int socklen_t; +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif +#endif +#include <wlioctl.h> +#define MAX_UDP_LEN 2048 + +#ifdef WIN32 +typedef SOCKET sockfd_t; +#else +typedef int sockfd_t; +#endif +struct sockfds +{ + sockfd_t *agtfd; /* dut agent main socket fd */ + sockfd_t *cafd; /* sock fd to control agent */ + sockfd_t *tgfd; /* traffic agent fd */ + sockfd_t *tgRevfd; /*traffic Recv Fd */ + sockfd_t *wmmfds; /* wmm stream ids */ + sockfd_t *psfd; /* wmm-ps socket id */ +}; + +#ifdef WIN32 + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + + +struct ifmap { + unsigned int mem_start; + unsigned int mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; + }; + +struct ifreq { + char ifr_name[IFNAMSIZ];/* Interface name */ + union { + SOCKADDR_IN ifr_addr; + SOCKADDR_IN ifr_dstaddr; + SOCKADDR_IN ifr_broadaddr; + SOCKADDR_IN ifr_netmask; + SOCKADDR_IN ifr_hwaddr; + short ifr_flags; + int ifr_ifindex; + int ifr_metric; + int ifr_mtu; + struct ifmap ifr_map; + char ifr_slave[IFNAMSIZ]; + char ifr_newname[IFNAMSIZ]; + char * ifr_data; + }; +}; + + + +#endif + + +extern int wfaCreateTCPServSock(unsigned short sport); +extern int wfaCreateUDPSock(char *sipaddr, unsigned short sport); +extern int wfaAcceptTCPConn(int servSock); +extern int wfaConnectUDPPeer(int sock, char *dipaddr, unsigned short dport); +extern int wfaConnectTCPPeer(unsigned short sport, char *dipaddr, unsigned short dport); +extern void wfaSetSockFiDesc(fd_set *sockset, int *, struct sockfds *); +extern int wfaCtrlSend(int sock, unsigned char *buf, int bufLen); +extern int wfaCtrlRecv(int sock, unsigned char *buf); +extern int wfaTrafficSendTo(int sock, char *buf, int bufLen, struct sockaddr *to); +extern int wfaTrafficRecv(int sock, char *buf, struct sockaddr *from); +extern int wfaGetifAddr(char *ifname, struct sockaddr_in *sa); +extern struct timeval *wfaSetTimer(int, int, struct timeval *); +extern int wfaSetSockMcastRecvOpt(int, char*); +extern int wfaSetSockMcastSendOpt(int); +extern int wfaSetProcPriority(int); + + +#endif /* _WFA_SOCK_H */
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_tg.h b/src/tools/Wifi_ASD_test/inc/wfa_tg.h new file mode 100644 index 0000000..045bd21 --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_tg.h
@@ -0,0 +1,292 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + /* + * wfa_tg.h: + * Definitions used in Traffic Generator Modules + */ +#ifndef _WFA_TG_H +#define _WFA_TG_H + +#ifndef WIN32 +#include <sys/time.h> +#include <pthread.h> +#include <bcmendian.h> +#else +#include <windows.h> +#ifdef WFA_WMM_EXT +#ifndef WIN32 +#include "sched.h" +#include "semaphore.h" +#endif /* !WIN32 */ +#endif /* WFA_WMM_EXT */ + +#define usleep(x) Sleep(x) +#define sleep(x) Sleep(x) +#endif /* !WIN32 */ + +/* maximum number of streams to support */ +//#define WFA_MAX_WMM_STREAMS 4 +#define IPV4_ADDRESS_STRING_LEN 16 + +#define MAX_PROFILE_NUM 6 +#define MINISECONDS 1000 +#define MICROSECONDS 1000000 +#define NANOSECONDS 1000000000 +#define LINUX_TIMER_RES 20000000 /* 20 MINSECONDS */ +#define CA_RESPONSE_BUF_SIZE 128 + +/* Profile Key words */ +#define KW_PROFILE 1 +#define KW_DIRECTION 2 +#define KW_DIPADDR 3 +#define KW_DPORT 4 +#define KW_SIPADDR 5 +#define KW_SPORT 6 +#define KW_FRATE 7 +#define KW_DURATION 8 +#define KW_PLOAD 9 +#define KW_TCLASS 10 +#define KW_STREAMID 11 +#define KW_COMPLETE 12 +#define KW_ERROR 13 +#define KW_STARTDELAY 14 +#define KW_NUMFRAME 15 +#define KW_USESYNCCLOCK 16 +#define KW_USERPRIORITY 17 + +/* Profile Types */ +#define PROF_FILE_TX 1 +#define PROF_MCAST 2 +#define PROF_IPTV 3 +#define PROF_TRANSC 4 +#define PROF_START_SYNC 5 /* this will be outdated */ +#define PROF_CALI_RTD 6 +#define PROF_UAPSD 7 +#define PROF_FILE_TX_TCP 8 +#define PROF_TRANSC_TCP 9 +#define PROF_LAST 10 + +/* Traffic Classes */ +//#define TRAFFIC_CLASS_VO 1 +//#define TRAFFIC_CLASS_VI 2 +//#define TRAFFIC_CLASS_BK 3 +//#define TRAFFIC_CLASS_BE 4 + + +/* Traffic Directions */ +#define DIRECT_SEND 1 +#define DIRECT_RECV 2 + +#define TG_PROTO_TCP 0 +#define TG_PROTO_UDP 1 + +#define TG_WMM_AC_UP0 12 /* User Priority 0 */ +#define TG_WMM_AC_UP1 13 /* 1 */ +#define TG_WMM_AC_UP2 14 /* 2 */ +#define TG_WMM_AC_UP3 15 /* 3 */ +#define TG_WMM_AC_UP4 16 /* 4 */ +#define TG_WMM_AC_UP5 17 /* 5 */ +#define TG_WMM_AC_UP6 18 /* 6 */ +#define TG_WMM_AC_UP7 19 /* 7 */ +#define TG_WMM_AC_BE 1 /* Best Effort */ +#define TG_WMM_AC_BK 2 /* Background */ +#define TG_WMM_AC_VI 3 /* Video */ +#define TG_WMM_AC_VO 4 /* Voice */ +#define TG_WMM_AC_UAPSD 5 /* UAPSD */ + +/* wmm defs */ +#define TOS_VO7 0xE0 // 111 0 0000 (7) AC_VO tos/dscp values +#define TOS_VO 0xD0 // 110 0 0000 (6) AC_VO tos/dscp values +//Atheros Madwifi use 0x88 for UPSD/Voice +//#define TOS_VO 0x88 // 110 0 0000 (6) AC_VO tos/dscp values + +#define TOS_VI 0xA0 // 101 0 0000 (5) AC_VI +#define TOS_VI4 0x80 // 100 0 0000 (4) AC_VI + +#define TOS_BE 0x00 // 000 0 0000 (0) AC_BE +#define TOS_EE 0x60 // 011 0 0000 (3) AC_BE + +#define TOS_BK 0x20 // 001 0 0000 (1) AC_BK +#define TOS_LE 0x40 // 010 0 0000 (2) AC_BK + +#define AC_CLASS_MAX_THREAD 5 + +#define WFA_UDP_ECHO_STREAM_ID 0xFFFF +#define WFA_UDP_ECHO_PORT 07 + +#define WFA_PING_ICMP_ECHO 0 +#define WFA_PING_UDP_ECHO 1 + +typedef struct _tg_profile +{ + int profile; /* profile id */ + int direction; + char dipaddr[IPV4_ADDRESS_STRING_LEN]; /* destination/remote ip address */ + unsigned short dport; + char sipaddr[IPV4_ADDRESS_STRING_LEN]; /* source/local ip address */ + unsigned short sport; + int rate; + int duration; + int pksize; + short trafficClass; /* VO, VI, BK, BE */ + int startdelay; +} tgProfile_t; + +typedef struct _tg_stats +{ + int txFrames; + int rxFrames; + int txPayloadBytes; + int rxPayloadBytes; + int outOfSequenceFrames; + int lostPkts; /* voice over wi-fi */ + unsigned long jitter; /* voice over wi-fi */ +} tgStats_t; + +typedef struct _tg_stream +{ + int id; + int sockfd; + int tblidx; + int lastPktSN; /* use for Jitter calculation */ + int rxTimeLast; /* use for pkLost */ + int fmInterval; + int state; /* indicate if the stream being active */ + tgProfile_t profile; + tgStats_t stats; +} tgStream_t; + +typedef struct _traffic_header +{ + char hdr[20]; /* always wfa */ +} tgHeader_t; + +#ifdef WFA_WMM_EXT +typedef struct _tg_wmm +{ + int thr_flag; /* this is used to indicate stream id */ + int stop_flag; /* this is used to indicate stream id */ +#ifndef WIN32 + int thr_id; + pthread_t thr; + pthread_cond_t thr_flag_cond; + pthread_cond_t thr_stop_cond; + pthread_mutex_t thr_flag_mutex; + pthread_mutex_t thr_stop_mutex; +#else + HANDLE thr_id; +#endif /*!WIN32 */ +}tgWMM_t; + +typedef int (*StationStateFunctionPtr)( char, int,int *); //PS,sleep period,state + +typedef struct station_state_table +{ +StationStateFunctionPtr statefunc; +char pw_offon; +int sleep_period; +} StationProcStatetbl_t; + +typedef int (*stationRecvStateFunctionPtr)(unsigned int *, int,int * ); //Recieved message buffer, length,state + +typedef struct console_rcv_state_table +{ +stationRecvStateFunctionPtr statefunc; +} StationRecvProcStatetbl_t; +#endif /* WFA_WMM_EXT */ + +typedef struct _tg_thr_data +{ + int tid; +#ifdef WFA_WMM_PS_EXT + /* In case of XP CA the library does not get compiled with WFA_WMM_PS_EXT + * Hence StationProcStatetbl_t definition will not be known to XP. + */ + StationProcStatetbl_t *state; +#endif /* WFA_WMM_PS_EXT */ + int state_num; +} tgThrData_t; + +typedef struct _tg_sync_time +{ + double dut_time; + double tm_time; + double dtime; +}tgSyncTime_t; + +typedef struct _e2e_stats +{ + int seqnum; + int lsec; + int lusec; + int rsec; + int rusec; +} tgE2EStats_t; + +extern int wfaTGConfig(int len, BYTE *buf, int *respLen, BYTE *respBuf); +extern int wfaSendLongFile(int fromSockfd, int streamId, BYTE *respBuf, int *respLen); + +extern int wfaImprovePerfSendLongFile(int fromSockfd, int streamId, BYTE *respBuf, int *respLen); + +extern int wfaRecvFile(int mySockfi, int profId, char *buf); +extern int wfaTGRecvStart(int len, BYTE *parms, int *respLen, BYTE *respBuf); +extern int wfaTGRecvStop(int len, BYTE *parms, int *respLen, BYTE *respBuf); +extern int wfaTGSendStart(int len, BYTE *parms, int *respLen, BYTE *respBuf); +extern int wfaTGReset(int len, BYTE *parms, int *respLen, BYTE *respBuf); +extern int wfaSendShortFile(int fromSockfd, int profId, BYTE *buf, int size, BYTE *respBuf, int *respLen); +extern int wfaFlushSockQueue(int profId); +extern int wfaTGSendPing(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); +extern int wfaTGStopPing(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf); + +#endif /* _WFA_TG_H */
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_tlv.h b/src/tools/Wifi_ASD_test/inc/wfa_tlv.h new file mode 100644 index 0000000..055563e --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_tlv.h
@@ -0,0 +1,311 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +/* + * File: wfa_tlv.h + * definitions for each of command types. + * format: + * --------------------------------------------------- + * | tag | length | value + * --------------------------------------------------- + * 2 bytes 2bytes defined by length + */ +#ifndef _WFA_TLV_H +#define _WFA_TLV_H + +#include "wfa_types.h" + +#define INTEGER_1 0x0001 /* byte */ +#define INTEGER_2 0x0002 /* word */ +#define OCTET_STRING 0x0003 /* string */ + +typedef struct _wfatlvHdr +{ + WORD tag; /* tag/type */ + WORD len; /* value length */ +} wfaTLV; + +#define WFA_TLV_HDR_LEN sizeof(wfaTLV) +#ifndef WIN32 +/* Commands */ +#define WFA_GET_VERSION_TLV 0x01 + +/* Generic TRAFFIC GENERATOR Commands */ +#define WFA_TRAFFIC_SEND_PING_TLV (WFA_GET_VERSION_TLV + 0x01) +#define WFA_TRAFFIC_STOP_PING_TLV (WFA_TRAFFIC_SEND_PING_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_CONFIG_TLV (WFA_TRAFFIC_STOP_PING_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_SEND_TLV (WFA_TRAFFIC_AGENT_CONFIG_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_RECV_START_TLV (WFA_TRAFFIC_AGENT_SEND_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_RECV_STOP_TLV (WFA_TRAFFIC_AGENT_RECV_START_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_RESET_TLV (WFA_TRAFFIC_AGENT_RECV_STOP_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_STATUS_TLV (WFA_TRAFFIC_AGENT_RESET_TLV + 0x01) /* 9 */ + +/* STATION/DUT Commands */ +#define WFA_STA_GET_IP_CONFIG_TLV (WFA_TRAFFIC_AGENT_STATUS_TLV + 0x01) +#define WFA_STA_SET_IP_CONFIG_TLV (WFA_STA_GET_IP_CONFIG_TLV + 0x01) +#define WFA_STA_GET_MAC_ADDRESS_TLV (WFA_STA_SET_IP_CONFIG_TLV + 0x01) +#define WFA_STA_SET_MAC_ADDRESS_TLV (WFA_STA_GET_MAC_ADDRESS_TLV + 0x01) +#define WFA_STA_IS_CONNECTED_TLV (WFA_STA_SET_MAC_ADDRESS_TLV + 0x01) +#define WFA_STA_VERIFY_IP_CONNECTION_TLV (WFA_STA_IS_CONNECTED_TLV + 0x01) +#define WFA_STA_GET_BSSID_TLV (WFA_STA_VERIFY_IP_CONNECTION_TLV + 0x01) +#define WFA_STA_GET_STATS_TLV (WFA_STA_GET_BSSID_TLV + 0x01) /* 17 */ +#define WFA_STA_SET_ENCRYPTION_TLV (WFA_STA_GET_STATS_TLV + 0x01) +#define WFA_STA_SET_PSK_TLV (WFA_STA_SET_ENCRYPTION_TLV + 0x01) +#define WFA_STA_SET_EAPTLS_TLV (WFA_STA_SET_PSK_TLV + 0x01) +#define WFA_STA_SET_UAPSD_TLV (WFA_STA_SET_EAPTLS_TLV + 0x01) +#define WFA_STA_ASSOCIATE_TLV (WFA_STA_SET_UAPSD_TLV + 0x01) +#define WFA_STA_SET_EAPTTLS_TLV (WFA_STA_ASSOCIATE_TLV + 0x01) +#define WFA_STA_SET_EAPSIM_TLV (WFA_STA_SET_EAPTTLS_TLV + 0x01) +#define WFA_STA_SET_PEAP_TLV (WFA_STA_SET_EAPSIM_TLV + 0x01) +#define WFA_STA_SET_IBSS_TLV (WFA_STA_SET_PEAP_TLV + 0x01) +#define WFA_STA_GET_INFO_TLV (WFA_STA_SET_IBSS_TLV + 0x01) +#define WFA_DEVICE_GET_INFO_TLV (WFA_STA_GET_INFO_TLV + 0x01) +#define WFA_DEVICE_LIST_IF_TLV (WFA_DEVICE_GET_INFO_TLV + 0x01) /* 29 */ + +#define WFA_STA_DEBUG_SET_TLV (WFA_DEVICE_LIST_IF_TLV + 0x01) /* 30 */ +#define WFA_STA_SET_MODE_TLV (WFA_STA_DEBUG_SET_TLV + 0x01) /* 31 */ +#define WFA_STA_SET_WMM_TLV (WFA_STA_SET_MODE_TLV + 0x01) /* 32 */ +#define WFA_STA_SEND_NEIGREQ_TLV (WFA_STA_SET_WMM_TLV + 0x01) /* 33 */ +#define WFA_STA_SET_SYSTIME_TLV (WFA_STA_SEND_NEIGREQ_TLV + 0x01) +#define WFA_STA_SET_11N_TLV (WFA_STA_SET_SYSTIME_TLV + 0x01) +#define WFA_STA_SET_RIFS_TEST_TLV (WFA_STA_SET_11N_TLV + 0x01) +#define WFA_STA_SET_WIRELESS_TLV (WFA_STA_SET_RIFS_TEST_TLV + 0x01) +#define WFA_STA_SEND_ADDBA_TLV (WFA_STA_SET_WIRELESS_TLV + 0x01) +#define WFA_STA_SEND_COEXIST_MGMT_TLV (WFA_STA_SEND_ADDBA_TLV + 0x01) +#define WFA_STA_DISCONNECT_TLV (WFA_STA_SEND_COEXIST_MGMT_TLV + 0x01) +#define WFA_STA_SET_EAPFAST_TLV (WFA_STA_DISCONNECT_TLV + 0x01) +#define WFA_STA_SET_EAPAKA_TLV (WFA_STA_SET_EAPFAST_TLV + 0x01) +#define WFA_STA_REASSOCIATE_TLV (WFA_STA_SET_EAPAKA_TLV + 0x01) /* 43 */ +#define WFA_STA_SET_PWRSAVE_TLV (WFA_STA_REASSOCIATE_TLV + 0x01) /* 44 */ +#define WFA_STA_RESET_DEFAULT_TLV (WFA_STA_SET_PWRSAVE_TLV + 0x01) /* 45 */ +#define WFA_STA_COMMANDS_END (WFA_STA_RESET_DEFAULT_TLV + 0x01) /* 46 */ + + +/* Version response */ +#define WFA_GET_VERSION_RESP_TLV (WFA_STA_COMMANDS_END + 0x01) /* 47 */ + +/* Generic Traffic Generator Responses */ +#define WFA_TRAFFIC_SEND_PING_RESP_TLV (WFA_GET_VERSION_RESP_TLV + 0x01) +#define WFA_TRAFFIC_STOP_PING_RESP_TLV (WFA_TRAFFIC_SEND_PING_RESP_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_CONFIG_RESP_TLV (WFA_TRAFFIC_STOP_PING_RESP_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_SEND_RESP_TLV (WFA_TRAFFIC_AGENT_CONFIG_RESP_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV (WFA_TRAFFIC_AGENT_SEND_RESP_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV (WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_RESET_RESP_TLV (WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV + 0x01) +#define WFA_TRAFFIC_AGENT_STATUS_RESP_TLV (WFA_TRAFFIC_AGENT_RESET_RESP_TLV + 0x01) + +/* STATION/DUT Responses */ +#define WFA_STA_GET_IP_CONFIG_RESP_TLV (WFA_TRAFFIC_AGENT_STATUS_RESP_TLV + 0x01) +#define WFA_STA_SET_IP_CONFIG_RESP_TLV (WFA_STA_GET_IP_CONFIG_RESP_TLV + 0x01) +#define WFA_STA_GET_MAC_ADDRESS_RESP_TLV (WFA_STA_SET_IP_CONFIG_RESP_TLV + 0x01) +#define WFA_STA_SET_MAC_ADDRESS_RESP_TLV (WFA_STA_GET_MAC_ADDRESS_RESP_TLV + 0x01) /* 59 */ +#define WFA_STA_IS_CONNECTED_RESP_TLV (WFA_STA_SET_MAC_ADDRESS_RESP_TLV + 0x01) +#define WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV (WFA_STA_IS_CONNECTED_RESP_TLV + 0x01) /* 61 */ +#define WFA_STA_GET_BSSID_RESP_TLV (WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV + 0x01) /* 62 */ +#define WFA_STA_GET_STATS_RESP_TLV (WFA_STA_GET_BSSID_RESP_TLV + 0x01) +#define WFA_STA_SET_ENCRYPTION_RESP_TLV (WFA_STA_GET_STATS_RESP_TLV + 0x01) +#define WFA_STA_SET_PSK_RESP_TLV (WFA_STA_SET_ENCRYPTION_RESP_TLV + 0x01) +#define WFA_STA_SET_EAPTLS_RESP_TLV (WFA_STA_SET_PSK_RESP_TLV + 0x01) +#define WFA_STA_SET_UAPSD_RESP_TLV (WFA_STA_SET_EAPTLS_RESP_TLV + 0x01) +#define WFA_STA_ASSOCIATE_RESP_TLV (WFA_STA_SET_UAPSD_RESP_TLV + 0x01) +#define WFA_STA_SET_EAPTTLS_RESP_TLV (WFA_STA_ASSOCIATE_RESP_TLV + 0x01) +#define WFA_STA_SET_EAPSIM_RESP_TLV (WFA_STA_SET_EAPTTLS_RESP_TLV + 0x01) +#define WFA_STA_SET_PEAP_RESP_TLV (WFA_STA_SET_EAPSIM_RESP_TLV + 0x01) +#define WFA_STA_SET_IBSS_RESP_TLV (WFA_STA_SET_PEAP_RESP_TLV + 0x01) +#define WFA_STA_GET_INFO_RESP_TLV (WFA_STA_SET_IBSS_RESP_TLV + 0x01) +#define WFA_DEVICE_GET_INFO_RESP_TLV (WFA_STA_GET_INFO_RESP_TLV + 0x01) +#define WFA_DEVICE_LIST_IF_RESP_TLV (WFA_DEVICE_GET_INFO_RESP_TLV + 0x01) + +#define WFA_STA_DEBUG_SET_RESP_TLV (WFA_DEVICE_LIST_IF_RESP_TLV + 0x01) +#define WFA_STA_SET_MODE_RESP_TLV (WFA_STA_DEBUG_SET_RESP_TLV + 0x01) /* 77 */ +#define WFA_STA_SET_WMM_RESP_TLV (WFA_STA_SET_MODE_RESP_TLV + 0x01) /* 78 */ +#define WFA_STA_SEND_NEIGREQ_RESP_TLV (WFA_STA_SET_WMM_RESP_TLV + 0x01) /* neighbor request */ +#define WFA_STA_SET_SYSTIME_RESP_TLV (WFA_STA_SEND_NEIGREQ_RESP_TLV + 0x01) +#define WFA_STA_SET_11N_RESP_TLV (WFA_STA_SET_SYSTIME_RESP_TLV + 0x01) +#define WFA_STA_SET_RIFS_TEST_RESP_TLV (WFA_STA_SET_11N_RESP_TLV + 0x01) +#define WFA_STA_SET_WIRELESS_RESP_TLV (WFA_STA_SET_RIFS_TEST_RESP_TLV + 0x01) +#define WFA_STA_SEND_ADDBA_RESP_TLV (WFA_STA_SET_WIRELESS_RESP_TLV + 0x01) +#define WFA_STA_SEND_COEXIST_MGMT_RESP_TLV (WFA_STA_SEND_ADDBA_RESP_TLV + 0x01) +#define WFA_STA_DISCONNECT_RESP_TLV (WFA_STA_SEND_COEXIST_MGMT_RESP_TLV + 0x01) +#define WFA_STA_SET_EAPFAST_RESP_TLV (WFA_STA_DISCONNECT_RESP_TLV + 0x01) +#define WFA_STA_SET_EAPAKA_RESP_TLV (WFA_STA_SET_EAPFAST_RESP_TLV + 0x01) +#define WFA_STA_REASSOCIATE_RESP_TLV (WFA_STA_SET_EAPAKA_RESP_TLV + 0x01) /* 72 */ +#define WFA_STA_SET_PWRSAVE_RESP_TLV (WFA_STA_REASSOCIATE_RESP_TLV + 0x01) /* 73 */ +#define WFA_STA_RESET_DEFAULT_RESP_TLV (WFA_STA_SET_PWRSAVE_RESP_TLV + 0x01) +#define WFA_STA_RESPONSE_END (WFA_STA_RESET_DEFAULT_RESP_TLV + 0x01) + +#else +//Hardcode these value MindTree to avoid compilation issues +#define WFA_GET_VERSION_TLV 0x01 + +#define WFA_TRAFFIC_SEND_PING_TLV 0x02 +#define WFA_TRAFFIC_STOP_PING_TLV 0x03 +#define WFA_TRAFFIC_AGENT_CONFIG_TLV 0x04 +#define WFA_TRAFFIC_AGENT_SEND_TLV 0x05 +#define WFA_TRAFFIC_AGENT_RECV_START_TLV 0x06 +#define WFA_TRAFFIC_AGENT_RECV_STOP_TLV 0x07 +#define WFA_TRAFFIC_AGENT_RESET_TLV 0x08 +#define WFA_TRAFFIC_AGENT_STATUS_TLV 0x09 /* 9 */ + +/* STATION/DUT Commands */ +#define WFA_STA_GET_IP_CONFIG_TLV 0x0a +#define WFA_STA_SET_IP_CONFIG_TLV 0x0b +#define WFA_STA_GET_MAC_ADDRESS_TLV 0x0c +#define WFA_STA_SET_MAC_ADDRESS_TLV 0x0d +#define WFA_STA_IS_CONNECTED_TLV 0x0e +#define WFA_STA_VERIFY_IP_CONNECTION_TLV 0x0f +#define WFA_STA_GET_BSSID_TLV 0x10 +#define WFA_STA_GET_STATS_TLV 0x11 /* 17 */ +#define WFA_STA_SET_ENCRYPTION_TLV 0x12 +#define WFA_STA_SET_PSK_TLV 0x13 +#define WFA_STA_SET_EAPTLS_TLV 0x14 +#define WFA_STA_SET_UAPSD_TLV 0x15 +#define WFA_STA_ASSOCIATE_TLV 0x16 +#define WFA_STA_SET_EAPTTLS_TLV 0x17 +#define WFA_STA_SET_EAPSIM_TLV 0x18 +#define WFA_STA_SET_PEAP_TLV 0x19 +#define WFA_STA_SET_IBSS_TLV 0x1a +#define WFA_STA_GET_INFO_TLV 0x1b +#define WFA_DEVICE_GET_INFO_TLV 0x1c +#define WFA_DEVICE_LIST_IF_TLV 0x1d /* 29 */ + +#define WFA_STA_DEBUG_SET_TLV 0x1e /* 30 */ +#define WFA_STA_SET_MODE_TLV 0x1f /* 31 */ +#define WFA_STA_SET_WMM_TLV 0x20 /* 32 */ +#define WFA_STA_SEND_NEIGREQ_TLV 0x21 /* 33 */ +#define WFA_STA_SET_SYSTIME_TLV 0x22 +#define WFA_STA_SET_11N_TLV 0x23 +#define WFA_STA_SET_RIFS_TEST_TLV 0x24 +#define WFA_STA_SET_WIRELESS_TLV 0x25 +#define WFA_STA_SEND_ADDBA_TLV 0x26 +#define WFA_STA_SEND_COEXIST_MGMT_TLV 0x27 +#define WFA_STA_DISCONNECT_TLV 0x28 +#define WFA_STA_SET_EAPFAST_TLV 0x29 +#define WFA_STA_SET_EAPAKA_TLV 0x2a +#define WFA_STA_REASSOCIATE_TLV 0x2b +#define WFA_STA_SET_PWRSAVE_TLV 0x2c +#define WFA_STA_RESET_DEFAULT_TLV 0x2d +#define WFA_STA_COMMANDS_END 0x2e /* 46 */ + + +/* Version response */ +#define WFA_GET_VERSION_RESP_TLV 0x2f /* 47 */ + +/* Generic Traffic Generator Responses */ +#define WFA_TRAFFIC_SEND_PING_RESP_TLV 0x30 +#define WFA_TRAFFIC_STOP_PING_RESP_TLV 0x31 +#define WFA_TRAFFIC_AGENT_CONFIG_RESP_TLV 0x32 +#define WFA_TRAFFIC_AGENT_SEND_RESP_TLV 0x33 +#define WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV 0x34 +#define WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV 0x35 +#define WFA_TRAFFIC_AGENT_RESET_RESP_TLV 0x36 +#define WFA_TRAFFIC_AGENT_STATUS_RESP_TLV 0x37 + +/* STATION/DUT Responses */ +#define WFA_STA_GET_IP_CONFIG_RESP_TLV 0x38 +#define WFA_STA_SET_IP_CONFIG_RESP_TLV 0x39 +#define WFA_STA_GET_MAC_ADDRESS_RESP_TLV 0x3a +#define WFA_STA_SET_MAC_ADDRESS_RESP_TLV 0x3b /* 59 */ +#define WFA_STA_IS_CONNECTED_RESP_TLV 0x3c +#define WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV 0x40 /* 61 */ +#define WFA_STA_GET_BSSID_RESP_TLV 0x3e /* 62 */ +#define WFA_STA_GET_STATS_RESP_TLV 0x3f +#define WFA_STA_SET_ENCRYPTION_RESP_TLV 0x40 +#define WFA_STA_SET_PSK_RESP_TLV 0x41 +#define WFA_STA_SET_EAPTLS_RESP_TLV 0x42 +#define WFA_STA_SET_UAPSD_RESP_TLV 0x43 +#define WFA_STA_ASSOCIATE_RESP_TLV 0x44 +#define WFA_STA_SET_EAPTTLS_RESP_TLV 0x45 +#define WFA_STA_SET_EAPSIM_RESP_TLV 0x46 +#define WFA_STA_SET_PEAP_RESP_TLV 0x47 +#define WFA_STA_SET_IBSS_RESP_TLV 0x48 +#define WFA_STA_GET_INFO_RESP_TLV 0x49 +#define WFA_DEVICE_GET_INFO_RESP_TLV 0x4a +#define WFA_DEVICE_LIST_IF_RESP_TLV 0x4b + +#define WFA_STA_DEBUG_SET_RESP_TLV 0x4c +#define WFA_STA_SET_MODE_RESP_TLV 0x4d /* 77 */ +#define WFA_STA_SET_WMM_RESP_TLV 0x4e /* 78 */ +#define WFA_STA_SEND_NEIGREQ_RESP_TLV 0x4f +#define WFA_STA_SET_SYSTIME_RESP_TLV 0x50 +#define WFA_STA_SET_11N_RESP_TLV 0x51 +#define WFA_STA_SET_RIFS_TEST_RESP_TLV 0x52 +#define WFA_STA_SET_WIRELESS_RESP_TLV 0x53 +#define WFA_STA_SEND_ADDBA_RESP_TLV 0x54 +#define WFA_STA_SEND_COEXIST_MGMT_RESP_TLV 0x55 +#define WFA_STA_DISCONNECT_RESP_TLV 0x56 +#define WFA_STA_SET_EAPFAST_RESP_TLV 0x57 +#define WFA_STA_SET_EAPAKA_RESP_TLV 0x58 +#define WFA_STA_REASSOCIATE_RESP_TLV 0x59 +#define WFA_STA_SET_PWRSAVE_RESP_TLV 0x5a +#define WFA_STA_RESET_DEFAULT_RESP_TLV 0x5b +#define WFA_STA_RESPONSE_END 0x5c +#define WFA_TLV_END WFA_STA_RESPONSE_END +#endif //MindTree + +#define WFA_TLV_HEAD_LEN 1+2 + +extern WORD wfaGetTag(BYTE *tlv_data); +extern void wfaSetTag(BYTE *tlv_data, BYTE new_tag); +extern WORD wfaGetTLVLen(BYTE *tlv_data); +extern WORD wfaGetValueLen(BYTE *tlv_data); +extern BOOL wfaGetValue(BYTE *pstr, int value_len, BYTE *tlv_data); +extern BOOL wfaIsValidTag(BYTE the_tag); +extern void wfaAliasByTag(BYTE the_tag, char *aliasStr); +extern BOOL wfaDecodeTLV(BYTE *tlv_data, int tlv_len, BYTE *ptlv_tag, int *ptlv_val_len, BYTE *ptlv_value); +extern BOOL wfaEncodeTLV(WORD the_tag, WORD the_len, BYTE *the_value, BYTE *tlv_data); + +extern WORD wfaGetValueType(BYTE the_tag, BYTE *tlv_data); + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_types.h b/src/tools/Wifi_ASD_test/inc/wfa_types.h new file mode 100644 index 0000000..00217fa --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_types.h
@@ -0,0 +1,111 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + /* Revision History: + * 11/07/07 02.30 Voice HSO -- qhu + * -- change FALSE to -1 -- a bug reported by rmaeder + * socket may be a 0 + */ + +/* + * wfa_types.h: + * Defines general types and enum + */ +#ifndef _WFA_TYPES_H +#define _WFA_TYPES_H + +#define WFA_IF_NAME_LEN 16 +#define WFA_VERSION_LEN 16 +#define WFA_SSID_NAME_LEN 64 +#define WFA_IP_ADDR_STR_LEN 16 +#define WFA_IP_MASK_STR_LEN 16 +#define WFA_MAX_DNS_NUM 2 +#define WFA_MAC_ADDR_STR_LEN 20 +#define WFA_DEFAULT_PROG_NAME 16 + +#define IF_80211 1 +#define IF_ETH 2 +/* only if test bed */ +#ifdef WFA_STA_TB +#define INTOLERANT_LEN 5 +#define CHNL_LIST 20 +#define WIRELESS_BAND 10 +#endif + +/* WMM-AC APSD defines*/ +#ifdef WFA_WMM_AC +#define DIR_NONE 0 +#define DIR_UP 1 +#define DIR_DOWN 2 +#define DIR_BIDIR 3 +#endif + +typedef unsigned short WORD; +typedef unsigned char BYTE; + +enum _response_staus +{ + STATUS_RUNNING = 0x0001, + STATUS_INVALID = 0x0002, + STATUS_ERROR = 0x0003, + STATUS_COMPLETE = 0x0004, +}; + +typedef int BOOL; + +#ifndef TRUE + #define FALSE -1 + #define TRUE 0 + #define DONE 1 +#endif + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_ver.h b/src/tools/Wifi_ASD_test/inc/wfa_ver.h new file mode 100644 index 0000000..403bc1f --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_ver.h
@@ -0,0 +1,64 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + + +#ifndef WFA_VER_H +#define WFA_VER_H + +/* + * Voice Personel support E2E + * 11N support + */ +#define WFA_SYSTEM_VER "03.00" + +#endif
diff --git a/src/tools/Wifi_ASD_test/inc/wfa_wmmps.h b/src/tools/Wifi_ASD_test/inc/wfa_wmmps.h new file mode 100644 index 0000000..628dee8 --- /dev/null +++ b/src/tools/Wifi_ASD_test/inc/wfa_wmmps.h
@@ -0,0 +1,244 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + +/* + * * APTS messages/tests + * */ +#ifndef _WFA_WMMPS_H_ +#define _WFA_WMMPS_H_ +#define B_D 1 +#define B_H 2 +#define B_B 3 +#define B_M 4 +#define M_D 5 +#define B_Z 6 +#define M_Y 7 +#define L_1 8 +#define A_Y 9 // active mode version of M_Y +#define B_W 10 // +#define A_J 11 // Active test of sending 4 down +#define M_V 12 +#define M_U 13 +#define A_U 14 +#define M_L 15 +#define B_K 16 +#define M_B 17 +#define M_K 18 +#define M_W 19 +#ifdef WFA_WMM_AC +#define ATC1 20 +#define ATC2 21 +#define ATC3 22 +#define ATC4 23 +#define ATC5 24 +#define ATC6 25 +#define ATC7 26 +#define ATC8 27 +#define ATC9 28 +#define ATC10 29 +#define ATC11 30 +#define STC1 31 +#define STC2 32 +#define STC3 33 +#define LAST_TEST STC3 +#else +#define LAST_TEST M_W +#endif /* WFA_WMM_AC */ +#define APTS_DEFAULT (LAST_TEST + 0x01) // message codes +#define APTS_HELLO (APTS_DEFAULT + 0x01) +#define APTS_BCST (APTS_HELLO + 0x01) +#define APTS_CONFIRM (APTS_BCST + 0x01) +#define APTS_STOP (APTS_CONFIRM + 0x01) +#define APTS_CK_BE (APTS_STOP + 0x01) +#define APTS_CK_BK (APTS_CK_BE + 0x01) +#define APTS_CK_VI (APTS_CK_BK + 0x01) +#define APTS_CK_VO (APTS_CK_VI + 0x01) +#define APTS_RESET (APTS_CK_VO + 0x01) +#define APTS_RESET_RESP (APTS_RESET + 0x01) +#define APTS_RESET_STOP (APTS_RESET_RESP + 0x01) +#define APTS_LAST 99 +//#define WFA_THREADS_NUM 1 +#define MAXRETRY 3 +#define MAXHELLO 20 +#define MAX_STOPS 10 +#define NTARG 32 // number of target names +#define EQ(a,b) (strcmp(a,b)==0) + +#define PORT 12345 // use a common port for sending/receiving +#define LII 2000000 +#ifdef WFA_WMM_AC +/*Listen Inteval for station,to be changed to the actual value*/ +#define lis_int 500000 +#define becon_int 100000 +#endif +#define NTARG 32 + +#define WFA_DEFAULT_CODEC_SEC 0 +#define WFA_DEFAULT_CODEC_USEC 10000 + +#define WFA_WMMPS_UDP_PORT 12345 // it must sync with console + +/* wmm defs */ +#define TOS_VO7 0xE0 // 111 0 0000 (7) AC_VO tos/dscp values +#define TOS_VO 0xD0 // 110 0 0000 (6) AC_VO tos/dscp values +//Atheros Madwifi use 0x88 for UPSD/Voice +//#define TOS_VO 0x88 // 110 0 0000 (6) AC_VO tos/dscp values + +#define TOS_VI 0xA0 // 101 0 0000 (5) AC_VI +#define TOS_VI4 0x80 // 100 0 0000 (4) AC_VI + +#define TOS_BE 0x00 // 000 0 0000 (0) AC_BE +#define TOS_EE 0x60 // 011 0 0000 (3) AC_BE + +#define TOS_BK 0x20 // 001 0 0000 (1) AC_BK +#define TOS_LE 0x40 // 010 0 0000 (2) AC_BK + + +/* + * * power management + * */ +#define PS_ON 1 +#define PS_OFF 0 +#define P_ON 1 +#define P_OFF 0 + +#ifndef WIN32 +#if WFA_DEBUG +#define PRINTF(s,args...) printf(s,## args) +#else +#define PRINTF(s,args...) ; +#endif /* WFA_DEBUG */ +#else +#define PRINTF +#endif /* !WIN32 */ + +extern int wl_set (void* wl,int cmd, void* buf,int len); +extern int WmmpsTrafficRecv(int sock, char *buf, struct sockaddr *from); +/* + * * internal table + * */ +struct apts_msg { // + char *name; // name of test + int cmd; // msg num + int param0; // number of packet exchanges + int param1; // number of uplink frames + int param2; // number of downlink frames + int param3; +}; + +/* + * * Wait/Timer states + * */ +typedef enum { + WFA_WAIT_NEXT_CODEC, + WFA_WAIT_FOR_AP_RESPONSE, + WFA_WAIT_STAUT_00, + WFA_WAIT_STAUT_01, + WFA_WAIT_STAUT_02, + WFA_WAIT_STAUT_03, + WFA_WAIT_STAUT_04, + WFA_WAIT_STAUT_0E, + WFA_WAIT_STAUT_VOLOAD, + WFA_WAIT_STAUT_SEQ, +} WAIT_MODE; + +typedef struct wfa_wmmps +{ + int my_sta_id; + int my_group_cookie; + int my_cookie; + int thr_flag; + int sta_state; + int sta_test; + int wait_state; + int nextsleep; + int nsent; + int msgno; + int ps_thread; + int rcv_state; + int dscp; + int reset; + int streamid; + tgThrData_t *tdata; + struct sockaddr_in psToAddr; +#ifndef WIN32 + pthread_t thr; + pthread_cond_t thr_flag_cond; + pthread_mutex_t thr_flag_mutex; +#endif +}wfaWmmPS_t; + + + +int WfaStaSndHello(char,int,int *state); +int WfaStaSndConfirm(char,int,int *state); +int WfaStaSndVO(char,int,int *state); +int WfaStaSndVOCyclic(char,int,int *state); +int WfaStaSnd2VO(char,int,int *state); +int WfaStaWaitStop(char,int,int *state); +int WfaStaSndVI(char,int,int *state); +int WfaStaSndBE(char,int,int *state); +int WfaStaSndBK(char,int,int *state); +int WfaStaSndVIE(char,int,int *state); +//int WfaStaSndVO(char,int,int *state); +int WfaStaSndBEE(char,int,int *state); +int WfaStaSnd2VOE(char,int,int *state); +void create_apts_msg(int msg, unsigned int txbuf[],int id); +int WfaRcvStop(unsigned int *,int ,int *); +int WfaRcvVO(unsigned int *,int ,int *); +int WfaRcvProc(unsigned int *,int ,int *); +int WfaRcvVOCyclic(unsigned int *,int ,int *); +int WfaRcvVI(unsigned int *,int ,int *); +int WfaRcvBE(unsigned int *,int ,int *); +int WfaRcvBK(unsigned int *,int ,int *); +#endif
diff --git a/src/tools/Wifi_ASD_test/lib/Makefile b/src/tools/Wifi_ASD_test/lib/Makefile new file mode 100644 index 0000000..9495713 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/Makefile
@@ -0,0 +1,36 @@ +ifndef SRCBASE + SRCBASE = ../../.. +endif + +include ../../../Makerules +include ../Makefile.inc + + +all: ${LIB_OBJS} + + $(AR) crv ${LIBWFA_NAME} $? + $(AR) crv ${LIBWFA_NAME_CA} $? + +#add dut lib to this ranlib for normal ASD (without RWL) + ${RANLIB} ${LIBWFA_NAME} ${LIBWFA_NAME_CA} + +vpath %.c $(SRCBASE)/tools/Wifi_ASD_test/dut + + +../dut/$(TARGETARCH)/%.o: %.c + @mkdir -p ../dut/$(TARGETARCH) + $(CC) -c $(CFLAGS) -o $@ $^ + +$(TARGETARCH)/%.o: %.c + @mkdir -p $(TARGETARCH) + $(CC) -c $(CFLAGS) -o $@ $^ + +clean: + rm -f ${PROGS} ${CLEANFILES} + rm -rf x86_mmx arm_le + +release_bins: + @mkdir -p $(INSTALL_DIR)/$(TARGETARCH) + install ${LIBWFA_NAME} ${LIBWFA_NAME_CA} $(INSTALL_DIR)/$(TARGETARCH) + +.phony: all clean release_bins
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_ca.c b/src/tools/Wifi_ASD_test/lib/wfa_ca.c new file mode 100644 index 0000000..c736987 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_ca.c
@@ -0,0 +1,1539 @@ + +/**************************************************************************** + * (c) Copyright 2006 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated Wi-Fi + * contractors ("Authorized Licensees"). Authorized Licensees are hereby + * granted the limited right to use this software solely for noncommercial + * applications and solely for testing Wi-Fi equipment. Authorized Licensees + * may embed this software into their proprietary equipment and distribute this + * software with such equipment under a license with at least the same + * restrictions as contained in this License, including, without limitation, + * the disclaimer of warranty and limitation of liability, below. Other than + * expressly granted herein, this License is not transferable or sublicensable, + * and it does not extend to and may not be used with non-Wi-Fi applications. + * + * Commercial derivative works of this software or applications that use the + * Wi-Fi scripts generated by this software are NOT AUTHORIZED without specific + * prior written permission from Wi-Fi Alliance. + * + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi with a copy of such + * derivative works under a perpetual, payment-free license to use, modify, + * and distribute such derivative works for purposes of testing Wi-Fi equipment. + * + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************** + */ + + +/* + * File: wfa_ca.c + * This file contains all implementation for the dut setup and control + * functions, such as network interfaces, ip address and wireless specific + * setup with its supplicant. + * + * The current implementation is to show how these functions + * should be defined in order to support the Agent Control/Test Manager + * control commands. To simplify the current work and avoid any GPL licenses, + * the functions mostly invoke shell commands by calling linux system call, + * system("<commands>"). + * + * It depends on the differnt device and platform, vendors can choice their + * own ways to interact its systems, supplicants and process these commands + * such as using the native APIs. + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA Release by qhu + * 2006/06/13 -- 00.02 Release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/09/01 -- 01.05 Release by qhu + * 2006/10/26 -- 01.06 Release by qhu + * replace hardcoded buff size with gloabal macro + * 2006/12/02 -- + * bugs: 1. fixes incorrect order of getipconfig.sh + * input parameters reported by p.schwann + * 2. will add a new network for wap_cli command + * in case the network id 0 not present, + * recommended by c.benson + * the solution is to reimplement with calling + * native C API + * 2007/01/11 -- 01.10 release by qhu + * + */ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <linux/types.h> +#include <linux/socket.h> +#include <iwlib.h> +#include <wireless.h> + +#include "wfa_debug.h" +#include "wfa_ver.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_ca.h" +#include "wfa_tlv.h" +#include "wfa_sock.h" +#include "wfa_tg.h" +#include "wfa_cmds.h" +#include "wfa_rsp.h" + +/* + * atheros wireless interface madwifi driver include files + * You may remove them if using other device interface + */ +#include "xtn/compat.h" +#include "xtn/_ieee80211.h" +#include "xtn/ieee80211_crypto.h" +#include "xtn/ieee80211.h" +#include "xtn/ieee80211_ioctl.h" +#include "xtn/if_athioctl.h" + +#define CERTIFICATES_PATH "/etc/wpa_supplicant" + +extern unsigned short wfa_defined_debug; + +/* error code */ +#define BCM_OK 0 +#define BCM_BAD 1 + +#define BCM_SSID_LEN_MAX 32 +#define BCM_SSID_MAX 32 + +/* defines for BSS types */ +#define BCM_BSS_INVALID 0 +#define BCM_BSS_INDEPENDENT 1 +#define BCM_BSS_INFRA 3 +#define BCM_BSS_AUTO 4 + +/* defines for WPA AITHENTICATION */ +#define BCM_WPA_AUTH_DISABLED 0x0 +#define BCM_WPA_AUTH_NONE 0x1 +#define BCM_WPA_AUTH_8021X 0x2 +#define BCM_WPA_AUTH_PSK 0x4 +#define BCM_WPA2_AUTH_8021X 0x40 +#define BCM_WPA2_AUTH_PSK 0x80 + +#define BCM_WEP_KEY_SIZE_MAX 32 + +#define BCM_PRI_KEY_BAD (-1) + +typedef struct bcmSsidObj +{ + char ssidStr[BCM_SSID_LEN_MAX]; + int bssType; + int channel; + int wsec; + int auth; /* 802.11 authentication : default 0 for open. */ + int wpa_auth; /* WPA authentication: default 1 for WPA-NONE */ + int uapsd; + char keys[4][BCM_WEP_KEY_SIZE_MAX]; /* wl addwep */ + int primary_key; + BYTE passphrase[64]; /* wl set_pmk */ + int powerSave; + /* UAPSD */ + int maxSPLength; + int acBE; + int acBK; + int acVI; + int acVO; +} bcmSsidObj_t; + +typedef struct bcmSsidObjTbl +{ + bcmSsidObj_t ssidObj[BCM_SSID_MAX]; + uint addCnt; + uint delCnt; + uint entries; +} bcmSsidObjTbl_t; + +bcmSsidObjTbl_t bsotbl; +int bcmSsidIsGood(char *ssidStr); +bcmSsidObj_t *bcmWfaSsidTblFreeEntry(); +bcmSsidObj_t *bcmWfaSsidTblSsidFind(char *ssidStr); +bcmSsidObj_t *bcmWfaSsidObjTblAdd(char *ssidStr); +void bcmWfaSsidObjTblDel(char *ssidStr); +void bcmWfaSsidObjPrint(bcmSsidObj_t *bso); +void bcmWfaSsidObjTblPrint(void); + +/* + * agtCmdProcGetVersion(): response "ca_get_version" command to controller + * input: cmd --- not used + * valLen -- not used + * output: parms -- a buffer to store the version info response. + */ +int agtCmdProcGetVersion(int len, BYTE *parms, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t getverResp; + + DPRINT_INFO(WFA_OUT, "entering agtCmdProcGetVersion ...\n"); + + getverResp.status = STATUS_COMPLETE; + strncpy(getverResp.cmdru.version, WFA_SYSTEM_VER, 8); + + wfaEncodeTLV(WFA_GET_VERSION_RESP_TLV, sizeof(getverResp), (BYTE *)&getverResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(getverResp); + + return TRUE; +} + +extern int gxcSockfd; + +/* + * wfaStaAssociate(): + * The function is to force the station wireless I/F to re/associate + * with the AP. + */ +int wfaStaAssociate(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + int retVal = TRUE; + dutCommand_t *assoc = (dutCommand_t *)caCmdBuf; + char cmdStr[WFA_CMD_STR_SZ]; + int imode; /* 0 for ibss, 1 for infrastructure */ + char ssidTarget[WFA_SSID_NAME_LEN]; + bcmSsidObj_t *bso; + int idx; + + bcopy(assoc->cmdsu.ssid, ssidTarget, WFA_SSID_NAME_LEN); + + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + retVal = FALSE; + goto exit; + } + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + } + imode = (bso->bssType == BCM_BSS_INDEPENDENT) ? 0 : 1; + + sprintf(cmdStr, "/tmp/ASD/wl disassoc"); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl down"); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + /* handle WEP keys */ + for(idx = 0; idx < 4; idx++) { + if(bso->keys[idx][0] != '\0') { + sprintf(cmdStr, "/tmp/ASD/wl addwep %d %s", idx, bso->keys[idx]); + } else { + sprintf(cmdStr, "/tmp/ASD/wl rmwep %d", idx); + } + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + } + + /* set primary key */ + if(bso->primary_key != BCM_PRI_KEY_BAD) { + sprintf(cmdStr, "/tmp/ASD/wl primary_key %d", bso->primary_key); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + } + + if ((!imode) && bso->channel){ + sprintf(cmdStr, "/tmp/ASD/wl channel %d", bso->channel); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + } + + sprintf(cmdStr, "/tmp/ASD/wl infra %d", imode); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + /* security */ + sprintf(cmdStr, "/tmp/ASD/wl wsec %d", bso->wsec); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + if(bso->passphrase[0] != '\0') { + sprintf(cmdStr, "/tmp/ASD/wl set_pmk %s", bso->passphrase); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + } + + sprintf(cmdStr, "/tmp/ASD/wl auth %d", bso->auth); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl wpa_auth %d", bso->wpa_auth); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + /* Power Save */ + sprintf(cmdStr, "/tmp/ASD/wl wme_apsd_sta %d %d %d %d %d", + bso->maxSPLength, bso->acBE, bso->acBK, bso->acVI, bso->acVO); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl up"); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl ssid '%s'", ssidTarget); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + +exit: + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_ASSOCIATE_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return retVal; +} + +/* + * wfaStaIsConnected(): + * The function is to check whether the station's wireless I/F has + * already connected to an AP. + */ +int wfaStaIsConnected(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + char cmdStr[WFA_CMD_STR_SZ]; + FILE *tmpfd; + dutCmdResponse_t staConnectResp; + + DPRINT_INFO(WFA_OUT, "Entering isConnected ...\n"); + + /* Associated gets long response */ + if ((tmpfd = popen("/tmp/ASD/wl assoc | wc -l", "r")) == NULL){ + printf("wc -l failed\n"); + } + fgets(cmdStr, sizeof(cmdStr), tmpfd); + pclose(tmpfd); + + /* Short response means not associated */ + if (atoi(cmdStr) <= 2) + staConnectResp.cmdru.connected = 0; + else + staConnectResp.cmdru.connected = 1; + + /* + * Report back the status: Complete or Failed. + */ + staConnectResp.status = STATUS_COMPLETE; + + wfaEncodeTLV(WFA_STA_IS_CONNECTED_RESP_TLV, sizeof(staConnectResp), + (BYTE *)&staConnectResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(staConnectResp); + return TRUE; +} + +/* + * wfaStaGetIpConfig(): + * This function is to retriev the ip info including + * 1. dhcp enable + * 2. ip address + * 3. mask + * 4. primary-dns + * 5. secondary-dns + * + * The current implementation is to use a script to find these information + * and store them in a file. + */ +int wfaStaGetIpConfig(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int i; + dutCommand_t *getIpConf = (dutCommand_t *)caCmdBuf; + dutCmdResponse_t ipconfigResp; + char *ifname = getIpConf->intf; + caStaGetIpConfigResp_t *ifinfo = &ipconfigResp.cmdru.getIfconfig; + + FILE *tmpfd; + char string[256]; + + /* Dhcp */ + if ((tmpfd = popen("ps ax | grep -v grep | grep dhcli | wc -l", "r")) == NULL){ + printf("wc -l failed\n"); + } + fgets(string, sizeof(string), tmpfd); + pclose(tmpfd); + if (atoi(string) >= 1) + ifinfo->isDhcp = 1; + else + ifinfo->isDhcp = 0; + + /* ipaddr */ + sprintf(string, "ifconfig %s | grep 'inet addr' | cut -d: -f2 | cut -d' ' -f1", ifname); + if ((tmpfd = popen(string, "r")) == NULL){ + printf("ifconfig addr failed\n"); + } + ifinfo->ipaddr[0] = 0; + fgets(ifinfo->ipaddr, WFA_IP_ADDR_STR_LEN, tmpfd); + ifinfo->ipaddr[strlen(ifinfo->ipaddr) - 1] = 0; /* Purge newline */ + pclose(tmpfd); + if(ifinfo->ipaddr[0] == 0) + strncpy(ifinfo->ipaddr, "none", 15); + + /* mask */ + sprintf(string, "ifconfig %s | grep 'inet addr' | cut -d: -f4", ifname); + if ((tmpfd = popen(string, "r")) == NULL){ + printf("ifconfig mask failed\n"); + } + ifinfo->mask[0] = 0; + fgets(ifinfo->mask, WFA_IP_MASK_STR_LEN, tmpfd); + ifinfo->mask[strlen(ifinfo->mask) - 1] = 0; /* Purge newline */ + pclose(tmpfd); + + if(ifinfo->mask[0] == 0) + strcpy(ifinfo->mask, "none"); + + /* dns */ + if ((tmpfd = popen("cat /etc/resolv.conf | grep nameserver | awk '{print $2}'", "r")) == NULL){ + printf("resolve.conf failed\n"); + } + for (i = 0; i < WFA_MAX_DNS_NUM; i++){ + fgets(ifinfo->dns[i], WFA_MAC_ADDR_STR_LEN, tmpfd); + if (ifinfo->dns[i][0]) + ifinfo->dns[i][strlen(ifinfo->dns[i]) - 1] = 0; /* Purge newline */ + else + strcpy(ifinfo->dns[i], "NOTDEF"); + } + pclose(tmpfd); + + /* + * Report back the results + */ + ipconfigResp.status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_GET_IP_CONFIG_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)&ipconfigResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(caStaGetIpConfigResp_t); + + DPRINT_INFO(WFA_OUT, "%i %i %s %s %s %s %i\n", ipconfigResp.status, + ifinfo->isDhcp, ifinfo->ipaddr, ifinfo->mask, + ifinfo->dns[0], ifinfo->dns[1], *respLen); + + return TRUE; +} + +/* + * wfaStaSetIpConfig(): + * The function is to set the ip configuration to a wireless I/F. + * 1. IP address + * 2. Mac address + * 3. default gateway + * 4. dns nameserver (pri and sec). + */ +int wfaStaSetIpConfig(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCommand_t *setIpConf = (dutCommand_t *)caCmdBuf; + char cmds[128]; + int ret = 0; + caStaSetIpConfig_t *ipconfig = &setIpConf->cmdsu.ipconfig; + + DPRINT_INFO(WFA_OUT, "entering wfaStaSetIpConfig ...\n"); + + /* + * Use command 'ifconfig' to configure the interface ip address, mask. + * (Linux specific). + */ + if (!strlen(ipconfig->intf) || !strlen(ipconfig->ipaddr)){ + ret = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_IP_CONFIG_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + sprintf(cmds, "%s %s %s ", IFCONFIG_PATH, ipconfig->intf, ipconfig->ipaddr); + if (strlen(ipconfig->mask)) + sprintf(&cmds[strlen(cmds)], "netmask %s ", ipconfig->mask); + system(cmds); + DPRINT_INFO(WFA_OUT, "%s\n", "doing ifconfig"); + + /* use command 'route add' to set set gatewway (linux specific) */ + if(ipconfig->defGateway[0]) { + sprintf(cmds, "%s add default gw %s > /dev/null 2>&1", ROUTE_PATH, ipconfig->defGateway); + system(cmds); + DPRINT_INFO(WFA_OUT, "%s\n", "doing route add"); + } + + /* set dns (linux specific) */ + if (ipconfig->pri_dns[0]){ + sprintf(cmds, "cp /etc/resolv.conf /tmp/resolv.conf.bk"); + system(cmds); + sprintf(cmds, "echo nameserv %s > /etc/resolv.conf", ipconfig->pri_dns); + system(cmds); + sprintf(cmds, "echo nameserv %s >> /etc/resolv.conf", ipconfig->sec_dns); + system(cmds); + } + + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_IP_CONFIG_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; +} + +/* + * wfaStaVerifyIpConnection(): + * The function is to verify if the station has IP connection with an AP by + * send ICMP/pings to the AP. + */ +int wfaStaVerifyIpConnection(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCommand_t *verip = (dutCommand_t *)caCmdBuf; + char cmdStr[WFA_CMD_STR_SZ]; + FILE *tmpfile; + dutCmdResponse_t verifyIpResp; + dutCommand_t vvv; + + + DPRINT_INFO(WFA_OUT, "Entering wfaStaVerifyIpConnection ...\n"); + memcpy(&vvv, caCmdBuf, sizeof(dutCommand_t)); + + /* set timeout value in case not set */ + if(verip->cmdsu.verifyIp.timeout <= 0) + verip->cmdsu.verifyIp.timeout = 10; + + /* execute the ping command and pipe the result to a tmp file */ + sprintf(cmdStr, "ping %s -c 3 -W %d | grep '100%%'", verip->cmdsu.verifyIp.dipaddr, verip->cmdsu.verifyIp.timeout); + + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + if (strlen(verip->cmdsu.verifyIp.dipaddr) == 0 || ((tmpfile = popen(cmdStr, "r")) == NULL)){ + int status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + DPRINT_ERR(WFA_ERR, "Could not execute %s\n", cmdStr); + return FALSE; + } + + verifyIpResp.status = STATUS_COMPLETE; + + if (fgets(cmdStr, sizeof(cmdStr), tmpfile) == NULL){ + verifyIpResp.cmdru.connected = 1; + } else{ + verifyIpResp.cmdru.connected = 0; + } + pclose(tmpfile); + + + wfaEncodeTLV(WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)&verifyIpResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return TRUE; +} + +/* + * wfaStaGetMacAddress() + * This function is to retrieve the MAC address of a wireless I/F. + */ +int wfaStaGetMacAddress(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t getmacResp; + FILE *tmpfd; + + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetMacAddress ...\n"); + + if ((tmpfd = popen("/tmp/ASD/wl dump | grep perm | awk '{print $4}'", "r")) == NULL){ + int status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_GET_MAC_ADDRESS_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + DPRINT_ERR(WFA_ERR, "Pipe open for wl dump failed\n"); + return FALSE; + } + fgets(getmacResp.cmdru.mac, sizeof(getmacResp.cmdru.mac), tmpfd); + getmacResp.cmdru.mac[strlen(getmacResp.cmdru.mac) - 1] = 0; /* Get rid of NL */ + printf("get_mac_addr: returning mac :%s:\n", getmacResp.cmdru.mac); + pclose (tmpfd); + getmacResp.status = STATUS_COMPLETE; + + wfaEncodeTLV(WFA_STA_GET_MAC_ADDRESS_RESP_TLV, sizeof(getmacResp), + (BYTE *)&getmacResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(getmacResp); + return TRUE; +} + +/* + * wfaStaGetBSSID(): + * This function is to retrieve BSSID of a specific wireless I/F. + */ +int wfaStaGetBSSID(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + char cmdStr[WFA_CMD_STR_SZ]; + FILE *tmpfd; + dutCmdResponse_t bssidResp; + + /* Associated gets long response */ + if ((tmpfd = popen("/tmp/ASD/wl assoc | wc -l", "r")) == NULL){ + printf("wc -l failed\n"); + } + fgets(cmdStr, sizeof(cmdStr), tmpfd); + pclose(tmpfd); + + /* Short response means not associated */ + if (atoi(cmdStr) <= 2){ + strcpy(bssidResp.cmdru.bssid, "00:00:00:00:00:00"); + } else { + if ((tmpfd = popen("/tmp/ASD/wl bssid", "r")) == NULL){ + printf("bassid failed\n"); + } + fgets(cmdStr, sizeof(cmdStr), tmpfd); + pclose(tmpfd); + cmdStr[17] = 0; /* Get rid of CR or NL */ + strcpy(bssidResp.cmdru.bssid, cmdStr); + } + bssidResp.status = STATUS_COMPLETE; + + wfaEncodeTLV(WFA_STA_GET_BSSID_RESP_TLV, sizeof(bssidResp), + (BYTE *)&bssidResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(bssidResp); + return TRUE; +} + +/* + * wfaStaGetStats(): + * The function is to retrieve the statistics of the I/F's layer 2 txFrames, + * rxFrames, txMulticast, rxMulticast, fcsErrors/crc, and txRetries. + * Currently there is not definition how to use these info. + */ +int wfaStaGetStats(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + caStaGetStatsResp_t statsResp; + FILE *fd; + char cmdStr[256]; + + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetStats ...\n"); + + if ((fd = popen("/tmp/ASD/wl dump stats | grep txframe | awk '{print $2,\"\\n\",$10}'", "r")) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get txframe stats\n"); + goto wfaStaGetStats_error; + } else { + fgets(cmdStr, sizeof(cmdStr), fd); /* line 1: tx frame */ + statsResp.txFrames = atoi(cmdStr); + fgets(cmdStr, sizeof(cmdStr), fd); /* line 2: rx frame */ + statsResp.rxFrames = atoi(cmdStr); + pclose(fd); + } + + if ((fd = popen("/tmp/ASD/wl dump stats | grep txmulti | awk '{print $4, \"\\n\", $6 + $8}'", "r")) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get d11_txmulti stats\n"); + goto wfaStaGetStats_error; + } else { + fgets(cmdStr, sizeof(cmdStr), fd); /* line 1: txmulti */ + statsResp.txMulticast = atoi(cmdStr); + fgets(cmdStr, sizeof(cmdStr), fd); /* line 2: d11_txretry + d11_txretrie */ + statsResp.txRetries = atoi(cmdStr); + pclose(fd); + } + + if ((fd = popen("/tmp/ASD/wl dump stats | grep rxdfrmmcast | awk '{print $6 + $8}'", "r")) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get rxdfrmmcast stats\n"); + goto wfaStaGetStats_error; + } else { + fgets(cmdStr, sizeof(cmdStr), fd); /* data + mngment mcast frames */ + statsResp.rxMulticast = atoi(cmdStr); + pclose(fd); + } + + if ((fd = popen("/tmp/ASD/wl dump stats | grep rxbadfcs | awk '{print $8}'", "r")) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get rxbadfcs stats\n"); + goto wfaStaGetStats_error; + } else { + fgets(cmdStr, sizeof(cmdStr), fd); + statsResp.fcsErrors = atoi(cmdStr); + pclose(fd); + } + + statsResp.status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_GET_STATS_RESP_TLV, sizeof(statsResp), (BYTE *)&statsResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(statsResp); + return TRUE; + +wfaStaGetStats_error: + ret = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_GET_STATS_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return FALSE; +} + +/* + * wfaSetEncryption(): + * The function is to set the wireless interface with WEP or none. + * Input parameters: + * 1. I/F + * 2. ssid + * 3. encpType - wep or none + * Optional: + * 4. key1 + * 5. key2 + * 6. key3 + * 7. key4 + * 8. activeKey Index : 1, 2, 3, or 4 + */ +int wfaSetEncryption(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + int retVal = TRUE; + caStaSetEncryption_t *setEncryp = (caStaSetEncryption_t *)caCmdBuf; + int idx; + bcmSsidObj_t *bso; + char * ssidStr; + + DPRINT_INFO(WFA_OUT, "wfaSetEncryption()\n"); + + /* Save the settings for when we need them */ + + ssidStr = setEncryp->ssid; + + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + /* set Key management to NONE (NO WPA) for plaintext or WEP */ + bso->wpa_auth = BCM_WPA_AUTH_DISABLED; + + for(idx = 0; idx < 4; idx++) { + if(setEncryp->keys[idx][0] != '\0') { + strcpy(bso->keys[idx], setEncryp->keys[idx]); + } else { + bzero(bso->keys[idx], BCM_WEP_KEY_SIZE_MAX); + } + } + + if ((setEncryp->activeKeyIdx > 0) && (setEncryp->activeKeyIdx < 5)) { + /* move the index range from (1 to 4) to (0 to 3) */ + bso->primary_key = setEncryp->activeKeyIdx - 1; + } + + bso->wsec = (!setEncryp->encpType) ? 0 : 1; + + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + +exit: + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_ENCRYPTION_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return retVal; +} + +/* + * wfaStaSetEapTLS(): + * This is to set + * 1. ssid + * 2. encrypType - tkip or aes-ccmp + * 3. keyManagementType - wpa or wpa2 + * 4. trustedRootCA + * 5. clientCertificate + */ +int wfaStaSetEapTLS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + caStaSetEapTLS_t *setTLS = (caStaSetEapTLS_t *)caCmdBuf; + char cmdStr[WFA_CMD_STR_SZ]; + char *ifname = setTLS->intf; + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetEapTLS ...\n"); + + /* + * need to store the trustedROOTCA and clientCertificate into a file first. + */ + sprintf(cmdStr, "wpa_cli -i %s disable_network 0", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + /* ssid */ + sprintf(cmdStr, "wpa_cli -i %s set_network 0 ssid '\"%s\"'", ifname, setTLS->ssid); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + /* key management */ + sprintf(cmdStr, "wpa_cli -i %s set_network 0 key_mgmt WPA-EAP", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + /* protocol WPA */ + sprintf(cmdStr, "wpa_cli -i %s set_network 0 proto WPA", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 eap TLS", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 ca_cert '\"%s\"'", ifname, setTLS->trustedRootCA); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 identity '\"wifi-user@wifilabs.local\"'", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 private_key '\"%s/%s\"'", ifname, CERTIFICATES_PATH, setTLS->clientCertificate); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 private_key_passwd '\"wifi\"'", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s enable_network 0", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_EAPTLS_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* + * The function is to set + * 1. ssid + * 2. passPhrase + * 3. keyMangementType - wpa/wpa2 + * 4. encrypType - tkip or aes-ccmp + */ +int wfaStaSetPSK(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + int retVal = TRUE; + caStaSetPSK_t *setPSK = (caStaSetPSK_t *)caCmdBuf; + bcmSsidObj_t *bso; + char *ssidStr; + + DPRINT_INFO(WFA_OUT, "wfaStaSetPSK()"); + + ssidStr = setPSK->ssid; + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + if (!strcmp(setPSK->keyMgmtType, "wpa")) { + bso->wpa_auth = BCM_WPA_AUTH_PSK; /* WPA-PSK/WPA-Personal */ + } else if (!strcmp(setPSK->keyMgmtType, "wpa2")) { + bso->wpa_auth = BCM_WPA2_AUTH_PSK; /* WPA2-PSK/WPA2-Personal */ + } else { + DPRINT_ERR(WFA_OUT, "invalid key_mgmt %s", setPSK->keyMgmtType); + retVal = FALSE; + goto exit; + } + + DPRINT_INFO(WFA_OUT, "wpa_auth %d\n", bso->wpa_auth); + + if (setPSK->encpType == ENCRYPT_TKIP) { + bso->wsec = 3; + } else if (setPSK->encpType == ENCRYPT_AESCCMP) { + bso->wsec = 7; + } else { + DPRINT_ERR(WFA_OUT, "invalid encpType %d", setPSK->encpType); + goto exit; + } + DPRINT_INFO(WFA_OUT, "encpType %d wsec %d\n", setPSK->encpType, bso->wsec); + + strcpy((char *)bso->passphrase, (char *)setPSK->passphrase); + bso->auth = 0; + + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + retVal = TRUE; + +exit: + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_PSK_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return retVal; +} + +/* + * wfaStaGetInfo(): + * Get vendor specific information in name/value pair by a wireless I/F. + */ +int wfaStaGetInfo(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t infoResp; + dutCommand_t *getInfo = (dutCommand_t *)caCmdBuf; + + /* + * Normally this is called to retrieve the vendor information + * from a interface, no implement yet + */ + sprintf(infoResp.cmdru.info, "interface,%s,vendor,XXX,cardtype,802.11a/b/g", getInfo->intf); + + infoResp.status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_GET_INFO_RESP_TLV, sizeof(infoResp), (BYTE *)&infoResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(infoResp); + + DPRINT_INFO(WFA_OUT, "%s\n", infoResp.cmdru.info); + + return TRUE; +} + +/* + * wfaStaSetEapTTLS(): + * This is to set + * 1. ssid + * 2. username + * 3. passwd + * 4. encrypType - tkip or aes-ccmp + * 5. keyManagementType - wpa or wpa2 + * 6. trustedRootCA + */ +int wfaStaSetEapTTLS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + char cmdStr[WFA_CMD_STR_SZ]; + caStaSetEapTTLS_t *setTTLS = (caStaSetEapTTLS_t *)caCmdBuf; + char *ifname = setTTLS->intf; + + sprintf(cmdStr, "wpa_cli -i %s disable_network 0", ifname); + system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 ssid '\"%s\"'", ifname, setTTLS->ssid); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 identity '\"%s\"'", ifname, setTTLS->username); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 password '\"%s\"'", ifname, setTTLS->passwd); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 key_mgmt WPA-EAP", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + +/* This may not need to set. if it is not set, default to take all */ +// sprintf(cmdStr, "wpa_cli -i %s set_network 0 pairwise '\"%s\"", ifname, setTTLS->encrptype); +// system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 eap TTLS", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 ca_cert '\"%s/%s\"'", ifname, CERTIFICATES_PATH, setTTLS->trustedRootCA); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 proto WPA", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 anonymous_identity '\"anonymous\"'", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 phase2 '\"auth=MSCHAPV2\"'", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s enable_network 0", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_EAPTTLS_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* + * wfaStaSetEapSIM(): + * This is to set + * 1. ssid + * 2. user name + * 3. passwd + * 4. encrypType - tkip or aes-ccmp + * 5. keyMangementType - wpa or wpa2 + */ +int wfaStaSetEapSIM(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + char cmdStr[WFA_CMD_STR_SZ]; + caStaSetEapSIM_t *setSIM = (caStaSetEapSIM_t *)caCmdBuf; + char *ifname = setSIM->intf; + + sprintf(cmdStr, "wpa_cli -i %s disable_network 0", ifname); + system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 ssid '\"%s\"'", ifname, setSIM->ssid); + system(cmdStr); + + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 identity '\"%s\"'", ifname, setSIM->username); + system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 key_mgmt WPA-EAP", ifname); + system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 pairwise '\"%s\"'", ifname, setSIM->encrptype); + system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 eap SIM", ifname); + system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 proto WPA", ifname); + system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s enable_network 0", ifname); + system(cmdStr); + + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_EAPSIM_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return ret; +} + +/* + * wfaStaSetPEAP() + * This is to set + * 1. ssid + * 2. user name + * 3. passwd + * 4. encryType - tkip or aes-ccmp + * 5. keyMgmtType - wpa or wpa2 + * 6. trustedRootCA + * 7. innerEAP + * 8. peapVersion + */ +int wfaStaSetPEAP(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + char cmdStr[WFA_CMD_STR_SZ]; + caStaSetEapPEAP_t *setPEAP = (caStaSetEapPEAP_t *)caCmdBuf; + char *ifname = setPEAP->intf; + + sprintf(cmdStr, "wpa_cli -i %s disable_network 0", ifname); + system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 ssid '\"%s\"'", ifname, setPEAP->ssid); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 eap PEAP", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 anonymous_identity '\"anonymous\"' ", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 identity '\"%s\"'", ifname, setPEAP->username); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 password '\"%s\"'", ifname, setPEAP->passwd); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 ca_cert '\"%s/%s\"'", ifname, CERTIFICATES_PATH, setPEAP->trustedRootCA); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + /* if this not set, default to set support all */ + //sprintf(cmdStr, "wpa_cli -i %s set_network 0 pairwise '\"%s\"'", ifname, setPEAP->encrptype); + //system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 key_mgmt WPA-EAP", ifname); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 phase1 '\"peaplabel=%i\"'", ifname, setPEAP->peapVersion); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s set_network 0 phase2 '\"auth=%s\"'", ifname, setPEAP->innerEAP); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + +// sprintf(cmdStr, "wpa_cli -i %s set_network 0 proto WPA", ifname); +// system(cmdStr); + + sprintf(cmdStr, "wpa_cli -i %s enable_network 0", ifname); + system(cmdStr); + + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_PEAP_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* + * wfaStaSetUAPSD() + * This is to set + * 1. maxSPLength - 0,1,2,or 4 + * 2. acBE + * 3. acBK + * 4. acVI + * 5. acVO + */ +int wfaStaSetUAPSD(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = 0; + int retVal = TRUE; + caStaSetUAPSD_t *uapsd = (caStaSetUAPSD_t *)caCmdBuf; + bcmSsidObj_t *bso; + char *ssidStr; + + DPRINT_INFO(WFA_OUT, "maxSPLength %d acBE %d acBK %d acVI %d acVO %d\n", + uapsd->maxSPLength, uapsd->acBE, uapsd->acBK, uapsd->acVI, uapsd->acVO); + + ssidStr = uapsd->ssid; + + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + bso->maxSPLength = uapsd->maxSPLength; + bso->acBE = uapsd->acBE; + bso->acBK = uapsd->acBK; + bso->acVI = uapsd->acVI; + bso->acVO = uapsd->acVO; + +exit: + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_UAPSD_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return retVal; +} + +/* + * wfaStaSetIBSS() + * This is to set + * 1. ssid + * 2. channel + * 3. encrypType - none or wep + * optional + * 4. key1 + * 5. key2 + * 6. key3 + * 7. key4 + * 8. activeIndex - 1, 2, 3, or 4 + */ + +/* Not sure what the intention is, but I am using this routine + * as storing info only, no action. Action is taken when we actually associate */ +int wfaStaSetIBSS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret; + int retVal = TRUE; + caStaSetIBSS_t *setIBSS = (caStaSetIBSS_t *)caCmdBuf; + bcmSsidObj_t *bso; + int idx; + char *ssidStr; + + DPRINT_INFO(WFA_OUT, "wfaStaSetIBSS()\n"); + + /* Save the settings for when we need them */ + + ssidStr = setIBSS->ssid; + + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + bso->bssType = BCM_BSS_INDEPENDENT; + + if (setIBSS->channel) { + bso->channel = setIBSS->channel; + } + + bso->wsec = (!setIBSS->encpType) ? 0 : 1; + + for(idx = 0; idx < 4; idx++) { + if(setIBSS->keys[idx][0] != '\0') { + strcpy(bso->keys[idx], setIBSS->keys[idx]); + } else { + bzero(bso->keys[idx], BCM_WEP_KEY_SIZE_MAX); + } + } + + if ((setIBSS->activeKeyIdx > 0) && (setIBSS->activeKeyIdx < 5)) { + /* move the index range from (1 to 4) to (0 to 3) */ + bso->primary_key = setIBSS->activeKeyIdx - 1; + } + + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + +exit: + ret = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_IBSS_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return retVal; +} + +int wfaDeviceGetInfo(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caDeviceGetInfoResp_t dinfo; + char cmdStr[WFA_CMD_STR_SZ]; + FILE *fd; + + if ((fd = popen("/tmp/ASD/wl ver | awk '{print $7}'", "r")) == NULL){ + printf("Couldn't open either /tmp/ASD/wl or awk\n"); + dinfo.status = STATUS_ERROR; + } else { + memset(&dinfo, 0, sizeof(dinfo)); + + fgets(cmdStr, sizeof(cmdStr), fd); /* Ignore first line */ + fgets(cmdStr, sizeof(cmdStr), fd); + cmdStr[strlen(cmdStr) - 1] = 0; /* Get rid of NL */ + pclose(fd); + + dinfo.status = STATUS_COMPLETE; + sprintf(dinfo.vendor, "%.16s", "Broadcom"); + + sprintf(dinfo.version, "%.16s", cmdStr); + sprintf(dinfo.model, "%.8s", "BRCM"); + + DPRINT_INFO(WFA_OUT, "Entering wfaDeviceGetInfo ...\n"); + + DPRINT_INFO(WFA_OUT, "status %i vendor %s model %s version %s\n", dinfo.status, dinfo.vendor, dinfo.model, dinfo.version); + + wfaEncodeTLV(WFA_DEVICE_GET_INFO_RESP_TLV, sizeof(dinfo), (BYTE *)&dinfo, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dinfo); + + } + return TRUE; + +} + +/* + * This funciton is to retrieve a list of interfaces and return + * the list back to Agent control. + * + */ +int wfaDeviceListIF(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret; + dutCommand_t *ifList = (dutCommand_t *)caCmdBuf; + caDeviceListIFResp_t ifListResp; + + switch(ifList->cmdsu.iftype) + { + case IF_80211: + ifListResp.status = STATUS_COMPLETE; + ifListResp.iftype = IF_80211; + strcpy(ifListResp.ifs[0], "eth1"); + strcpy(ifListResp.ifs[1], "NULL"); + strcpy(ifListResp.ifs[2], "NULL"); + break; + case IF_ETH: + ifListResp.status = STATUS_COMPLETE; + ifListResp.iftype = IF_ETH; + strcpy(ifListResp.ifs[0], "eth0"); + strcpy(ifListResp.ifs[1], "NULL"); + strcpy(ifListResp.ifs[2], "NULL"); + break; + default: + { + ret = STATUS_ERROR; + wfaEncodeTLV(WFA_DEVICE_LIST_IF_RESP_TLV, 4, (BYTE *)&ret, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + } + + wfaEncodeTLV(WFA_DEVICE_LIST_IF_RESP_TLV, sizeof(ifListResp), (BYTE *)&ifListResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(ifListResp); + + return TRUE; +} + +int wfaStaDebugSet(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t debugResp; + dutCommand_t *debugSet = (dutCommand_t *)caCmdBuf; + + DPRINT_INFO(WFA_OUT, "Entering wfaStaDebugSet ...\n"); + + if(debugSet->cmdsu.dbg.state == 1) /* enable */ + wfa_defined_debug |= debugSet->cmdsu.dbg.level; + else + wfa_defined_debug = (~debugSet->cmdsu.dbg.level & wfa_defined_debug); + + debugResp.status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_GET_INFO_RESP_TLV, sizeof(debugResp), (BYTE *)&debugResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(debugResp); + + DPRINT_INFO(WFA_OUT, "%s\n", debugResp.cmdru.info); + + return TRUE; +} + +int bcmSsidIsGood(char *ssidStr) +{ + int ssidLen = strlen(ssidStr); + + if ((ssidLen == 0) || (ssidLen > BCM_SSID_LEN_MAX)) { + return (FALSE); + } else { + return (TRUE); + } +} + +bcmSsidObj_t *bcmWfaSsidTblFreeEntry() +{ + bcmSsidObj_t *bso; + int idx; + + DPRINT_INFO(WFA_OUT, "bcmWfaSsidTblFreeEntry\n"); + + for (idx = 0; idx < BCM_SSID_MAX; idx++) { + bso = &bsotbl.ssidObj[idx]; + if (bcmSsidIsGood(bso->ssidStr) == FALSE) { + return bso; + } + } + + DPRINT_ERR(WFA_OUT, "bcmWfaSsidTblFreeEntry: no free entry available.\n"); + return (NULL); +} + +bcmSsidObj_t *bcmWfaSsidTblSsidFind(char *ssidStr) +{ + bcmSsidObj_t *bso; + bcmSsidObj_t *bsoFound= NULL; + int idx; + + if (bcmSsidIsGood(ssidStr) == FALSE) { + return (NULL); + } + + for (idx = 0; idx < BCM_SSID_MAX; idx++) { + bso = &bsotbl.ssidObj[idx]; + if (bcmSsidIsGood(ssidStr) == FALSE) { + continue; + } + + if (strcmp(ssidStr, bso->ssidStr)) { + continue; + } else { + bsoFound = bso; + break; + } + } + + return (bsoFound); +} + +bcmSsidObj_t *bcmWfaSsidObjTblAdd(char *ssidStr) +{ + bcmSsidObj_t *bso; + + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd: ssidStr %s\n", ssidStr); + + if (bcmSsidIsGood(ssidStr) == FALSE) { + return (NULL); + } + + if ((bso = bcmWfaSsidTblSsidFind(ssidStr))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s): ssid already exists\n", ssidStr); + return (bso); + } + + if (!(bso = bcmWfaSsidTblFreeEntry())) { + DPRINT_INFO(WFA_OUT, "no free entry\n"); + return (NULL); + } + + strcpy(bso->ssidStr, ssidStr); + bso->bssType = BCM_BSS_INFRA; /* init it to infrastructure bss */ + bso->primary_key = BCM_PRI_KEY_BAD; /* init it to bad one */ + + bsotbl.addCnt++; + bsotbl.entries++; + + return (bso); +} + +void bcmWfaSsidObjTblDel(char *ssidStr) +{ + bcmSsidObj_t *bso; + + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblDel: ssidStr %s\n", ssidStr); + + bso = bcmWfaSsidTblSsidFind(ssidStr); + if (bso == NULL) { + return; + } + + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblDel: deleting bso %p\n", bso); + + bzero(bso, sizeof(bcmSsidObj_t)); + bsotbl.delCnt++; + bsotbl.entries--; +} + +void bcmWfaSsidObjPrint(bcmSsidObj_t *bso) +{ + int idx; + + if (bcmSsidIsGood(bso->ssidStr) == FALSE) { + fprintf(WFA_OUT, "bso %p is blank.\n", bso); + return; + } + + fprintf(WFA_OUT, "bso %p\n", bso); + fprintf(WFA_OUT, "\tssid %s", bso->ssidStr); + fprintf(WFA_OUT, "\tbssType %d\n", bso->bssType); + fprintf(WFA_OUT, "\tchannel %d\n", bso->channel); + fprintf(WFA_OUT, "\twsec %d\n", bso->wsec); + fprintf(WFA_OUT, "\tauth %d\n", bso->auth); + fprintf(WFA_OUT, "\twpa_auth %d\n", bso->wpa_auth); + fprintf(WFA_OUT, "\tpowerSave %d\n", bso->powerSave); + fprintf(WFA_OUT, "\tuapsd %d\n", bso->uapsd); + + for (idx = 0; idx < 4; idx++) { + fprintf(WFA_OUT, "\tkeys[%d] : %s\n", idx, bso->keys[idx]); + } + fprintf(WFA_OUT, "\tprimary_key %d\n", bso->primary_key); + fprintf(WFA_OUT, "\tpassphrase : %s\n", bso->passphrase); +} + +void bcmWfaSsidObjTblPrint(void) +{ + int idx; + + fprintf(WFA_OUT, "entries %d addCnt %d delCnt %d\n", + bsotbl.entries, bsotbl.addCnt, bsotbl.delCnt); + for (idx = 0; idx < BCM_SSID_MAX; idx++) { + bcmWfaSsidObjPrint(&bsotbl.ssidObj[idx]); + } +} + +void bcmWfaInit(void) +{ + char cmdStr[WFA_CMD_STR_SZ]; +#ifdef BCMWFA_TEST + int idx; + char ssidStr[64]; + bcmSsidObj_t *bso; +#endif /* def BCMWFA_TEST */ + + bzero(&bsotbl, sizeof(bsotbl)); + sprintf(cmdStr, "/tmp/ASD/wl down"); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl ap 0"); /* not AP */ + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl radio on"); /* not AP */ + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl wsec 0"); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl auth 0"); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl wpa_auth 0"); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl sup_wpa 1"); /* enable in-driver supplicant */ + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + + sprintf(cmdStr, "/tmp/ASD/wl up"); + system(cmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", cmdStr); + +#ifdef BCMWFA_TEST + bcmWfaSsidObjTblPrint(); + + fprintf(WFA_OUT, "add SSIDs\n"); + for (idx = 0; idx < 2 * WFA_SSID_NAME_LEN; idx++) { + sprintf(ssidStr, "ssid_%d", idx); + fprintf(WFA_OUT, "adding %s\n", ssidStr); + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + fprintf(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidStr); + } + } + bcmWfaSsidObjTblPrint(); + + fprintf(WFA_OUT, "add SSIDs again\n"); + for (idx = 0; idx < 2 * WFA_SSID_NAME_LEN; idx++) { + sprintf(ssidStr, "ssid_%d", idx); + fprintf(WFA_OUT, "ssid %s\n", ssidStr); + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + fprintf(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidStr); + } + } + bcmWfaSsidObjTblPrint(); + + fprintf(WFA_OUT, "delete SSIDs\n"); + for (idx = 2 * WFA_SSID_NAME_LEN; idx >= 0; idx--) { + sprintf(ssidStr, "ssid_%d", idx); + bcmWfaSsidObjTblDel(ssidStr); + } + bcmWfaSsidObjTblPrint(); + + fprintf(WFA_OUT, "delete SSIDs again\n"); + for (idx = 2 * WFA_SSID_NAME_LEN; idx >= 0; idx--) { + sprintf(ssidStr, "ssid_%d", idx); + bcmWfaSsidObjTblDel(ssidStr); + } + bcmWfaSsidObjTblPrint(); +#endif /* def BCMWFA_TEST */ +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_ca_resp.c b/src/tools/Wifi_ASD_test/lib/wfa_ca_resp.c new file mode 100644 index 0000000..cbaa987 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_ca_resp.c
@@ -0,0 +1,1506 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ +/* + * File: wfa_ca_resp.c + * All functions are desginated to handle the command responses from + * a DUT and inform TM the command status. + * They will be called by Control Agent. + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA release by qhu + * 2006/06/13 -- 00.02 release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/07/01 -- 01.05 Release by qhu + * 2006/10/26 -- 01.06 release by qhu + * 2007/01/11 -- 01.10 Released by qhu + * 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi + * 2007/03/30 -- 02.40 WPA2 and Official WMM Beta release by qhu + * 2007/04/20 -- 02.40 WPA2 and Official WMM release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * + */ + + /* NOTE: The response for the commands are not sent using + * wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)) in case of RWL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef WIN32 +#include <sys/socket.h> +#endif +#include "wfa_debug.h" +#include "wfa_sock.h" +#include "wfa_types.h" +#include "wfa_tg.h" +#include "wfa_main.h" +#include "wfa_tlv.h" +#include "wfa_miscs.h" +#include "wfa_ca.h" +#include "wfa_rsp.h" +#include "wfa_ca_resp.h" + + +extern unsigned short wfa_defined_debug; + + +char gRespStr[WFA_BUFF_512]; + +dutCommandRespFuncPtr wfaCmdRespProcFuncTbl[WFA_STA_RESPONSE_END - WFA_STA_COMMANDS_END] = +{ + caCmdNotDefinedYet, + wfaGetVersionResp, /* WFA_GET_VERSION_RESP_TLV - WFA_STA_COMMANDS_END (1) */ + wfaTrafficAgentPingStartResp, /* WFA_TRAFFIC_SEND_PING_RESP_TLV - WFA_STA_COMMANDS_END (2) */ + wfaTrafficAgentPingStopResp, /* WFA_TRAFFIC_STOP_PING_RESP_TLV - WFA_STA_COMMANDS_END (3) */ + wfaTrafficAgentConfigResp, /* WFA_TRAFFIC_AGENT_CONFIG_RESP_TLV - WFA_STA_COMMANDS_END (4) */ + wfaTrafficAgentSendResp, /* WFA_TRAFFIC_AGENT_SEND_RESP_TLV - WFA_STA_COMMANDS_END (5) */ + wfaTrafficAgentRecvStartResp, /* WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV - WFA_STA_COMMANDS_END (6) */ + wfaTrafficAgentRecvStopResp, /* WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV - WFA_STA_COMMANDS_END (7) */ + wfaTrafficAgentResetResp, /* WFA_TRAFFIC_AGENT_RESET_RESP_TLV - WFA_STA_COMMANDS_END (8) */ + caCmdNotDefinedYet, /* WFA_TRAFFIC_AGENT_STATUS_RESP_TLV - WFA_STA_COMMANDS_END (9) */ + + wfaStaGetIpConfigResp, /* WFA_STA_GET_IP_CONFIG_RESP_TLV - WFA_STA_COMMANDS_END (10) */ + wfaStaSetIpConfigResp, /* WFA_STA_SET_IP_CONFIG_RESP_TLV - WFA_STA_COMMANDS_END (11) */ + wfaStaGetMacAddressResp, /* WFA_STA_GET_MAC_ADDRESS_RESP_TLV - WFA_STA_COMMANDS_END (12) */ + caCmdNotDefinedYet, /* WFA_STA_SET_MAC_ADDRESS_RESP_TLV - WFA_STA_COMMANDS_END (13) */ + wfaStaIsConnectedResp, /* WFA_STA_IS_CONNECTED_RESP_TLV - WFA_STA_COMMANDS_END (14) */ + wfaStaVerifyIpConnectResp, /* WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV - WFA_STA_COMMANDS_END (15) */ + wfaStaGetBSSIDResp, /* WFA_STA_GET_BSSID_RESP_TLV - WFA_STA_COMMANDS_END (16) */ + wfaStaGetStatsResp, /* WFA_STA_GET_STATS_RESP_TLV - WFA_STA_COMMANDS_END (17) */ + wfaStaSetEncryptionResp, /* WFA_STA_SET_ENCRYPTION_RESP_TLV - WFA_STA_COMMANDS_END (18) */ + wfaStaSetPSKResp, /* WFA_STA_SET_PSK_RESP_TLV - WFA_STA_COMMANDS_END (19) */ + wfaStaSetEapTLSResp, /* WFA_STA_SET_EAPTLS_RESP_TLV - WFA_STA_COMMANDS_END (20) */ + + /* Start: Modified as per BRCM 1.3 ASD */ + wfaStaSetUAPSDResp, /* WFA_STA_SET_UAPSD_RESP_TLV - WFA_STA_COMMANDS_END (21) */ + /* End: Modified as per BRCM 1.3 ASD */ + + + wfaStaAssociateResp, /* WFA_STA_ASSOCIATE_RESP_TLV - WFA_STA_COMMANDS_END (22) */ + wfaStaSetEapTLSResp, /* WFA_STA_SET_EAPTTLS_RESP_TLV - WFA_STA_COMMANDS_END (23) */ + wfaStaSetEapSIMResp, /* WFA_STA_SET_EAPSIM_RESP_TLV - WFA_STA_COMMANDS_END (24) */ + wfaStaSetEapPEAPResp, /* WFA_STA_SET_PEAP_RESP_TLV - WFA_STA_COMMANDS_END (25) */ + wfaStaSetIBSSResp, /* WFA_STA_SET_IBSS_RESP_TLV - WFA_STA_COMMANDS_END (26) */ + wfaStaGetInfoResp, /* WFA_STA_GET_INFO_RESP_TLV - WFA_STA_COMMANDS_END (27) */ + wfaDeviceGetInfoResp, /* WFA_DEVICE_GET_INFO_RESP_TLV - WFA_STA_COMMANDS_END (28) */ + wfaDeviceListIFResp, /* WFA_DEVICE_LIST_IF_RESP_TLV - WFA_STA_COMMANDS_END (29) */ + wfaStaDebugSetResp, /* WFA_STA_DEBUG_SET_RESP_TLV - WFA_STA_COMMANDS_END (30) */ + wfaStaSetModeResp, /* WFA_STA_SET_MODE_RESP_TLV - WFA_STA_COMMANDS_END (31) */ + wfaStaSetWMMResp, /* WFA_STA_SET_WMM_RESP_TLV - WFA_STA_COMMANDS_END (32) */ + wfaStaSendNeigreqResp, /* WFA_STA_SEND_NEIGREQ_RESP_TLV - WFA_STA_COMMANDS_END (33) */ + wfaStaSetSystimeResp, /* WFA_STA_SET_SYSTIME_TLV - WFA_STA_COMMANDS_END (34) */ + wfaStaSet11nResp, /* WFA_STA_SET_11N_TLV - WFA_STA_COMMANDS_END (35) */ + wfaStaSetRifsTestResp, /* WFA_STA_SET_RIFS_TEST_TLV - WFA_STA_COMMANDS_END (36) */ + wfaStaSetWirelessResp, /* WFA_STA_SET_WIRELESS_TLV - WFA_STA_COMMANDS_END (37) */ + wfaStaSendAddbaResp, /* WFA_STA_SEND_ADDBA_TLV - WFA_STA_COMMANDS_END (38) */ + wfaStaSendCoexistMgmtResp, /* WFA_STA_SEND_COEXIST_MGMT_TLV - WFA_STA_COMMANDS_END (39) */ + wfaStaDisconnectResp, /* WFA_STA_SEND_DISCONNECT_TLV - WFA_STA_COMMANDS_END (40) */ + wfaStaSetEapFASTResp, /* WFA_STA_SET_EAP_FAST_TLV - WFA_STA_COMMANDS_END (41) */ + wfaStaSetEapAKAResp, /* WFA_STA_SET_EAP_AKA_TLV - WFA_STA_COMMANDS_END (42) */ + wfaStaReassociateResp, /* WFA_STA_REASSOCIATE_RESP_TLV - WFA_STA_COMMANDS_END (41) */ + wfaStaSetPwrsaveResp, /* WFA_STA_SET_PWRSAVE_RESP_TLV - WFA_STA_CMMANDS_END (42) */ + wfaStaResetDefaultResp /* WFA_STA_RESET_DEFAULT_RESP_TLV - WFA_STA_COMMANDS_END (43) */ +}; + +extern int gSock, gCaSockfd, gxcSockfd; + + +int caCmdNotDefinedYet(BYTE *cmdBuf) +{ + int done; + + sprintf(gRespStr, "status,ERROR,Command Not Defined\r\n"); + /* make sure if getting send error, will close the socket */ + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + done = 0; + return done; +} + +int wfaStaVerifyIpConnectResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *verifyResp = (dutCmdResponse_t *)(cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaVerifyIpConnectResp\n"); + switch(verifyResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,connected,%i\r\n", verifyResp->cmdru.connected); + DPRINT_INFO(WFA_OUT, "%s", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + DPRINT_INFO(WFA_OUT, "%s", gRespStr); + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + printf("%s\n",gRespStr); + return done; +} + + +int wfaStaSetIpConfigResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setIpConfigResp = (dutCmdResponse_t *)(cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetIpConfigResp ...\n"); + + switch(setIpConfigResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, "status,COMPLETE\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + return done; +} + +int wfaStaIsConnectedResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *connectedResp = (dutCmdResponse_t *)(cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaIsConnectedResp ...\n"); + switch(connectedResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,connected,%i\r\n", connectedResp->cmdru.connected); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + break; + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + return done; +} + +int wfaStaGetIpConfigResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *getIpConfigResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetIpConfigResp ...\n"); + switch(getIpConfigResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + break; + + case STATUS_COMPLETE: + if(strlen(getIpConfigResp->cmdru.getIfconfig.dns[0]) == 0) + *getIpConfigResp->cmdru.getIfconfig.dns[0] = '\0'; + if(strlen(getIpConfigResp->cmdru.getIfconfig.dns[1]) == 0) + *getIpConfigResp->cmdru.getIfconfig.dns[1] = '\0'; + + sprintf(gRespStr, "status,COMPLETE,dhcp,%i,ip,%s,mask,%s,primary-dns,%s,secondary-dns,%s\r\n", getIpConfigResp->cmdru.getIfconfig.isDhcp, + getIpConfigResp->cmdru.getIfconfig.ipaddr, + getIpConfigResp->cmdru.getIfconfig.mask, + getIpConfigResp->cmdru.getIfconfig.dns[0], + getIpConfigResp->cmdru.getIfconfig.dns[1]); + break; + + default: + sprintf(gRespStr, "status,INVALID,dhcp,NOTDEF,ip,NOTDEF,mask,NOTDEF,primary-dns,NOTDEF,secondary-dns,NOTDEF\r\n"); + } + printf("%s\n",gRespStr); + return done; +} + +int wfaGetVersionResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *getverResp =(dutCmdResponse_t *)(cmdBuf + 4); + + switch(getverResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,version,%s\r\n", getverResp->cmdru.version); + break; + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + return done ; +} + +int wfaStaGetInfoResp(BYTE *cmdBuf) +{ + dutCmdResponse_t *infoResp = (dutCmdResponse_t *)(cmdBuf + 4); + int done = 0; + + switch(infoResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "sta Get info running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,%s\r\n", infoResp->cmdru.info); + DPRINT_INFO(WFA_OUT, "info: %s\n", infoResp->cmdru.info); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + printf("%s\n",gRespStr); + return done; +} + +int wfaStaGetTestDataResp(BYTE *cmdBuf) +{ + dutCmdResponse_t *dataResp = (dutCmdResponse_t *)(cmdBuf + 4); + int done = 0; + + switch(dataResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "get test data running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + printf("%s\n",gRespStr); + return done; +} + +int wfaTrafficAgentConfigResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *agtConfigResp = (dutCmdResponse_t *)(cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaTrafficAgentConfigResp ...\n"); + switch(agtConfigResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,streamID,%i\r\n", agtConfigResp->streamId); + break; + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + return done; +} + +int wfaTrafficAgentSendResp(BYTE *cmdBuf) +{ + /* Bug, fixed on 19th Dec 2007 */ + int done=0,i; + char copyBuf[64]; + int errorStatus = 0; + BYTE *dutRsp = cmdBuf+4; + BYTE *startRsp = dutRsp; + wfaTLV *ptlv = (wfaTLV *)cmdBuf; + int len = ptlv->len; + int numStreams = len/sizeof(dutCmdResponse_t); + dutCmdResponse_t statResp[WFA_MAX_TRAFFIC_STREAMS]; + + + DPRINT_INFO(WFA_OUT, "Entering wfaTrafficAgentSendResp ...%d\n", numStreams); + + for(i=0; i<numStreams; i++) + { + dutRsp = startRsp + i * sizeof(dutCmdResponse_t); + memcpy(&statResp[i], dutRsp, sizeof(dutCmdResponse_t)); + } + for(i=0; i<numStreams; i++) + { + if(statResp[i].status!= STATUS_COMPLETE) + { + + errorStatus = 1; + } + } + + if(errorStatus) + { + sprintf(gRespStr, "status,ERROR"); + } + else + { + sprintf(gRespStr, "status,COMPLETE,streamID,"); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, " %i", statResp[i].streamId); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + + strncat(gRespStr, ",txFrames,", 10); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, "%i ", statResp[i].cmdru.stats.txFrames); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + + strncat(gRespStr, ",rxFrames,", 10); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, "%i ", statResp[i].cmdru.stats.rxFrames); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + + strncat(gRespStr, ",txPayloadBytes,", 16); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, "%i ", statResp[i].cmdru.stats.txPayloadBytes); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + + strncat(gRespStr, ",rxPayloadBytes,", 16); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, "%i ", statResp[i].cmdru.stats.rxPayloadBytes); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + strncat(gRespStr, ",outOfSequenceFrames,", 21); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, "%i ", statResp[i].cmdru.stats.outOfSequenceFrames); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + + printf("jitter %lu\n", statResp[i].cmdru.stats.jitter); + strncat(gRespStr, "\r\n", 4); + } + return done; +} + +int wfaTrafficAgentRecvStartResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *recvStartResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaTrafficAgentRecvStartResp ...\n"); + switch(recvStartResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "Send command is running\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + + return done; +} + +int wfaTrafficAgentRecvStopResp(BYTE *cmdBuf) +{ + /* Bug, fixed on 19th Dec, 2007 */ + int done=0; + int i = 0; + int errorStatus = 0; + char copyBuf[64]; + + BYTE *dutRsp = cmdBuf+4; + BYTE *startRsp = dutRsp; + wfaTLV *ptlv = (wfaTLV *)cmdBuf; + int len = ptlv->len; + int numStreams = len/sizeof(dutCmdResponse_t); + dutCmdResponse_t statResp[WFA_MAX_TRAFFIC_STREAMS]; + DPRINT_INFO(WFA_OUT, "Entering wfaTrafficAgentRecvStopResp ...\n"); + + + for(i=0; i<numStreams; i++) + { + dutRsp = startRsp + i * sizeof(dutCmdResponse_t); + memcpy(&statResp[i], dutRsp, sizeof(dutCmdResponse_t)); + } + for(i=0; i<numStreams; i++) + { + if(statResp[i].status != STATUS_COMPLETE) + errorStatus = 1; + } + if(errorStatus) + { + sprintf(gRespStr, "status,ERROR"); + } + else + { + sprintf(gRespStr, "status,COMPLETE,streamID,"); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, " %d", statResp[i].streamId); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + strncat(gRespStr, ",txFrames,", 10); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, " %d", statResp[i].cmdru.stats.txFrames); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + strncat(gRespStr, ",rxFrames,", 10); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, " %d", statResp[i].cmdru.stats.rxFrames); + strcat(gRespStr, copyBuf); + } + strncat(gRespStr, ",txPayloadBytes,", 16); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, " %d", statResp[i].cmdru.stats.txPayloadBytes); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + strncat(gRespStr, ",rxPayloadBytes,", 16); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, " %d", statResp[i].cmdru.stats.rxPayloadBytes); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + strncat(gRespStr, ",outOfSequenceFrames,", 21); + for(i=0; i<numStreams; i++) + { + sprintf(copyBuf, " %d", statResp[i].cmdru.stats.outOfSequenceFrames); + strncat(gRespStr, copyBuf, sizeof(copyBuf) - 1); + } + strncat(gRespStr, "\r\n", 4); + } + return done; +} + +int wfaTrafficAgentResetResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *resetResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaTrafficAgentResetResp ...\n"); + switch(resetResp->status) + { + case STATUS_RUNNING: + done = 1; + break; + + case STATUS_COMPLETE: + printf("Inform to stop\n"); + sprintf(gRespStr, "status,COMPLETE\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + return done; +} + +int wfaTrafficAgentPingStartResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *staPingResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaTrafficAgentPingStartResp ...\n"); + + switch(staPingResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent ping start running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,streamID,%i\r\n", staPingResp->streamId); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + } + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + return done; +} + +int wfaTrafficAgentPingStopResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *stpResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(stpResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent ping stop running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + { + sprintf(gRespStr, "status,COMPLETE,sent,%d,replies,%d\r\n", + stpResp->cmdru.pingStp.sendCnt, + stpResp->cmdru.pingStp.repliedCnt); + DPRINT_INFO(WFA_OUT, "%s\n", gRespStr); + break; + } + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + DPRINT_INFO(WFA_OUT, "%s\n", gRespStr); + return done; +} + +int wfaStaGetMacAddressResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *getmacResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetMacAddressResp ...\n"); + switch(getmacResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,mac,%s\r\n", getmacResp->cmdru.mac); + printf("status,COMPLETE,mac,%s\r\n", getmacResp->cmdru.mac); + break; + + case STATUS_ERROR: + printf("status,ERROR\n"); + sprintf(gRespStr, "status,COMPLETE,mac,00:00:00:00:00:00\r\n"); + break; + + default: + sprintf(gRespStr, "status,COMPLETE,mac,00:00:00:00:00:00\r\n"); + printf("unknown status\n"); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + printf("%s\n", gRespStr); + return done; +} + +int wfaStaGetBSSIDResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *getBssidResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetBSSIDResp ...\n"); + switch(getBssidResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,bssid,%s\r\n", getBssidResp->cmdru.bssid); + printf("status,COMPLETE,bssid,%s\r\n", getBssidResp->cmdru.bssid); + break; + case STATUS_ERROR: + printf("status,ERROR\n"); + sprintf(gRespStr, "status,COMPLETE,mac,00:00:00:00:00:00\r\n"); + break; + default: + sprintf(gRespStr, "status,COMPLETE,mac,00:00:00:00:00:00\r\n"); + printf("unknown status\n"); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + printf("%s\n", gRespStr); + return done; +} + +int wfaStaSetEncryptionResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *getBssidResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetEncryptionResp ...\n"); + switch(getBssidResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + printf("status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + printf("status,ERROR\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + return done; +} + +int wfaStaSetEapTLSResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setEapTLSResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetEapTLSResp ...\n"); + switch(setEapTLSResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + return done; + +} + +int wfaStaSetPSKResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setPSKResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetPSKResp ...\n"); + switch(setPSKResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + return done; +} + + +/* Start: Added as per BRCM 1.3 ASD */ + +int wfaStaSetUAPSDResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setUAPSDResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetUAPSDResp ...\n"); + + switch(setUAPSDResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "STA set UAPSD running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, sizeof(gRespStr)); + return done; +} +/* End: Added as per BRCM 1.3 ASD */ + + + +int wfaStaSetEapTTLSResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setEapTTLSResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetEapTTLSResp ...\n"); + switch(setEapTTLSResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + return done; +} + +int wfaStaSetEapPEAPResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setEapPeapResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetEapPEAPResp ...\n"); + switch(setEapPeapResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + return done; +} + +int wfaStaSetEapSIMResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setEapSIMResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetEapSIMResp ...\n"); + switch(setEapSIMResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + return done; +} + +int wfaStaAssociateResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *assocResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaAssociateResp ...\n"); + switch(assocResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetIBSSResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setIBSSResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetIBSSResp ...\n"); + switch(setIBSSResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + return done; +} + +int wfaStaGetStatsResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *getStatsResp = (dutCmdResponse_t *) (cmdBuf + 4); + caStaGetStatsResp_t *stats = &getStatsResp->cmdru.ifStats; + + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetStatsResp ...\n"); + + switch(getStatsResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE,txFrames,%i,rxFrames,%i,txMulticast,%i,rxMulticast,%i,fcsErrors,%i,txRetries,%i\r\n", + stats->txFrames, stats->rxFrames, stats->txMulticast, stats->rxMulticast, stats->fcsErrors, stats->txRetries); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaDeviceGetInfoResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *devInfoResp = (dutCmdResponse_t *) (cmdBuf + 4); + + + + caDeviceGetInfoResp_t *dinfo = &devInfoResp->cmdru.devInfo; + + switch(devInfoResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + if(dinfo->firmware[0] != '\0' || dinfo->firmware[0] != '\n') + sprintf(gRespStr, "status,COMPLETE,firmware,%s\r\n", dinfo->firmware); + else + sprintf(gRespStr, "status,COMPLETE,vendor,%s,model,%s,version,%s\r\n", + dinfo->vendor, dinfo->model, dinfo->version); + + DPRINT_INFO(WFA_OUT, "%s\n", gRespStr); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaDeviceListIFResp(BYTE *cmdBuf) +{ + int done=0, i; + dutCmdResponse_t *devListIfResp = (dutCmdResponse_t *) (cmdBuf + 4); + caDeviceListIFResp_t *ifResp = &devListIfResp->cmdru.ifList; + + switch(devListIfResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + if(ifResp->iftype == IF_80211) + { + sprintf(gRespStr, "status,COMPLETE,interfaceType,802.11,interfaceID"); + DPRINT_INFO(WFA_OUT, "%s\n", gRespStr); + DPRINT_INFO(WFA_OUT, "%s\n", ifResp->ifs[0]); + } + else if(ifResp->iftype == IF_ETH) + sprintf(gRespStr, "status,COMPLETE,interfaceType,Ethernet,interfaceID"); + + for(i=0; i<1; i++) + { + if(ifResp->ifs[i][0] != '\0') + { + strncat(gRespStr,",", 4); + strncat(gRespStr, ifResp->ifs[i], sizeof(ifResp->ifs[i])); + strncat(gRespStr, "\r\n", 4); + } + } + + DPRINT_INFO(WFA_OUT, "%s\n", gRespStr); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + return done; +} + +int wfaStaDebugSetResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *debugResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaDebugSetResp ...\n"); + switch(debugResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetModeResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *getBssidResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetModeResp ...\n"); + switch(getBssidResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + printf("status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + printf("status,ERROR\r\n"); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetWMMResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *setwmmResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(setwmmResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "wfaStaSetWMM running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + sprintf(gRespStr, "status,COMPLETE\r\n"); + printf("status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + case STATUS_ERROR: + sprintf(gRespStr, "status,ERROR\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + sprintf(gRespStr, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSendNeigreqResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *neigreqResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaDebugSetResp ...\n"); + switch(neigreqResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetSystimeResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *systimeResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(systimeResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSet11nResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *set11nResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(set11nResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetRifsTestResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *testResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(testResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetWirelessResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *wirelessResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(wirelessResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSendAddbaResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *addbaResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(addbaResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSendCoexistMgmtResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *mgmtResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(mgmtResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaDisconnectResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *DisconnectResp = (dutCmdResponse_t *) (cmdBuf + 4); + + switch(DisconnectResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetEapFASTResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *eapfastResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaEapFASTSetResp ...\n"); + switch(eapfastResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetEapAKAResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *eapakaResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaEapAKASetResp ...\n"); + switch(eapakaResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaReassociateResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *reassocResp = (dutCmdResponse_t *) (cmdBuf + 4); + DPRINT_INFO(WFA_OUT, "Entering wfaStaReassociateResp ...\n"); + switch(reassocResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaSetPwrsaveResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *pwrsaveResp = (dutCmdResponse_t *) (cmdBuf + 4); + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetPwrsaveResp ...\n"); + switch(pwrsaveResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} + +int wfaStaResetDefaultResp(BYTE *cmdBuf) +{ + int done=0; + dutCmdResponse_t *resetResp = (dutCmdResponse_t *) (cmdBuf + 4); + DPRINT_INFO(WFA_OUT, "Entering wfaStaResetDefaultResp ...\n"); + switch(resetResp->status) + { + case STATUS_RUNNING: + DPRINT_INFO(WFA_OUT, "traffic agent config running ...\n"); + done = 1; + break; + + case STATUS_COMPLETE: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,COMPLETE\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + break; + + default: + S_N_PRINTF(gRespStr, WFA_BUFF_512, "status,INVALID\r\n"); + DPRINT_INFO(WFA_OUT, " %s\n", gRespStr); + } + wfaCtrlSend(gCaSockfd, (BYTE *)gRespStr, strlen(gRespStr)); + + return done; +} +
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_cmdproc.c b/src/tools/Wifi_ASD_test/lib/wfa_cmdproc.c new file mode 100644 index 0000000..e5315a9 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_cmdproc.c
@@ -0,0 +1,3036 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ +/* + * File: wfa_cmdproc.c + * Library functions to handle all string command parsing and convert it + * to an internal format for DUT. They should be called by Control Agent + * and Test console while receiving commands from CLI or TM + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA release by qhu + * 2006/06/13 -- 00.02 release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/08/30 -- add some print statements by Isaac in Epson. + * 2006/09/01 -- 01.05 release by qhu + * 2006/10/26 -- 01.06 release by qhu + * 2006/12/02 -- bug fix reported by p.schwan + * 2007/01/11 -- 01.10 release by qhu + * 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef WIN32 +#include <sys/socket.h> +#endif +#include "wfa_debug.h" +#include "wfa_types.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_ca.h" +#include "wfa_cmds.h" +#include "wfa_miscs.h" +#include "wfa_agtctrl.h" + +extern int gSock; +extern void printProfile(tgProfile_t *); +extern unsigned short wfa_defined_debug; + +/* command KEY WORD String table */ +typeNameStr_t keywordStr[] = +{ + { KW_PROFILE, "profile", NULL}, + { KW_DIRECTION, "direction", NULL}, + { KW_DIPADDR, "destination", NULL}, + { KW_DPORT, "destinationport", NULL}, + { KW_SIPADDR, "source", NULL}, + { KW_SPORT, "sourceport", NULL}, + { KW_FRATE, "framerate", NULL}, + { KW_DURATION, "duration", NULL}, + { KW_PLOAD, "payloadsize", NULL}, + { KW_TCLASS, "trafficClass", NULL}, /* It is to indicate WMM traffic pattern */ + { KW_STREAMID, "streamid", NULL}, + { KW_STARTDELAY, "startdelay", NULL}, /* It is used to schedule multi-stream test such as WMM */ + { KW_NUMFRAME, "numframes", NULL}, + { KW_USESYNCCLOCK, "useSyncClock", NULL}, + { KW_USERPRIORITY, "userpriority", NULL} +}; + +/* profile type string table */ +typeNameStr_t profileStr[] = +{ + { PROF_FILE_TX, "file_transfer", NULL}, + { PROF_MCAST, "multicast", NULL}, + { PROF_IPTV, "iptv", NULL}, /* This is used for WMM, confused? */ + { PROF_TRANSC, "transaction", NULL}, + { PROF_START_SYNC, "start_sync", NULL}, + { PROF_CALI_RTD, "cali_rtd", NULL}, + { PROF_UAPSD, "uapsd", NULL}, + { PROF_FILE_TX_TCP, "file_transfer_tcp", NULL}, + { PROF_TRANSC_TCP, "transaction_tcp", NULL} +}; + +/* direction string table */ +typeNameStr_t direcStr[] = +{ + { DIRECT_SEND, "send", NULL}, + { DIRECT_RECV, "receive", NULL} +}; + +/* + * cmdProcNotDefinedYet(): a dummy function + */ +int cmdProcNotDefinedYet(char *pcmdStr, char *buf, int len) +{ + DPRINT_INFO(WFA_OUT,"The command processing function not defined.\n"); + + /* need to send back a response */ + + return (TRUE); +} + +extern unsigned short wfa_defined_debug; + +/* + * xcCmdProcGetVersion(): process the command get_version string from TM + * to convert it into a internal format + * input: pcmdStr -- a string pointer to the command string + */ +int xcCmdProcGetVersion(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + DPRINT_INFO(WFA_OUT, "start xcCmdProcGetVersion ...\n"); + + if(aBuf == NULL) + return FALSE; + + /* encode the tag without values */ + wfaEncodeTLV(WFA_GET_VERSION_TLV, 0, NULL, aBuf); + + *aLen = 4; + + return TRUE; +} + +/* + * xcCmdProcAgentConfig(): process the command traffic_agent_config string + * from TM to convert it into a internal format + * input: pcmdStr -- a string pointer to the command string + */ +int xcCmdProcAgentConfig(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + char *str; + int i = 0, j=0, kwcnt = 0; + wfaTLV *hdr = (wfaTLV *)aBuf; + tgProfile_t tgpf; + tgProfile_t *pf = &tgpf; + int userPrio = 0; + + DPRINT_INFO(WFA_OUT, "start xcCmdProcAgentConfig ...\n"); + DPRINT_INFO(WFA_OUT, "params: %s\n", pcmdStr); + + if(aBuf == NULL) + return FALSE; + + while((str = strtok_r(NULL, ",", (char **)&pcmdStr)) != NULL) + { + DPRINT_INFO(WFA_OUT,"key word %s\n", str); + for(i = 0; i<sizeof(keywordStr); i++) + { + if(strcasecmp(str, keywordStr[i].name) == 0) + { + switch(keywordStr[i].type) + { + case KW_PROFILE: + str = strtok_r(NULL, ",", (char **)&pcmdStr); + if(isString(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect profile keyword format\n"); + return FALSE; + } + + for(j = 0; j < PROF_LAST; j++) + if(strcasecmp(str, profileStr[j].name) == 0) + { + pf->profile = profileStr[j].type; + } + + DPRINT_INFO(WFA_OUT, "profile type %i\n", pf->profile); + kwcnt++; + str = NULL; + break; + + case KW_DIRECTION: + str = strtok_r(NULL, ",", &pcmdStr); + if(isString(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect direction keyword format\n"); + return FALSE; + } + + if(strcasecmp(str, "send") == 0) + { + pf->direction = DIRECT_SEND; + } + else if(strcasecmp(str, "receive") == 0) + { + pf->direction = DIRECT_RECV; + } + else + DPRINT_INFO(WFA_OUT,"Don't know direction\n"); + + DPRINT_INFO(WFA_OUT, "direction %i\n", pf->direction); + kwcnt++; + str = NULL; + break; + + case KW_DIPADDR: /* dest ip address */ + memcpy(pf->dipaddr, strtok_r(NULL, ",", &pcmdStr), IPV4_ADDRESS_STRING_LEN); + if(isIpV4Addr(pf->dipaddr) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect ipaddr format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "dipaddr %s\n", pf->dipaddr); + + kwcnt++; + str = NULL; + break; + + case KW_DPORT: + str = strtok_r(NULL, ",", &pcmdStr); + if(isNumber(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect port number format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "dport %s\n", str); + pf->dport = atoi(str); + + kwcnt++; + str = NULL; + break; + + case KW_SIPADDR: + memcpy(pf->sipaddr, strtok_r(NULL, ",", &pcmdStr), IPV4_ADDRESS_STRING_LEN); + + if(isIpV4Addr(pf->sipaddr) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect ipaddr format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "sipaddr %s\n", pf->sipaddr); + kwcnt++; + str = NULL; + break; + + case KW_SPORT: + str = strtok_r(NULL, ",", &pcmdStr); + if(isNumber(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect port number format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "sport %s\n", str); + pf->sport = atoi(str); + + kwcnt++; + str = NULL; + break; + + case KW_FRATE: + str = strtok_r(NULL, ",", &pcmdStr); + if(isNumber(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect frame rate format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "framerate %s\n", str); + pf->rate = atoi(str); + kwcnt++; + str = NULL; + break; + + case KW_DURATION: + str = strtok_r(NULL, ",", &pcmdStr); + if (strlen(str)) { + if(isNumber(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect duration format\n"); + return FALSE; + } + } + else + { + DPRINT_ERR(WFA_ERR, "No duration specified\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "duration %s\n", str); + pf->duration = atoi(str); + kwcnt++; + str = NULL; + break; + + case KW_PLOAD: + str = strtok_r(NULL, ",", &pcmdStr); + if(isNumber(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect payload format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "payload %s\n", str); + pf->pksize = atoi(str); + kwcnt++; + str = NULL; + break; + + case KW_STARTDELAY: + str = strtok_r(NULL, ",", &pcmdStr); + if(isNumber(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect startDelay format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "startDelay %s\n", str); + pf->startdelay = atoi(str); + kwcnt++; + str = NULL; + break; + + case KW_TCLASS: + str = strtok_r(NULL, ",", &pcmdStr); + + /* if user priority is used, tclass is ignored. */ + if(userPrio == 1) + break; + + if(strcasecmp(str, "voice") == 0) + { + pf->trafficClass = TG_WMM_AC_VO; + } + else if(strcasecmp(str, "Video") == 0) + { + pf->trafficClass = TG_WMM_AC_VI; + } + else if(strcasecmp(str, "Background") == 0) + { + pf->trafficClass = TG_WMM_AC_BK; + } + else if(strcasecmp(str, "BestEffort") == 0) + { + pf->trafficClass = TG_WMM_AC_BE; + } + else + { + pf->trafficClass = TG_WMM_AC_BE; + } + + kwcnt++; + str = NULL; + break; + + case KW_USERPRIORITY: + str = strtok_r(NULL, ",", &pcmdStr); + + if( strcasecmp(str, "6") == 0 ) + { + pf->trafficClass = TG_WMM_AC_UP6; + } + else if( strcasecmp(str, "7") == 0 ) + { + pf->trafficClass = TG_WMM_AC_UP7; + } + else if( strcasecmp(str, "5") == 0 ) + { + pf->trafficClass = TG_WMM_AC_UP5; + } + else if( strcasecmp(str, "4") == 0 ) + { + pf->trafficClass = TG_WMM_AC_UP4; + } + else if( strcasecmp(str, "1") == 0 ) + { + pf->trafficClass = TG_WMM_AC_UP1; + } + else if( strcasecmp(str, "2") == 0 ) + { + pf->trafficClass = TG_WMM_AC_UP2; + } + else if( strcasecmp(str, "0") == 0 ) + { + pf->trafficClass = TG_WMM_AC_UP0; + } + else if( strcasecmp(str, "3") == 0) + { + pf->trafficClass = TG_WMM_AC_UP3; + } + + /* if User Priority is used */ + userPrio = 1; + + kwcnt++; + str = NULL; + break; + + case KW_STREAMID: + kwcnt++; + break; + + case KW_NUMFRAME: + DPRINT_INFO(WFA_OUT,"Number of Frame\n"); + str = strtok_r(NULL, ",", &pcmdStr); + if(isNumber(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect numframe format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "num frame %s\n", str); + DPRINT_INFO(WFA_OUT,"num frame %s\n", str); + kwcnt++; + str = NULL; + break; + + case KW_USESYNCCLOCK: + str = strtok_r(NULL, ",", &pcmdStr); + if(isNumber(str) == FALSE) + { + DPRINT_ERR(WFA_ERR, "Incorrect sync clock format\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "sync clock %s\n", str); + DPRINT_INFO(WFA_OUT,"sync clock %s\n", str); + kwcnt++; + str = NULL; + break; + + default: + ; + } /* switch */ + + if(str==NULL) + break; + } + + } /* for */ + } /* while */ + + + printProfile(pf); + hdr->tag = WFA_TRAFFIC_AGENT_CONFIG_TLV; + hdr->len = sizeof(tgProfile_t); + + memcpy(aBuf+4, pf, sizeof(tgpf)); + + *aLen = 4+sizeof(tgProfile_t); + + return TRUE; +} + +/* + * xcCmdProcAgentSend(): Process and send the Control command + * "traffic_agent_send" + * input - pcmdStr parameter string pointer + * return - TRUE or FALSE; + */ +int xcCmdProcAgentSend(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + wfaTLV *hdr = (wfaTLV *)aBuf; + char *str, *sid; + int strid; + int id_cnt = 0; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, 512); + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcAgentSend ...\n"); + /* there is only one stream for baseline. Will support + * multiple streams later. + */ + str = strtok_r(NULL, ",", &pcmdStr); + + if(str == NULL || str[0] == '\0') + return FALSE; + + /* take the stream ids */ + if(strcasecmp(str, "streamid") != 0) + { + DPRINT_ERR(WFA_ERR, "invalid type name\n"); + return FALSE; + } + + /* + * To handle there are multiple stream ids such as WMM + */ + while(1) + { + sid = strtok_r (NULL, " ", &pcmdStr); + if(sid == NULL) + break; + + if(isNumber(sid) == FALSE) + continue; + + strid = atoi(sid); + DPRINT_INFO(WFA_OUT,"id %i\n", strid); + id_cnt++; + + memcpy(aBuf+4*id_cnt, (char *)&strid, 4); + } + + hdr->tag = WFA_TRAFFIC_AGENT_SEND_TLV; + hdr->len = 4*id_cnt; /* multiple 4s if more streams */ + + *aLen = 4 + 4*id_cnt; + +#ifdef DEBUG + { + int i; + for(i = 0; i< *aLen; i++) + DPRINT_INFO(WFA_OUT,"%x ", aBuf[i]); + + DPRINT_INFO(WFA_OUT,"\n"); + } +#endif + + + return TRUE; +} + +/* + * xcCmdProcAgentReset(): Process and send the Control command + * "traffic_agent_reset" + * input - pcmdStr parameter string pointer + * return - TRUE or FALSE; + */ +int xcCmdProcAgentReset(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + wfaTLV *hdr = (wfaTLV *)aBuf; + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcAgentReset ...\n"); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + hdr->tag = WFA_TRAFFIC_AGENT_RESET_TLV; + hdr->len = 0; /* multiple 4s if more streams */ + + *aLen = 4; + + return TRUE; +} + +/* + * xcCmdProcAgentRecvStart(): Process and send the Control command + * "traffic_agent_receive_start" + * input - pcmdStr parameter string pointer + * return - TRUE or FALSE; + */ +int xcCmdProcAgentRecvStart(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + + wfaTLV *hdr = (wfaTLV *)aBuf; + char *str, *sid; + int strid; + int id_cnt = 0; + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcAgentRecvStart ...%s\n", pcmdStr); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + /* there is only one stream for baseline. Will support + * multiple streams later. + */ + str = strtok_r(NULL, ",", &pcmdStr); + + if(str == NULL || str[0] == '\0') + { + DPRINT_ERR(WFA_ERR, "Null string\n"); + return FALSE; + } + + + if(strcasecmp(str, "streamid") != 0) + { + DPRINT_ERR(WFA_ERR, "invalid type name\n"); + return FALSE; + } + + while(1) + { + sid = strtok_r (NULL, " ", &pcmdStr); + if(sid == NULL) + break; + + if(isNumber(sid) == FALSE) + continue; + + strid = atoi(sid); + id_cnt++; + + memcpy(aBuf+4*id_cnt, (char *)&strid, 4); + } + + hdr->tag = WFA_TRAFFIC_AGENT_RECV_START_TLV; + hdr->len = 4*id_cnt; /* multiple 4s if more streams */ + + *aLen = 4 + 4*id_cnt; + +#ifdef DEBUG + { + int i; + for(i = 0; i< *aLen; i++) + DPRINT_INFO(WFA_OUT,"%x ", aBuf[i]); + + DPRINT_INFO(WFA_OUT,"\n"); + } +#endif + return TRUE; +} + +/* + * xcCmdProcAgentRecvStop(): Process and send the Control command + * "traffic_agent_receive_stop" + * input - pcmdStr parameter string pointer + * return - TRUE or FALSE; + */ +int xcCmdProcAgentRecvStop(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + wfaTLV *hdr = (wfaTLV *)aBuf; + char *str, *sid; + int strid; + int id_cnt = 0; + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcAgentRecvStop ...\n"); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + /* there is only one stream for baseline. Will support + * multiple streams later. + */ + str = strtok_r(NULL, ",", &pcmdStr); + + if(str == NULL || str[0] == '\0') + return FALSE; + + if(strcasecmp(str, "streamid") != 0) + { + DPRINT_ERR(WFA_ERR, "invalid type name\n"); + return FALSE; + } + while(1) + { + sid = strtok_r (NULL, " ", &pcmdStr); + if(sid == NULL) + break; + if(isNumber(sid) == FALSE) + continue; + + strid = atoi(sid); + id_cnt++; + + memcpy(aBuf+4*id_cnt, (char *)&strid, 4); + } + + hdr->tag = WFA_TRAFFIC_AGENT_RECV_STOP_TLV; + hdr->len = 4*id_cnt; /* multiple 4s if more streams */ + + *aLen = 4 + 4*id_cnt; + + return TRUE; +} + +int xcCmdProcAgentSendPing(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + wfaTLV *hdr = (wfaTLV *)aBuf; + tgPingStart_t *staping = (tgPingStart_t *) (aBuf+sizeof(wfaTLV)); + char *str; + staping->type = 0; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "destination") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(staping->dipaddr, str, 15); + DPRINT_INFO(WFA_OUT, "destination %s\n", staping->dipaddr); + } + if(strcasecmp(str, "frameSize") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + staping->frameSize=atoi(str); + DPRINT_INFO(WFA_OUT, "framesize %i\n", staping->frameSize); + } + if(strcasecmp(str, "frameRate") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + staping->frameRate=atoi(str); + DPRINT_INFO(WFA_OUT, "framerate %i\n", staping->frameRate); + } + if(strcasecmp(str, "duration") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + staping->duration=atoi(str); + DPRINT_INFO(WFA_OUT, "duration %i\n", staping->duration); + } + if(strcasecmp(str, "type") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str, "udp") == 0) + staping->type = 1; + else + staping->type = 0; + } + } + + hdr->tag = WFA_TRAFFIC_SEND_PING_TLV; + hdr->len = sizeof(tgPingStart_t); + + *aLen = hdr->len + 4; + + return TRUE; +} + +int xcCmdProcAgentStopPing(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + wfaTLV *hdr = (wfaTLV *)aBuf; + char *str; + int strid; + str = strtok_r(NULL, ",", &pcmdStr); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + if(str == NULL || str[0] == '\0') + return FALSE; + + if(strcasecmp(str, "streamid") == 0) + str = strtok_r(NULL, ",", &pcmdStr); + else + { + DPRINT_ERR(WFA_ERR, "invalid type name\n"); + return FALSE; + } + + if(isNumber(str) == FALSE) + return FALSE; + + strid = atoi(str); + + memcpy(aBuf+4, (char *)&strid, 4); + + hdr->tag = WFA_TRAFFIC_STOP_PING_TLV; + hdr->len = 4; /* multiple 4s if more streams */ + + *aLen = 8; + + return TRUE; +} + +int xcCmdProcStaGetIpConfig(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + int slen; + char *str = NULL; + dutCommand_t getipconf; + memset(&getipconf, 0, sizeof(dutCommand_t)); + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcStaGetIpConfig ...\n"); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + str = strtok_r(NULL, ",", &pcmdStr); + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL) + return FALSE; + + + slen = strlen(str); + memcpy(getipconf.intf, str, slen); + wfaEncodeTLV(WFA_STA_GET_IP_CONFIG_TLV, sizeof(dutCommand_t), (BYTE *)&getipconf, aBuf); + + *aLen = 4+sizeof(getipconf); + + return TRUE; +} + +int xcCmdProcStaSetIpConfig(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t staSetIpConfig; + char *str; + caStaSetIpConfig_t *setip; + memset(&staSetIpConfig, 0, sizeof(staSetIpConfig)); + setip = (caStaSetIpConfig_t *)&staSetIpConfig.cmdsu.ipconfig; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setip->intf, str, 15); + DPRINT_INFO(WFA_OUT, "interface %s\n", setip->intf); + } + else if(strcasecmp(str, "dhcp") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setip->isDhcp = atoi(str); + DPRINT_INFO(WFA_OUT, "dhcp %i\n", setip->isDhcp); + } + else if(strcasecmp(str, "ip") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setip->ipaddr, str, 15); + DPRINT_INFO(WFA_OUT, "ip %s\n", setip->ipaddr); + } + else if(strcasecmp(str, "mask") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setip->mask, str, 15); + DPRINT_INFO(WFA_OUT, "mask %s\n", setip->mask); + } + else if(strcasecmp(str, "defaultGateway") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setip->defGateway, str, 15); + DPRINT_INFO(WFA_OUT, "gw %s\n", setip->defGateway); + } + else if(strcasecmp(str, "primary-dns") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setip->pri_dns, str, 15); + DPRINT_INFO(WFA_OUT, "dns p %s\n", setip->pri_dns); + } + else if(strcasecmp(str, "secondary-dns") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setip->sec_dns, str, 15); + DPRINT_INFO(WFA_OUT, "dns s %s\n", setip->sec_dns); + } + else + { + DPRINT_ERR(WFA_ERR, "invalid command\n"); + return FALSE; + } + } + + wfaEncodeTLV(WFA_STA_SET_IP_CONFIG_TLV, sizeof(staSetIpConfig), (BYTE *)&staSetIpConfig, aBuf); + + *aLen = 4+sizeof(staSetIpConfig); + + return TRUE; +} + +int xcCmdProcStaGetMacAddress(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + int slen; + char *str = NULL; + dutCommand_t getmac; + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcStaGetMacAddress ...\n"); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + memset(&getmac, 0, sizeof(getmac)); + str = strtok_r(NULL, ",", &pcmdStr); + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL) + return FALSE; + + slen = strlen(str); + memcpy(getmac.intf, str, slen); + wfaEncodeTLV(WFA_STA_GET_MAC_ADDRESS_TLV, sizeof(getmac), (BYTE *)&getmac, aBuf); + + *aLen = 4+sizeof(getmac); + + return TRUE; +} + + +int xcCmdProcStaIsConnected(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + int slen; + char *str = NULL; + dutCommand_t isconnected; + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcStaIsConnected\n"); + + memset(&isconnected, 0, sizeof(isconnected)); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + str = strtok_r(NULL, ",", &pcmdStr); + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL) + return FALSE; + + slen = strlen(str); + memcpy(isconnected.intf, str, slen); + wfaEncodeTLV(WFA_STA_IS_CONNECTED_TLV, sizeof(isconnected), (BYTE *)&isconnected, aBuf); + + *aLen = 4+sizeof(isconnected); + + return TRUE; +} + +int xcCmdProcStaVerifyIpConnection(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + wfaTLV *hdr = (wfaTLV *)aBuf; + dutCommand_t *verifyip = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcStaVerifyIpConnection ...\n"); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(verifyip->intf, str); + verifyip->intf[15]='\0'; + DPRINT_INFO(WFA_OUT, "interface %s %i\n", verifyip->intf, strlen(verifyip->intf)); + } + else if(strcasecmp(str, "destination") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(verifyip->cmdsu.verifyIp.dipaddr, str, 15); + DPRINT_INFO(WFA_OUT, "ip %s\n", verifyip->cmdsu.verifyIp.dipaddr); + } + else if(strcasecmp(str, "timeout") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + verifyip->cmdsu.verifyIp.timeout = atoi(str); + DPRINT_INFO(WFA_OUT, "timeout %i\n", verifyip->cmdsu.verifyIp.timeout); + } + } + + wfaEncodeTLV(WFA_STA_VERIFY_IP_CONNECTION_TLV, sizeof(verifyip), (BYTE *)&verifyip, aBuf); + + hdr->tag = WFA_STA_VERIFY_IP_CONNECTION_TLV; + hdr->len = sizeof(dutCommand_t); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcStaGetBSSID(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + int slen; + char *str = NULL; + dutCommand_t getbssid; + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcStaGetBSSID ...\n"); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + memset(&getbssid, 0, sizeof(getbssid)); + str = strtok_r(NULL, ",", &pcmdStr); + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL) + return FALSE; + + slen = strlen(str); + memcpy(getbssid.intf, str, slen-1); + getbssid.intf[slen-1] = '\0'; + wfaEncodeTLV(WFA_STA_GET_BSSID_TLV, sizeof(getbssid), (BYTE *)&getbssid, aBuf); + + *aLen = 4+sizeof(getbssid); + + return TRUE; +} + + +int xcCmdProcStaGetStats(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + int slen; + char *str = NULL; + dutCommand_t getstats; + + DPRINT_INFO(WFA_OUT, "Entering xcCmdProcStaGetStats ...\n"); + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + memset(&getstats, 0, sizeof(getstats)); + str = strtok_r(NULL, ",", &pcmdStr); + /* need to check if the parameter name is called interface */ + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL) + return FALSE; + + slen = strlen(str); + memcpy(getstats.intf, str, slen-1); + getstats.intf[slen-1] = '\0'; + wfaEncodeTLV(WFA_STA_GET_STATS_TLV, sizeof(getstats), (BYTE *)&getstats, aBuf); + + *aLen = 4+sizeof(getstats); + + return TRUE; +} + + +int xcCmdProcStaSetEncryption(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetEncryption_t *setencryp = (caStaSetEncryption_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setencryp->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setencryp->ssid, str, 64); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str, "wep") == 0) + setencryp->encpType = ENCRYPT_WEP; + else + setencryp->encpType = 0; + } + else if(strcasecmp(str, "key1") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setencryp->keys[0], str, 26); + DPRINT_INFO(WFA_OUT, "%s\n", setencryp->keys[0]); + setencryp->activeKeyIdx = 0; + } + else if(strcasecmp(str, "key2") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setencryp->keys[1], str, 26); + DPRINT_INFO(WFA_OUT, "%s\n", setencryp->keys[1]); + } + else if(strcasecmp(str, "key3") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setencryp->keys[2], str, 26); + DPRINT_INFO(WFA_OUT, "%s\n", setencryp->keys[2]); + } + else if(strcasecmp(str, "key4") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setencryp->keys[3], str, 26); + DPRINT_INFO(WFA_OUT, "%s\n", setencryp->keys[3]); + } + else if(strcasecmp(str, "activeKey") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setencryp->activeKeyIdx = atoi(str); + } + else + { + DPRINT_INFO(WFA_WNG, "Incorrect Command, check syntax\n"); + } + } + + wfaEncodeTLV(WFA_STA_SET_ENCRYPTION_TLV, sizeof(caStaSetEncryption_t), (BYTE *)setencryp, aBuf); + + *aLen = 4+sizeof(caStaSetEncryption_t); + + return TRUE; +} + +int xcCmdProcStaSetPSK(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetPSK_t *setencryp = (caStaSetPSK_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setencryp->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setencryp->ssid, str, 64); + DPRINT_INFO(WFA_OUT, "ssid %s\n", setencryp->ssid); + } + else if(strcasecmp(str, "passPhrase") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setencryp->passphrase, str, 64); + } + else if(strcasecmp(str, "keyMgmtType") == 0) + { + str=strtok_r(NULL, ",", &pcmdStr); + strncpy(setencryp->keyMgmtType, str, 7); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + + if(strcasecmp(str, "tkip") == 0) + setencryp->encpType = ENCRYPT_TKIP; + else if(strcasecmp(str, "aes-ccmp") == 0) + setencryp->encpType = ENCRYPT_AESCCMP; + } + } + + wfaEncodeTLV(WFA_STA_SET_PSK_TLV, sizeof(caStaSetPSK_t), (BYTE *)setencryp, aBuf); + + *aLen = 4+sizeof(caStaSetPSK_t); + + return TRUE; +} + +int xcCmdProcStaSetEapTLS(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetEapTLS_t *setsec = (caStaSetEapTLS_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->ssid, str, 64); + } + else if(strcasecmp(str, "keyMgmtType") == 0) + { + str=strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->keyMgmtType, str, 7); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->encrptype, str, 8); + } + else if(strcasecmp(str, "trustedRootCA") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->trustedRootCA, str); + } + else if(strcasecmp(str, "clientCertificate") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->clientCertificate, str); + } + } + + wfaEncodeTLV(WFA_STA_SET_EAPTLS_TLV, sizeof(caStaSetEapTLS_t), (BYTE *)setsec, aBuf); + + *aLen = 4+sizeof(caStaSetEapTLS_t); + + return TRUE; +} + +int xcCmdProcStaSetEapTTLS(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetEapTTLS_t *setsec = (caStaSetEapTTLS_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->ssid, str, 64); + } + else if(strcasecmp(str, "username") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->username, str); + } + else if(strcasecmp(str, "password") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->passwd, str); + } + else if(strcasecmp(str, "keyMgmtType") == 0) + { + str=strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->keyMgmtType, str, 7); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->encrptype, str, 8); + } + else if(strcasecmp(str, "trustedRootCA") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->trustedRootCA, str); + } + else if(strcasecmp(str, "clientCertificate") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->clientCertificate, str); + } + } + + wfaEncodeTLV(WFA_STA_SET_EAPTTLS_TLV, sizeof(caStaSetEapTTLS_t), (BYTE *)setsec, aBuf); + + *aLen = 4+sizeof(caStaSetEapTTLS_t); + + return TRUE; +} + +int xcCmdProcStaSetEapSIM(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetEapSIM_t *setsec = (caStaSetEapSIM_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->ssid, str, 64); + } + else if(strcasecmp(str, "username") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->username, str); + } + else if(strcasecmp(str, "password") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->passwd, str); + } + else if(strcasecmp(str, "keyMgmtType") == 0) + { + str=strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->keyMgmtType, str, 7); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->encrptype, str, 8); + } + } + + wfaEncodeTLV(WFA_STA_SET_EAPSIM_TLV, sizeof(caStaSetEapSIM_t), (BYTE *)setsec, aBuf); + + *aLen = 4+sizeof(caStaSetEapSIM_t); + + return TRUE; +} + +int xcCmdProcStaSetPEAP(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetEapPEAP_t *setsec = (caStaSetEapPEAP_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->ssid, str, 64); + } + else if(strcasecmp(str, "username") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->username, str); + } + else if(strcasecmp(str, "password") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->passwd, str); + } + else if(strcasecmp(str, "keyMgmtType") == 0) + { + str=strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->keyMgmtType, str, 7); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->encrptype, str, 8); + } + else if(strcasecmp(str, "innerEAP") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->innerEAP, str); + } + else if(strcasecmp(str, "peapVersion") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setsec->peapVersion = atoi(str); + } + } + + + wfaEncodeTLV(WFA_STA_SET_PEAP_TLV, sizeof(caStaSetEapPEAP_t), (BYTE *)setsec, aBuf); + + *aLen = 4+sizeof(caStaSetEapPEAP_t); + + return TRUE; +} + + +int xcCmdProcStaSetIBSS(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetIBSS_t *setibss = (caStaSetIBSS_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setibss->intf, str, 15); + DPRINT_INFO(WFA_OUT, "interface %s\n", setibss->intf); + + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setibss->ssid, str, 64); + DPRINT_INFO(WFA_OUT, "ssid %s\n", setibss->ssid); + } + else if(strcasecmp(str, "channel") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setibss->channel = atoi(str); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str, "wep") == 0) + setibss->encpType = ENCRYPT_WEP; + else + setibss->encpType = 0; + } + else if(strcasecmp(str, "key1") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setibss->keys[0], str, 26); + setibss->activeKeyIdx = 0; + } + else if(strcasecmp(str, "key2") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setibss->keys[1], str, 26); + setibss->activeKeyIdx = 1; + } + else if(strcasecmp(str, "key3") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setibss->keys[2], str, 26); + setibss->activeKeyIdx = 2; + } + else if(strcasecmp(str, "key4") == 0) + { + DPRINT_INFO(WFA_OUT,"in key 4\n"); + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setibss->keys[3], str, 26); + setibss->activeKeyIdx = 3; + } + else if(strcasecmp(str, "activeKey") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setibss->activeKeyIdx = atoi(str); + } + } + + wfaEncodeTLV(WFA_STA_SET_IBSS_TLV, sizeof(caStaSetIBSS_t), (BYTE *)setibss, aBuf); + + *aLen = 4+sizeof(caStaSetIBSS_t); + + return TRUE; +} + +int xcCmdProcDeviceGetInfo(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *dutCmd = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + caDevInfo_t *dinfo = &dutCmd->cmdsu.dev; + char *str; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + dinfo->fw = 0; + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL && str[0] == '\0') + { + if(strcasecmp(str, "firmware") == 0) + { + dinfo->fw = 1; + } + } + + wfaEncodeTLV(WFA_DEVICE_GET_INFO_TLV, 0, NULL, aBuf); + + *aLen = 4; + + return TRUE; +} + +int xcCmdProcStaGetInfo(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + char *str; + dutCommand_t *getInfo = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(getInfo->intf, str, 15); + DPRINT_INFO(WFA_OUT, "interface %s\n", getInfo->intf); + + } + + wfaEncodeTLV(WFA_STA_GET_INFO_TLV, sizeof(dutCommand_t), (BYTE *)getInfo, aBuf); + + *aLen = 4 + sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcStaGetTestData(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + char *str; + dutCommand_t *dutCmd = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + caStaGetTestData_t *tdp = &dutCmd->cmdsu.tdata; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + + if(strcasecmp(str, "testdata") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str, "voice") == 0) + { + tdp->type = 1; + DPRINT_INFO(WFA_OUT, "testdata voice %i\n", tdp->type); + } + } + + wfaEncodeTLV(WFA_STA_GET_INFO_TLV, sizeof(dutCommand_t), (BYTE *)dutCmd, aBuf); + + *aLen = 4 + sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcStaAssociate(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *setassoc = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setassoc->intf, str, 15); + DPRINT_INFO(WFA_OUT, "interface %s\n", setassoc->intf); + + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str != NULL){ + strncpy(setassoc->cmdsu.ssid, str, 64); + DPRINT_INFO(WFA_OUT, "ssid %s\n", setassoc->cmdsu.ssid); + } + } + } + + wfaEncodeTLV(WFA_STA_ASSOCIATE_TLV, sizeof(dutCommand_t), (BYTE *)setassoc, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcStaReAssociate(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *setassoc = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setassoc->intf, str, 15); + DPRINT_INFO(WFA_OUT, "interface %s\n", setassoc->intf); + + } + else if(strcasecmp(str, "bssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setassoc->cmdsu.bssid, str, 64); + DPRINT_INFO(WFA_OUT, "bssid %s\n", setassoc->cmdsu.bssid); + } + } + + wfaEncodeTLV(WFA_STA_REASSOCIATE_TLV, sizeof(dutCommand_t), (BYTE *)setassoc, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcDeviceListIF(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *getdevlist = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + #ifdef DEBUG + int i; + #endif + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + + if(strcasecmp(str, "interfaceType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcmp(str, "802.11") == 0) + getdevlist->cmdsu.iftype = IF_80211; + + DPRINT_INFO(WFA_OUT, "interface type %i\n", getdevlist->cmdsu.iftype); + } + + wfaEncodeTLV(WFA_DEVICE_LIST_IF_TLV, sizeof(dutCommand_t), (BYTE *)getdevlist, aBuf); + + *aLen = 4 + sizeof(dutCommand_t); + +#if DEBUG + for(i = 0; i< *aLen; i++) + DPRINT_INFO(WFA_OUT,"%x ", aBuf[i]); + + DPRINT_INFO(WFA_OUT,"\n"); +#endif + + return TRUE; +} + +int xcCmdProcStaSetUAPSD(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetUAPSD_t *setuapsd = (caStaSetUAPSD_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + memset(setuapsd, 0, sizeof(caStaSetUAPSD_t)); /* Added as per BRCM 1.3 ASD */ + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setuapsd->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setuapsd->ssid, str, 64); + } + else if(strcasecmp(str, "maxSPlength") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setuapsd->maxSPLength = atoi(str); + } + else if(strcasecmp(str, "acBE") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setuapsd->acBE = atoi(str); + } + else if(strcasecmp(str, "acBK") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setuapsd->acBK = atoi(str); + + } + else if(strcasecmp(str, "acVI") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setuapsd->acVI = atoi(str); + + } + else if(strcasecmp(str, "acVO") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setuapsd->acVO = atoi(str); + } + } + +/* Start: Added as per BRCM 1.3 ASD */ + wfaEncodeTLV(WFA_STA_SET_UAPSD_TLV, sizeof(caStaSetUAPSD_t), (BYTE *)setuapsd, aBuf); + *aLen = 4+sizeof(caStaSetUAPSD_t); +/* End: Added as per BRCM 1.3 ASD */ + + + return TRUE; +} + +int xcCmdProcStaDebugSet(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *debugSet = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "level") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(atoi(str) == WFA_DEBUG_INFO || WFA_DEBUG_WARNING) + { + debugSet->cmdsu.dbg.level = atoi(str); + DPRINT_INFO(WFA_OUT, "dbg level %i\n", debugSet->cmdsu.dbg.level); + } + else + return FALSE; /* not support */ + + } + else if(strcasecmp(str, "enable") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + DPRINT_INFO(WFA_OUT,"enable %i\n", atoi(str)); + switch(atoi(str)) /* enable */ + { + case 1: + debugSet->cmdsu.dbg.state = 1; + DPRINT_INFO(WFA_OUT,"enable\n"); + break; + case 0: + debugSet->cmdsu.dbg.state = 0; + DPRINT_INFO(WFA_OUT,"disable\n"); + break; + default: + DPRINT_INFO(WFA_OUT,"wrong\n"); + return FALSE; /* command invalid */ + } + } + } + + wfaEncodeTLV(WFA_STA_DEBUG_SET_TLV, sizeof(dutCommand_t), (BYTE *)debugSet, aBuf); + + *aLen = 4 + sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcStaSetMode(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetMode_t *setmode = (caStaSetMode_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setmode->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setmode->ssid, str, 64); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str, "wep") == 0) + setmode->encpType = ENCRYPT_WEP; + else + setmode->encpType = 0; + } + else if(strcasecmp(str, "key1") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setmode->keys[0], str, 26); + DPRINT_INFO(WFA_OUT, "%s\n", setmode->keys[0]); + setmode->activeKeyIdx = 0; + } + else if(strcasecmp(str, "key2") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setmode->keys[1], str, 26); + DPRINT_INFO(WFA_OUT, "%s\n", setmode->keys[1]); + } + else if(strcasecmp(str, "key3") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setmode->keys[2], str, 26); + DPRINT_INFO(WFA_OUT, "%s\n", setmode->keys[2]); + } + else if(strcasecmp(str, "key4") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setmode->keys[3], str, 26); + DPRINT_INFO(WFA_OUT, "%s\n", setmode->keys[3]); + } + else if(strcasecmp(str, "activeKey") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setmode->activeKeyIdx = atoi(str); + } + else if(strcasecmp(str, "mode") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + DPRINT_INFO(WFA_OUT,"\r\n mode is %s\n",str); + if(strcasecmp(str, "adhoc") == 0) + setmode->mode = 1; + else + setmode->mode = 0; + } + else if(strcasecmp(str, "channel") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setmode->channel = atoi(str); + } + else + { + DPRINT_INFO(WFA_WNG, "Incorrect Command, check syntax\n"); + DPRINT_INFO(WFA_OUT,"\r\n mode is %s\n",str); + } + } + + wfaEncodeTLV(WFA_STA_SET_MODE_TLV, sizeof(caStaSetMode_t), (BYTE *)setmode, aBuf); + *aLen = 4+sizeof(caStaSetMode_t); + + return TRUE; +} + +int xcCmdProcStaSetPwrSave(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetPwrSave_t *setps = (caStaSetPwrSave_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setps->intf, str, 15); + } + else if(strcasecmp(str, "mode") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str,"on") == 0) + setps->mode = 2; + else if(strcasecmp(str,"off") == 0) + setps->mode = 0; + else + return FALSE; + } + } + + wfaEncodeTLV(WFA_STA_SET_PWRSAVE_TLV, sizeof(caStaSetPwrSave_t), (BYTE *)setps, aBuf); + *aLen = 4+sizeof(caStaSetPwrSave_t); + + return TRUE; +} + +int xcCmdProcStaSetWMM(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetWMM_t *setwmm = (caStaSetWMM_t *) (aBuf+sizeof(wfaTLV)); + char *str; + wfaTLV *hdr = (wfaTLV *)aBuf; + + DPRINT_INFO(WFA_OUT, "start xcCmdProcStaSetWMM ...\n"); + DPRINT_INFO(WFA_OUT, "params: %s\n", pcmdStr); + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + /* Some default values, in case they are not specified*/ + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setwmm->intf, str, 15); + } + else if(strcasecmp(str, "GROUP") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str,"WMMAC") == 0) + setwmm->group = GROUP_WMMAC; + else if(strcasecmp(str,"WMM-CONFIG") == 0) + { + setwmm->group = GROUP_WMMCONF; + setwmm->actions.config.frag_thr = 2346; + setwmm->actions.config.rts_thr = 2346; + setwmm->actions.config.wmm = 1; + } + } + else if(strcasecmp(str, "ACTION") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str,"addts") == 0) + { + /* Put default values for the tspec element */ + setwmm->action = WMMAC_ADDTS; + setwmm->actions.addts.accesscat = WMMAC_AC_BE; + setwmm->actions.addts.tspec.tsinfo.dummy1 = 1; + setwmm->actions.addts.tspec.tsinfo.dummy2 = 0; + } + else if(strcasecmp(str,"delts") == 0) + setwmm->action = WMMAC_DELTS; + DPRINT_INFO(WFA_OUT,"action is %d\n",setwmm->action); + } + else if(strcasecmp(str, "RTS_thr") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.config.rts_thr = atoi(str); + } + else if(strcasecmp(str, "wmm") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(atoi(str) != 0) + setwmm->actions.config.wmm = 1; + else + setwmm->actions.config.wmm = 0; + } + else if(strcasecmp(str, "Frag_thr") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.config.frag_thr = atoi(str); + } + else if(strcasecmp(str, "DIALOG_TOKEN") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.dialog_token = atoi(str); + } + else if(strcasecmp(str, "TID") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(setwmm->action == WMMAC_ADDTS) + setwmm->actions.addts.tspec.tsinfo.TID = atoi(str); + else + setwmm->actions.delts = atoi(str); + } + else if(strcasecmp(str, "SENDTRIG") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str,"true") == 0) + setwmm->send_trig=1; + else + setwmm->send_trig=0; + } + else if(strcasecmp(str, "DEST") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setwmm->dipaddr, str, 15); + } + else if(strcasecmp(str, "trigac") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str,"VO") == 0) + setwmm->trig_ac= TG_WMM_AC_VO; + else if(strcasecmp(str,"VI") == 0) + setwmm->trig_ac= TG_WMM_AC_VI; + else if(strcasecmp(str,"BE") == 0) + setwmm->trig_ac= TG_WMM_AC_BE; + else if(strcasecmp(str,"BK") == 0) + setwmm->trig_ac= TG_WMM_AC_BK; + } + else if(strcasecmp(str, "DIRECTION") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str,"UP") == 0) + setwmm->actions.addts.tspec.tsinfo.direction = WMMAC_UPLINK; + else if(strcasecmp(str,"DOWN") == 0) + setwmm->actions.addts.tspec.tsinfo.direction = WMMAC_DOWNLINK; + else if(strcasecmp(str,"BIDI") == 0) + setwmm->actions.addts.tspec.tsinfo.direction = WMMAC_BIDIR; + } + else if(strcasecmp(str, "PSB") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str,"UAPSD") == 0) + setwmm->actions.addts.tspec.tsinfo.PSB = 1; + else + setwmm->actions.addts.tspec.tsinfo.PSB = 0; + } + else if(strcasecmp(str, "UP") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.tsinfo.UP = atoi(str); + } + else if(strcasecmp(str, "Fixed") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str, "true") == 0) + setwmm->actions.addts.tspec.Fixed = 1; + else + setwmm->actions.addts.tspec.Fixed = 0; + } + else if(strcasecmp(str, "SIZE") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.size = atoi(str); + } + else if(strcasecmp(str, "MAXSIZE") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.maxsize = atoi(str); + } + else if(strcasecmp(str, "MIN_SRVC_INTRVL") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.min_srvc = atoi(str); + } + else if(strcasecmp(str, "MAX_SRVC_INTRVL") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.max_srvc = atoi(str); + } + else if(strcasecmp(str, "INACTIVITY") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.inactivity = atoi(str); + } + else if(strcasecmp(str, "SUSPENSION") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.suspension = atoi(str); + } + else if(strcasecmp(str, "SRVCSTARTTIME") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.srvc_strt_tim = atoi(str); + } + else if(strcasecmp(str, "MINDATARATE") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.mindatarate = atoi(str); + } + else if(strcasecmp(str, "MEANDATARATE") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.meandatarate = atoi(str); + } + else if(strcasecmp(str, "PEAKDATARATE") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.peakdatarate = atoi(str); + } + else if(strcasecmp(str, "BURSTSIZE") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.burstsize = atoi(str); + } + else if(strcasecmp(str, "DELAYBOUND") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.delaybound = atoi(str); + } + else if(strcasecmp(str, "PHYRATE") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.PHYrate = atoi(str); + } + else if(strcasecmp(str, "SBA") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.sba = (float)atof(str); + } + else if(strcasecmp(str, "MEDIUM_TIME") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + setwmm->actions.addts.tspec.medium_time = atoi(str); + } + else if(strcasecmp(str, "ACCESSCAT") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str,"VO") == 0) + setwmm->actions.addts.accesscat = WMMAC_AC_VO; + else if(strcasecmp(str,"VI") == 0) + setwmm->actions.addts.accesscat = WMMAC_AC_VI; + else if(strcasecmp(str,"BE") == 0) + setwmm->actions.addts.accesscat = WMMAC_AC_BE; + else if(strcasecmp(str,"BK") == 0) + setwmm->actions.addts.accesscat = WMMAC_AC_BK; + } + } + if (setwmm->action == WMMAC_ADDTS) { + DPRINT_INFO(WFA_OUT, "ADDTS AC PARAMS: dialog id: %d, TID: %d, DIRECTION: %d, PSB: %d, UP: %d,\ + Fixed %d, MSDU Size: %d, Max MSDU Size %d, MIN SERVICE INTERVAL: %d, MAX SERVICE INTERVAL: %d\ + ,INACTIVITY: %d,SUSPENSION %d,SERVICE START TIME: %d,MIN DATARATE: %d,MEAN DATA RATE: %d\ + , PEAK DATA RATE: %d,BURSTSIZE: %d,DELAY BOUND: %d,PHYRATE: %d, SPLUSBW: %f,MEDIUM TIME: %d, ACCESSCAT: %d\n"\ + ,setwmm->actions.addts.dialog_token,setwmm->actions.addts.tspec.tsinfo.TID\ + ,setwmm->actions.addts.tspec.tsinfo.direction,setwmm->actions.addts.tspec.tsinfo.PSB,setwmm->actions.addts.tspec.tsinfo.UP\ + ,setwmm->actions.addts.tspec.Fixed,setwmm->actions.addts.tspec.size, setwmm->actions.addts.tspec.maxsize,\ + setwmm->actions.addts.tspec.min_srvc,\ + setwmm->actions.addts.tspec.max_srvc,setwmm->actions.addts.tspec.inactivity,setwmm->actions.addts.tspec.suspension,\ + setwmm->actions.addts.tspec.srvc_strt_tim,setwmm->actions.addts.tspec.mindatarate,setwmm->actions.addts.tspec.meandatarate\ + ,setwmm->actions.addts.tspec.peakdatarate,setwmm->actions.addts.tspec.burstsize,\ + setwmm->actions.addts.tspec.delaybound,setwmm->actions.addts.tspec.PHYrate,setwmm->actions.addts.tspec.sba,\ + setwmm->actions.addts.tspec.medium_time,setwmm->actions.addts.accesscat); + } + else + DPRINT_INFO(WFA_OUT, "DELTS AC PARAMS: TID: %d\n", setwmm->actions.delts); + + hdr->tag = WFA_STA_SET_WMM_TLV; + hdr->len = sizeof(caStaSetWMM_t); + + memcpy(aBuf+4, setwmm, sizeof(caStaSetWMM_t)); + + *aLen = 4+sizeof(caStaSetWMM_t); + + return TRUE; +} + +int xcCmdProcStaNeigreq(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *neigreq = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "mac") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(neigreq->mac, str, WFA_MAC_ADDR_STR_LEN); + DPRINT_INFO(WFA_OUT, "mac %s\n", neigreq->mac); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str != NULL) + { + strncpy(neigreq->cmdsu.ssid, str, WFA_SSID_NAME_LEN); + DPRINT_INFO(WFA_OUT, "ssid %s\n", neigreq->cmdsu.ssid); + } + } + } + + wfaEncodeTLV(WFA_STA_SEND_NEIGREQ_TLV, sizeof(dutCommand_t), (BYTE *)neigreq, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + + +int xcCmdProcStaSetSystime(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *systime = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + int temp; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "month") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + temp = atoi(str); + /* + * If month is more than 2 character then error + * If it is 2 character and less than 10 and first char is not 0 like '1b' + * 'b7' etc. All possible errors input taken care + */ + if ((temp > 12 || temp < 1) || (strlen(str) > 2) || + (strlen(str) == 2 && temp < 10 && str[0] != '0')) + { + DPRINT_ERR(WFA_OUT, "Wrong month input \n"); + return FALSE; + } + systime->cmdsu.stime.month = temp; + DPRINT_INFO(WFA_OUT, "month %d\n", systime->cmdsu.stime.month); + } + else if(strcasecmp(str, "date") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + temp = atoi(str); + if ((temp > 31 || temp < 1) || (strlen(str) > 2) || + (strlen(str) == 2 && temp < 10 && str[0] != '0')) + { + DPRINT_ERR(WFA_OUT, "Wrong date input \n"); + return FALSE; + } + /* In case of Linux there is no invalid date, all dates will be accepted and it will + * set to next corresponding valid date + * In case of win32 system will return error while setting bad date + */ + systime->cmdsu.stime.date = temp; + DPRINT_INFO(WFA_OUT, "date %d\n", systime->cmdsu.stime.date); + } + else if(strcasecmp(str, "year") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + temp = atoi(str); + /* + * Unix date start from 1970, so lower limit kept + */ + if (temp < 1970 || strlen(str) > 4) + { + DPRINT_ERR(WFA_OUT, "Wrong year input\n"); + return FALSE; + } + systime->cmdsu.stime.year = temp; + DPRINT_INFO(WFA_OUT, "year %d\n", systime->cmdsu.stime.year); + } + else if(strcasecmp(str, "hours") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + temp = atoi(str); + if ((temp > 23 || temp < 0) || (strlen(str) > 2) || + (strlen(str) == 2 && temp < 10 && str[0] != '0')) + { + DPRINT_ERR(WFA_OUT, "Wrong hours input \n"); + return FALSE; + } + systime->cmdsu.stime.hours = temp; + DPRINT_INFO(WFA_OUT, "hours %d\n", systime->cmdsu.stime.hours); + } + else if(strcasecmp(str, "minutes") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + temp = atoi(str); + if ((temp > 59 || temp < 0) || (strlen(str) > 2) || + (strlen(str) == 2 && temp < 10 && str[0] != '0')) + { + DPRINT_ERR(WFA_OUT, "Wrong minutes input \n"); + return FALSE; + } + systime->cmdsu.stime.minutes = temp; + DPRINT_INFO(WFA_OUT, "minutes %d\n", systime->cmdsu.stime.minutes); + } + else if(strcasecmp(str, "seconds") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + temp = atoi(str); + if ((temp > 59 || temp < 0) || (strlen(str) > 2) || + (strlen(str) == 2 && temp < 10 && str[0] != '0')) + { + DPRINT_ERR(WFA_OUT, "Wrong seconds input \n"); + return FALSE; + } + systime->cmdsu.stime.seconds = temp; + DPRINT_INFO(WFA_OUT, "seconds %d\n", systime->cmdsu.stime.seconds); + } + } + + wfaEncodeTLV(WFA_STA_SET_SYSTIME_TLV, sizeof(dutCommand_t), (BYTE *)systime, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + +#ifdef WFA_STA_TB + +int xcCmdProcStaSet11n(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *Set11n = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + int smps; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + /* 1 is for disable and 2 is for enable, as all values set to 0 initially */ + if(strcasecmp(str, "40_intolerant") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "enable") == 0) + Set11n->cmdsu.set11n.intolerant_40 = 2; + else if(strcasecmp(str, "disable") == 0) + Set11n->cmdsu.set11n.intolerant_40 = 1; + else + { + DPRINT_ERR(WFA_OUT, "not a proper action id\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "40_intolerant %d\n", Set11n->cmdsu.set11n.intolerant_40); + } + else if(strcasecmp(str, "addba_reject") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "enable") == 0) + Set11n->cmdsu.set11n.addba_reject = 2; + else if(strcasecmp(str, "disable") == 0) + Set11n->cmdsu.set11n.addba_reject = 1; + else + { + DPRINT_ERR(WFA_OUT, "not a proper action id\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "addba_reject %d\n", Set11n->cmdsu.set11n.addba_reject); + } + else if(strcasecmp(str, "ampdu") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "enable") == 0) + Set11n->cmdsu.set11n.ampdu = 2; + else if(strcasecmp(str, "disable") == 0) + Set11n->cmdsu.set11n.ampdu = 1; + else + { + DPRINT_ERR(WFA_OUT, "not a proper action id\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "ampdu %d\n", Set11n->cmdsu.set11n.ampdu); + } + else if(strcasecmp(str, "amsdu") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "enable") == 0) + Set11n->cmdsu.set11n.amsdu = 2; + else if(strcasecmp(str, "disable") == 0) + Set11n->cmdsu.set11n.amsdu = 1; + else + { + DPRINT_ERR(WFA_OUT, "not a proper action id\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "amsdu %d\n", Set11n->cmdsu.set11n.amsdu); + } + else if(strcasecmp(str, "greenfield") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "enable") == 0) + Set11n->cmdsu.set11n.greenfield = 2; + else if(strcasecmp(str, "disable") == 0) + Set11n->cmdsu.set11n.greenfield = 1; + else + { + DPRINT_ERR(WFA_OUT, "not a proper action id\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "greenfield %d\n", Set11n->cmdsu.set11n.greenfield); + } + else if(strcasecmp(str, "sgi20") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "enable") == 0) + Set11n->cmdsu.set11n.sgi20 = 2; + else if(strcasecmp(str, "disable") == 0) + Set11n->cmdsu.set11n.sgi20 = 1; + else + { + DPRINT_ERR(WFA_OUT, "not a proper action id\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "sgi20 %d\n", Set11n->cmdsu.set11n.sgi20); + } + else if(strcasecmp(str, "stbc_rx") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + Set11n->cmdsu.set11n.stbc_rx = atoi(str); + DPRINT_INFO(WFA_OUT, "stbc_rx %d\n", Set11n->cmdsu.set11n.stbc_rx); + } + else if(Set11n->cmdsu.set11n.stbc_rx == 0) + { + Set11n->cmdsu.set11n.stbc_rx = -1; + } + else if(strcasecmp(str, "width") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "auto") == 0) + Set11n->cmdsu.set11n.width = -1; + else + Set11n->cmdsu.set11n.width = atoi(str); + DPRINT_INFO(WFA_OUT, "width %d\n", Set11n->cmdsu.set11n.width); + } + else if(strcasecmp(str, "mcs32") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "enable") == 0) + Set11n->cmdsu.set11n.mcs32 = 2; + else if(strcasecmp(str, "disable") == 0) + Set11n->cmdsu.set11n.mcs32 = 1; + else + { + DPRINT_ERR(WFA_OUT, "not a proper action id\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "mcs32 %d\n", Set11n->cmdsu.set11n.mcs32); + } + else if(strcasecmp(str, "smps") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + smps = atoi(str); + smps++; + Set11n->cmdsu.set11n.smps = smps; + DPRINT_INFO(WFA_OUT, "smps %d\n", Set11n->cmdsu.set11n.smps); + } + else if(strcasecmp(str, "txsp_stream") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + Set11n->cmdsu.set11n.txsp_stream = atoi(str); + DPRINT_INFO(WFA_OUT, "txsp_stream %d\n", Set11n->cmdsu.set11n.txsp_stream); + } + else if(strcasecmp(str, "rxsp_stream") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + Set11n->cmdsu.set11n.rxsp_stream = atoi(str); + DPRINT_INFO(WFA_OUT, "rxsp_stream %d\n", Set11n->cmdsu.set11n.rxsp_stream); + } + else if(strcasecmp(str, "mcs_fixedrate") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + Set11n->cmdsu.set11n.mcs_fixedrate = atoi(str); + if((Set11n->cmdsu.set11n.mcs_fixedrate > 31) || (Set11n->cmdsu.set11n.mcs_fixedrate < 0)) + return FALSE; + DPRINT_INFO(WFA_OUT, "mcs_fixedrate %d\n", Set11n->cmdsu.set11n.mcs_fixedrate); + } + else + { + /* done to ignore mcs if it is not set */ + Set11n->cmdsu.set11n.mcs_fixedrate = -1; + } + } + + wfaEncodeTLV(WFA_STA_SET_11N_TLV, sizeof(dutCommand_t), (BYTE *)Set11n, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcStaSetRIFSTest(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *rifstest = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(rifstest->intf, str, WFA_IF_NAME_LEN); + DPRINT_INFO(WFA_OUT, "interface %s\n", rifstest->intf); + } + if(strcasecmp(str, "action") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "enable") == 0) + rifstest->cmdsu.action_rifs = 2; + else if(strcasecmp(str, "disable") == 0) + rifstest->cmdsu.action_rifs = 1; + else + { + DPRINT_ERR(WFA_OUT, "not a proper action id\n"); + return FALSE; + } + DPRINT_INFO(WFA_OUT, "action %d\n", rifstest->cmdsu.action_rifs); + } + } + wfaEncodeTLV(WFA_STA_SET_RIFS_TEST_TLV, sizeof(dutCommand_t), (BYTE *)rifstest, aBuf); + + *aLen = 4 + sizeof(dutCommand_t); + return TRUE; +} + +int xcCmdProcStaSetWireless(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *wireless = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(wireless->intf, str, WFA_IF_NAME_LEN); + DPRINT_INFO(WFA_OUT, "interface %s\n", wireless->intf); + } + else if(strcasecmp(str, "band") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(wireless->cmdsu.wireless_band, str, strlen(str)); + DPRINT_INFO(WFA_OUT, "band %s\n", wireless->cmdsu.wireless_band); + } + } + + wfaEncodeTLV(WFA_STA_SET_WIRELESS_TLV, sizeof(dutCommand_t), (BYTE *)wireless, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcStaSendAddba(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *addba = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(addba->intf, str, WFA_IF_NAME_LEN); + DPRINT_INFO(WFA_OUT, "interface %s\n", addba->intf); + } + else if(strcasecmp(str, "tid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + addba->cmdsu.tid = atoi(str); + DPRINT_INFO(WFA_OUT, "tid %d\n", addba->cmdsu.tid); + } + } + + wfaEncodeTLV(WFA_STA_SEND_ADDBA_TLV, sizeof(dutCommand_t), (BYTE *)addba, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + +int xcCmdProcStaSendCoexistMGMT(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *coexist = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(coexist->intf, str, WFA_IF_NAME_LEN); + DPRINT_INFO(WFA_OUT, "interface %s\n", coexist->intf); + } + else if(strcasecmp(str, "type") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "MHz") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "value") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(coexist->cmdsu.coexistmgmt.Mhz, str, 1); + } + } + else if(strcasecmp(str, "BSS") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "value") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(coexist->cmdsu.coexistmgmt.bss, str, 1); + } + } + else if(strcasecmp(str, "ChnlRepo") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + if(strcasecmp(str, "value") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(coexist->cmdsu.coexistmgmt.ChnlRepo, str, strlen(str)); + } + } + } + } + + wfaEncodeTLV(WFA_STA_SEND_COEXIST_MGMT_TLV, sizeof(dutCommand_t), (BYTE *)coexist, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + return TRUE; +} + +int xcCmdProcStaDisconnect(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + dutCommand_t *disconnect = (dutCommand_t *) (aBuf+sizeof(wfaTLV)); + char *str; + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + return FALSE; + strncpy(disconnect->intf, str, WFA_IF_NAME_LEN); + DPRINT_INFO(WFA_OUT, "intf %s\n", disconnect->intf); + } + } + + wfaEncodeTLV(WFA_STA_DISCONNECT_TLV, sizeof(dutCommand_t), (BYTE *)disconnect, aBuf); + + *aLen = 4+sizeof(dutCommand_t); + + return TRUE; +} + +#endif /* WFA_STA_TB */ + +int xcCmdProcStaResetDefault(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaResetDefault_t *reset = (caStaResetDefault_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(reset->intf, str, 15); + } + else if(strcasecmp(str, "program") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(reset->prog, str, 16); + } + } + + wfaEncodeTLV(WFA_STA_RESET_DEFAULT_TLV, sizeof(caStaResetDefault_t), (BYTE *)reset, aBuf); + *aLen = 4+sizeof(caStaResetDefault_t); + + return TRUE; +} + +int xcCmdProcStaSetEapFAST(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetEapFAST_t *setsec = (caStaSetEapFAST_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->ssid, str, 64); + } + else if(strcasecmp(str, "username") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->username, str); + } + else if(strcasecmp(str, "password") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->passwd, str); + } + else if(strcasecmp(str, "keyMgmtType") == 0) + { + str=strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->keyMgmtType, str, 7); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->encrptype, str, 8); + } + else if(strcasecmp(str, "trustedRootCA") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->trustedRootCA, str,31); + } + else if(strcasecmp(str, "innerEAP") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->innerEAP, str); + } + else if(strcasecmp(str, "validateServer") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(strcasecmp(str, "yes") == 0) + { + setsec->validateServer=1; + } + else if(strcasecmp(str, "no") == 0) + { + setsec->validateServer=0; + } + } + else if(strcasecmp(str, "pacFile") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->pacFileName, str); + } + } + + wfaEncodeTLV(WFA_STA_SET_EAPFAST_TLV, sizeof(caStaSetEapFAST_t), (BYTE *)setsec, aBuf); + + *aLen = 4+sizeof(caStaSetEapFAST_t); + + return TRUE; +} + + +int xcCmdProcStaSetEapAKA(char *pcmdStr, BYTE *aBuf, int *aLen) +{ + caStaSetEapAKA_t *setsec = (caStaSetEapAKA_t *) (aBuf+sizeof(wfaTLV)); + char *str; + + if(aBuf == NULL) + return FALSE; + + memset(aBuf, 0, *aLen); + + for(;;) + { + str = strtok_r(NULL, ",", &pcmdStr); + if(str == NULL || str[0] == '\0') + break; + + if(strcasecmp(str, "interface") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->intf, str, 15); + } + else if(strcasecmp(str, "ssid") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->ssid, str, 64); + } + else if(strcasecmp(str, "username") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->username, str); + } + else if(strcasecmp(str, "password") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strcpy(setsec->passwd, str); + } + else if(strcasecmp(str, "keyMgmtType") == 0) + { + str=strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->keyMgmtType, str, 7); + } + else if(strcasecmp(str, "encpType") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy(setsec->encrptype, str, 8); + } + else if(strcasecmp(str, "triplet1") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setsec->tripletSet[0], str, 63); + DPRINT_INFO(WFA_OUT, "Triplet1 : %s\n", setsec->tripletSet[0]); + setsec->tripletCount = 1; + } + else if(strcasecmp(str, "triplet2") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setsec->tripletSet[1], str, 63); + DPRINT_INFO(WFA_OUT, "Triplet2 : %s\n", setsec->tripletSet[1]); + setsec->tripletCount=2; + } + else if(strcasecmp(str, "triplet3") == 0) + { + str = strtok_r(NULL, ",", &pcmdStr); + strncpy((char *)setsec->tripletSet[2], str, 63); + DPRINT_INFO(WFA_OUT, "Triplet1 : %s\n", setsec->tripletSet[2]); + setsec->tripletCount = 3; + } + } + + wfaEncodeTLV(WFA_STA_SET_EAPAKA_TLV, sizeof(caStaSetEapAKA_t), (BYTE *)setsec, aBuf); + + *aLen = 4+sizeof(caStaSetEapAKA_t); + + return TRUE; +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_cmdtbl.c b/src/tools/Wifi_ASD_test/lib/wfa_cmdtbl.c new file mode 100644 index 0000000..fbb6de0 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_cmdtbl.c
@@ -0,0 +1,167 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ +/* + * File: wfa_cmdtbl.c + * The file contains a predefined function array. The command process and + * execution functions of a DUT traffic generator and control will be + * registered in the array/table by the order of the defined commands TLV + * values. + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA release by qhu + * 2006/06/13 -- 00.02 release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/09/01 -- 01.05 Release by qhu + * 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef WIN32 +#include <sys/socket.h> +#endif +#include "wfa_debug.h" +#include "wfa_sock.h" +#include "wfa_types.h" +#include "wfa_main.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_miscs.h" +#include "wfa_ca.h" +#include "wfa_agt.h" +#include "wfa_rsp.h" + +/* extern defined variables */ +extern int gxcSockfd, btSockfd; + +int NotDefinedYet(int len, unsigned char *params, int *respLen, BYTE *respBuf); +extern int agtCmdProcGetVersion(int len, BYTE *parms, int *respLen, BYTE *respBuf); + +extern unsigned short wfa_defined_debug; + +/* globally define the function table */ +xcCommandFuncPtr gWfaCmdFuncTbl[WFA_STA_COMMANDS_END] = +{ + /* Traffic Agent Commands */ + NotDefinedYet, /* None (0) */ + agtCmdProcGetVersion, /* WFA_GET_VERSION_TLV (1) */ + wfaTGSendPing, /* WFA_TRAFFIC_SEND_PING_TLV (2) */ + wfaTGStopPing, /* WFA_TRAFFIC_STOP_PING_TLV (3) */ + wfaTGConfig, /* WFA_TRAFFIC_AGENT_CONFIG_TLV (4) */ + wfaTGSendStart, /* WFA_TRAFFIC_AGENT_SEND_TLV (5) */ + wfaTGRecvStart, /* WFA_TRAFFIC_AGENT_RECV_START_TLV (6) */ + wfaTGRecvStop, /* WFA_TRAFFIC_AGENT_RECV_STOP_TLV (7) */ + wfaTGReset, /* WFA_TRAFFIC_AGENT_RESET_TLV (8) */ + NotDefinedYet, /* WFA_TRAFFIC_AGENT_STATUS_TLV (9) */ + + /* Control and Configuration Commands */ + wfaStaGetIpConfig, /* WFA_STA_GET_IP_CONFIG_TLV (10)*/ + wfaStaSetIpConfig, /* WFA_STA_SET_IP_CONFIG_TLV (11)*/ + wfaStaGetMacAddress, /* WFA_STA_GET_MAC_ADDRESS_TLV (12)*/ + NotDefinedYet, /* WFA_STA_SET_MAC_ADDRESS_TLV (13)*/ + wfaStaIsConnected, /* WFA_STA_IS_CONNECTED_TLV (14)*/ + wfaStaVerifyIpConnection, /* WFA_STA_VERIFY_IP_CONNECTION_TLV (15)*/ + wfaStaGetBSSID, /* WFA_STA_GET_BSSID_TLV (16)*/ + wfaStaGetStats, /* WFA_STA_GET_STATS_TLV (17)*/ + wfaSetEncryption, /* WFA_STA_SET_ENCRYPTION_TLV (18)*/ + wfaStaSetPSK, /* WFA_STA_SET_PSK_TLV (19)*/ + wfaStaSetEapTLS, /* WFA_STA_SET_EAPTLS_TLV (20)*/ + wfaStaSetUAPSD, /* WFA_STA_SET_UAPSD_TLV (21)*/ + wfaStaAssociate, /* WFA_STA_ASSOCIATE_TLV (22)*/ + wfaStaSetEapTTLS, /* WFA_STA_SET_EAPTTLS_TLV (23)*/ + wfaStaSetEapSIM, /* WFA_STA_SET_EAPSIM_TLV (24)*/ + wfaStaSetPEAP, /* WFA_STA_SET_PEAP_TLV (25)*/ + wfaStaSetIBSS, /* WFA_STA_SET_IBSS_TLV (26)*/ + wfaStaGetInfo, /* WFA_STA_GET_INFO_TLV (27)*/ + wfaDeviceGetInfo, /* WFA_DEVICE_GET_INFO_TLV (28)*/ + wfaDeviceListIF, /* WFA_DEVICE_LIST_IF_TLV] (29)*/ + wfaStaDebugSet, /* WFA_STA_DEBUG_SET (30)*/ + wfaStaSetMode, /* WFA_STA_SET_MODE (31)*/ + wfaStaSetWMM, /* WFA_STA_SET_WMM (32)*/ + wfaStaSendNeigreq, /* WFA_STA_SEND_NEIGREQ (33)*/ + wfaStaSetSystime, /* WFA_STA_SET_SYSTIME (34)*/ + wfaStaSet11n, /* WFA_STA_SET_11N (35)*/ + wfaStaSetRifsTest, /* WFA_STA_SET_RIFS_TEST (36)*/ + wfaStaSetWireless, /* WFA_STA_SET_WIRELESS (37)*/ + wfaStaSendAddba, /* WFA_STA_SEND_ADDBA (38)*/ + wfaStaSendCoexistMgmt, /* WFA_STA_SEND_COEXIST_MGMT (39)*/ + wfaStaSetDisconnect, /* WFA_STA_SET_DISCONNECT (40)*/ + wfaStaSetEapFAST, /* WFA_STA_SET_EAPFAST_TLV (41)*/ + wfaStaSetEapAKA, /* WFA_STA_SET_EAPAKA_TLV (42)*/ + wfaStaReAssociate, /* WFA_STA_REASSOCIATE (41)*/ + wfaStaSetPwrSave, /* WFA_STA_SET_PWRSAVE (42)*/ + wfaStaResetDefault, /* WFA_STA_RESET_DEFAULT (43)*/ +}; + + +/* + * NotDefinedYet(): a dummy function + */ +int NotDefinedYet(int len, unsigned char *params, int *respLen, BYTE *respBuf) +{ + DPRINT_WARNING(WFA_WNG, "The command processing function not defined.\n"); + + + /* need to send back a response */ + + return TRUE; +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_cs.c b/src/tools/Wifi_ASD_test/lib/wfa_cs.c new file mode 100755 index 0000000..d084c41 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_cs.c
@@ -0,0 +1,3139 @@ +/**************************************************************************** +* (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved +* +* +* LICENSE +* +* License is granted only to Wi-Fi Alliance members and designated +* contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted +* the non-exclusive, worldwide, limited right to use, copy, import, export +* and distribute this software: +* (i) solely for noncommercial applications and solely for testing Wi-Fi +* equipment; and +* (ii) solely for the purpose of embedding the software into Authorized +* Licensee$B!G(Bs proprietary equipment and software products for distribution to +* its customers utipnder a license with at least the same restrictions as +* contained in this License, including, without limitation, the disclaimer of +* warranty and limitation of liability, below..AN The distribution rights +* granted in clause +* (ii), above, include distribution to third party companies who will +* redistribute the Authorized Licensee$B!G(Bs product to their customers with or +* without such third party$B!G(Bs private label. Other than expressly granted +* herein, this License is not transferable or sublicensable, and it does not +* extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance +* reserves all rights not expressly granted herein..AN +*.AN +* Except as specifically set forth above, commercial derivative works of +* this software or applications that use the Wi-Fi scripts generated by this +* software are NOT AUTHORIZED without specific prior written permission from +* Wi-Fi Alliance. +*.AN +* Non-Commercial derivative works of this software for internal use are +* authorized and are limited by the same restrictions; provided, however, +* that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of +* such derivative works under a perpetual, payment-free license to use, +* modify, and distribute such derivative works for purposes of testing Wi-Fi +* equipment. +*.AN +* Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse +* or promote products that are derived from or that use this software without +* specific prior written permission from Wi-Fi Alliance. +* +* THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, +* ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, +* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE +* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF +* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +* File: wfa_cs.c -- configuration and setup +* This file contains all implementation for the dut setup and control +* functions, such as network interfaces, ip address and wireless specific +* setup with its supplicant. +* +* The current implementation is to show how these functions +* should be defined in order to support the Agent Control/Test Manager +* control commands. To simplify the current work and avoid any GPL licenses, +* the functions mostly invoke shell commands by calling linux system call, +* system("<commands>"). +* +* It depends on the differnt device and platform, vendors can choice their +* own ways to interact its systems, supplicants and process these commands +* such as using the native APIs. +* +* Revision History: +* 2006/03/10 -- initially created by qhu +* 2006/06/01 -- BETA Release by qhu +* 2006/06/13 -- 00.02 Release by qhu +* 2006/06/30 -- 00.10 Release by qhu +* 2006/07/10 -- 01.00 Release by qhu +* 2006/09/01 -- 01.05 Release by qhu +* 2006/10/26 -- 01.06 Released by qhu +* replace hardcoded buf size with macro +* 2006/12/02 -- bugs: 1. fixes incorrect order of getipconfig.sh +* input parameters reported by p.schwann +* 2. will add a new network for wap_cli command +* in case the network id 0 not present, +* recommended by c.benson +* the solution is to reimplement with calling +* native C API +* 2007/01/11 -- 01.10 released by qhu +* 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi +* 2007/03/18 -- add file close statements +* 2007/03/21 -- rename the file to avoid the confusion. +* 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu +* 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu +* 2007/08/15 -- 02.10 WMM-Power Save release by qhu +* 2007/10/10 -- 02.20 Voice SOHO beta -- qhu +* 2007/11/07 -- 02.30 Voice HSO -- qhu +* +*/ +#ifndef WIN32 +#include <unistd.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <arpa/inet.h> +#include <linux/types.h> +#include <linux/socket.h> +#include <poll.h> +#include <bcmendian.h> +#else +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <windows.h> +#include <iphlpapi.h> +#endif + +#include "wfa_debug.h" +#include "wfa_ver.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_ca.h" +#include "wfa_tlv.h" +#include "wfa_sock.h" +#include "wfa_tg.h" +#include "wfa_cmds.h" +#include "wfa_rsp.h" +#include "wfa_miscs.h" +#ifdef WFA_WMM_EXT +#ifdef WFA_WMM_PS_EXT +#include "wfa_wmmps.h" +#endif +#endif + +#define CERTIFICATES_PATH "/etc/wpa_supplicant" +#define TSPEC_VER 2 +#define TSPEC_BUF_SIZE 15 +#define MAX_TOKENS 15 +#define BYTE_0 0 +#define BYTE_1 1 +#define BYTE_2 2 +#define TID_INDEX 4 +#define NO_TSINFO 1 +#define TID_MISMATCH 2 + +/* Some device may only support UDP ECHO, activate this line */ +//#define WFA_PING_UDP_ECHO_ONLY 1 + + +int g_serv_sock_desc; + +/* Start --> Modified as per BRCM 1.3 ASD */ + +/* error code */ +#define BCM_OK 0 +#define BCM_BAD 1 + +#define BCM_SSID_LEN_MAX 32 +#define BCM_SSID_MAX 32 + +/* defines for BSS types */ +#define BCM_BSS_INVALID 0 +#define BCM_BSS_INDEPENDENT 1 +#define BCM_BSS_INFRA 3 +#define BCM_BSS_AUTO 4 + +/* defines for WPA AITHENTICATION */ +#define BCM_WPA_AUTH_DISABLED 0x0 +#define BCM_WPA_AUTH_NONE 0x1 +#define BCM_WPA_AUTH_8021X 0x2 +#define BCM_WPA_AUTH_PSK 0x4 +#define BCM_WPA2_AUTH_8021X 0x40 +#define BCM_WPA2_AUTH_PSK 0x80 + +#define BCM_WEP_KEY_SIZE_MAX 32 +#define BCM_8021X_ASSOC_TIMEOUT 3600 +#define BCM_PRI_KEY_BAD (-1) + +typedef union bcmEapObj { + caStaSetEapTLS_t setEapTLS; + caStaSetEapTTLS_t setEapTTLS; + caStaSetEapSIM_t setEapSIM; + caStaSetEapPEAP_t setEapPEAP; + caStaSetEapFAST_t setEapFAST; + caStaSetEapAKA_t setEapAKA; +} bcmEapObj_t; + +typedef struct bcmSsidObj +{ + char ssidStr[BCM_SSID_LEN_MAX + 1]; + int bssType; + int channel; + int wsec; + int auth; /* 802.11 authentication : default 0 for open. */ + int wpa_auth; /* WPA authentication: default 1 for WPA-NONE */ + int uapsd; + char keys[4][BCM_WEP_KEY_SIZE_MAX]; /* wl addwep */ + int primary_key; + BYTE passphrase[64]; /* wl set_pmk */ + int powerSave; + /* UAPSD */ + int maxSPLength; + int acBE; + int acBK; + int acVI; + int acVO; + /* EAP Types*/ + bcmEapObj_t eapObj; + int eapType; +} bcmSsidObj_t; + +typedef struct bcmSsidObjTbl +{ + bcmSsidObj_t ssidObj[BCM_SSID_MAX]; + uint addCnt; + uint delCnt; + uint entries; +} bcmSsidObjTbl_t; + +bcmSsidObjTbl_t bsotbl; +int bcmSsidIsGood(char *ssidStr); +bcmSsidObj_t *bcmWfaSsidTblFreeEntry(); +bcmSsidObj_t *bcmWfaSsidTblSsidFind(char *ssidStr); +bcmSsidObj_t *bcmWfaSsidObjTblAdd(char *ssidStr); +void bcmWfaSsidObjTblDel(char *ssidStr); +void bcmWfaSsidObjPrint(bcmSsidObj_t *bso); +void bcmWfaSsidObjTblPrint(void); + +/* End --> Modified as per BRCM 1.3 ASD */ + +/* Since the two definitions are used all over the CA function */ +char gCmdStr[WFA_CMD_STR_SZ]; +dutCmdResponse_t gGenericResp; + +/* +* agtCmdProcGetVersion(): response "ca_get_version" command to controller +* input: cmd --- not used +* valLen -- not used +* output: parms -- a buffer to store the version info response. +*/ + +int agtCmdProcGetVersion(int len, BYTE *parms, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t *getverResp = &gGenericResp; + + DPRINT_INFO(WFA_OUT, "entering agtCmdProcGetVersion ...\n"); + + getverResp->status = STATUS_COMPLETE; + strncpy(getverResp->cmdru.version, WFA_SYSTEM_VER, 8); + + wfaEncodeTLV(WFA_GET_VERSION_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)getverResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return TRUE; +} + +/* +* wfaStaAssociate(): +* The function is to force the station wireless I/F to re/associate +* with the AP. +*/ +int wfaStaAssociate(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int retVal = TRUE; + dutCommand_t *assoc = (dutCommand_t *)caCmdBuf; + dutCmdResponse_t *staAssocResp = &gGenericResp; + /* Start: Modified as per BRCM 1.3 ASD */ + int imode; /* 0 for ibss, 1 for infrastructure */ + char ssidTarget[WFA_SSID_NAME_LEN]; + bcmSsidObj_t *bso; + int idx; + char identity[WFA_BUFF_128],dummy[WFA_BUFF_128]; + + DPRINT_INFO(WFA_OUT, "entering wfaStaAssociate ...\n"); + /* use 'ifconfig' command to bring down the interface (linux specific) */ + + memcpy(ssidTarget, assoc->cmdsu.ssid, WFA_SSID_NAME_LEN); + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + retVal = FALSE; + goto exit; + } + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + } + imode = (bso->bssType == BCM_BSS_INDEPENDENT) ? 0 : 1; + sprintf(gCmdStr, "%s disassoc", rwl_client_path); + exec_process(gCmdStr); + + asd_sleep(3); + /*Default case will be non-802.1x associations*/ + switch (bso->eapType) { + case BCM_EAP_TYPE_TLS: + strncpy(identity,bso->eapObj.setEapTLS.clientCertificate,sizeof(identity)); + /* For EAPTLS, identity is taken as the file name of the Client certificate + * since we do not have any username information in this mode + */ + printf("\n %s\n",identity); + strtok_r(identity,".",(char **)&dummy); + printf("\n %s\n",identity); + S_N_PRINTF(gCmdStr,sizeof(gCmdStr),"%s sh cnClient -A %s -ssid %s -%s -%s -tls " + "-usercert %s %s -identity %s -validate %s -timeout %d %s ", rwl_client_path, + bso->eapObj.setEapTLS.intf, bso->eapObj.setEapTLS.ssid, + bso->eapObj.setEapTLS.keyMgmtType, bso->eapObj.setEapTLS.encrptype, + bso->eapObj.setEapTLS.clientCertificate, KEY_FILE, identity, + bso->eapObj.setEapTLS.trustedRootCA, BCM_8021X_ASSOC_TIMEOUT, "%"); + retVal = exec_process_cnclient(gCmdStr, rwl_client_path, rwl_wifi_flag); + break; + case BCM_EAP_TYPE_TTLS: + S_N_PRINTF(gCmdStr,sizeof(gCmdStr),"%s sh cnClient -A %s -ssid %s -%s -%s -ttls-%s " + "-user %s -password %s -identity %s -validate %s -timeout %d %s ", rwl_client_path, + bso->eapObj.setEapTTLS.intf, bso->eapObj.setEapTTLS.ssid, + bso->eapObj.setEapTTLS.keyMgmtType, bso->eapObj.setEapTTLS.encrptype, TTLS_innerEAP, + bso->eapObj.setEapTTLS.username, bso->eapObj.setEapTTLS.passwd, + bso->eapObj.setEapTTLS.username, bso->eapObj.setEapTTLS.trustedRootCA, + BCM_8021X_ASSOC_TIMEOUT, "%"); + retVal = exec_process_cnclient(gCmdStr, rwl_client_path, rwl_wifi_flag); + break; + case BCM_EAP_TYPE_SIM: + S_N_PRINTF(gCmdStr,sizeof(gCmdStr),"%s sh cnClient -A %s -ssid %s -%s -%s -sim %s " + "-scpin %s -timeout %d %s ", rwl_client_path, bso->eapObj.setEapSIM.intf, + bso->eapObj.setEapSIM.ssid, bso->eapObj.setEapSIM.keyMgmtType, + bso->eapObj.setEapSIM.encrptype, bso->eapObj.setEapSIM.username, + bso->eapObj.setEapSIM.passwd, BCM_8021X_ASSOC_TIMEOUT, "%"); + retVal = exec_process_cnclient(gCmdStr, rwl_client_path, rwl_wifi_flag); + break; + case BCM_EAP_TYPE_PEAP: + S_N_PRINTF(gCmdStr,sizeof(gCmdStr),"%s sh cnClient -A %s -ssid %s -%s -%s -peap-%s " + "-user %s -password %s -identity %s -timeout %d %s ", rwl_client_path, + bso->eapObj.setEapPEAP.intf, bso->eapObj.setEapPEAP.ssid, + bso->eapObj.setEapPEAP.keyMgmtType, bso->eapObj.setEapPEAP.encrptype, + bso->eapObj.setEapPEAP.innerEAP, bso->eapObj.setEapPEAP.username, + bso->eapObj.setEapPEAP.passwd, bso->eapObj.setEapPEAP.username, + BCM_8021X_ASSOC_TIMEOUT, "%"); + retVal = exec_process_cnclient(gCmdStr, rwl_client_path, rwl_wifi_flag); + break; + case BCM_EAP_TYPE_FAST: + S_N_PRINTF(gCmdStr,sizeof(gCmdStr),"%s sh cnClient -A %s -ssid %s -%s -%s -fast-%s " + "-user %s -password %s -identity %s -validate %s -timeout %d %s ", rwl_client_path, + bso->eapObj.setEapFAST.intf, bso->eapObj.setEapFAST.ssid, + bso->eapObj.setEapFAST.keyMgmtType, bso->eapObj.setEapFAST.encrptype, + bso->eapObj.setEapFAST.innerEAP, bso->eapObj.setEapFAST.username, + bso->eapObj.setEapFAST.passwd, bso->eapObj.setEapFAST.username, + bso->eapObj.setEapFAST.trustedRootCA, BCM_8021X_ASSOC_TIMEOUT, "%"); + retVal = exec_process_cnclient(gCmdStr, rwl_client_path, rwl_wifi_flag); + break; + case BCM_EAP_TYPE_AKA: + S_N_PRINTF(gCmdStr,sizeof(gCmdStr),"%s sh cnClient -A %s -ssid %s -%s -%s -eap-aka " + "-user %s -password %s -identity %s -timeout %d %s ", rwl_client_path, + bso->eapObj.setEapAKA.intf, bso->eapObj.setEapAKA.ssid, + bso->eapObj.setEapAKA.keyMgmtType, bso->eapObj.setEapAKA.encrptype, + bso->eapObj.setEapAKA.username, bso->eapObj.setEapAKA.passwd, + bso->eapObj.setEapAKA.username,BCM_8021X_ASSOC_TIMEOUT, "%"); + retVal = exec_process_cnclient(gCmdStr, rwl_client_path, rwl_wifi_flag); + break; + default: + /* Run the commands in the batching mode in case of wifi transport*/ + if(rwl_wifi_flag) { + asd_sleep(1); + sprintf(gCmdStr, "%s seq_start", rwl_client_path); + exec_process(gCmdStr); + } + + + asd_sleep(1); + if ((!imode) && bso->channel){ + sprintf(gCmdStr, "%s channel %d", rwl_client_path, bso->channel); + exec_process(gCmdStr); + } + + sprintf(gCmdStr, "%s infra %d", rwl_client_path, imode); + exec_process(gCmdStr); + + /*Execute the command wme_apsd_sta only if the driver is down*/ + sprintf(gCmdStr, "%s wme_apsd_sta %d %d %d %d %d", rwl_client_path, + bso->maxSPLength, bso->acBE, bso->acBK, bso->acVI, bso->acVO); + exec_process(gCmdStr); + + asd_sleep(3); + sprintf(gCmdStr, "%s up", rwl_client_path); + exec_process(gCmdStr); + + if(rwl_wifi_flag) { + sprintf(gCmdStr, "%s seq_stop", rwl_client_path); + exec_process(gCmdStr); + } + + asd_sleep(2); + /* handle WEP keys */ + for(idx = 0; idx < 4; idx++) { + if(bso->keys[idx][0] != '\0') { + sprintf(gCmdStr, "%s addwep %d %s", rwl_client_path, idx, bso->keys[idx]); + } else { + sprintf(gCmdStr, "%s rmwep %d", rwl_client_path, idx); + } + exec_process(gCmdStr); + } + + /* set primary key */ + if(bso->primary_key != BCM_PRI_KEY_BAD) { + sprintf(gCmdStr, "%s primary_key %d", rwl_client_path, bso->primary_key); + exec_process(gCmdStr); + } + + /* security */ + sprintf(gCmdStr, "%s wsec %d", rwl_client_path, bso->wsec); + exec_process(gCmdStr); + + if(bso->passphrase[0] != '\0') { + sprintf(gCmdStr, "%s set_pmk %s", rwl_client_path, bso->passphrase); + exec_process(gCmdStr); + } + + if(bso->wpa_auth == BCM_WPA_AUTH_PSK) { + sprintf(gCmdStr, "%s sup_wpa 1", rwl_client_path ); + exec_process(gCmdStr); + } else if(bso->wpa_auth == BCM_WPA2_AUTH_PSK) { + sprintf(gCmdStr, "%s sup_wpa 2", rwl_client_path ); + exec_process(gCmdStr); + } + + sprintf(gCmdStr, "%s auth %d", rwl_client_path, bso->auth); + exec_process(gCmdStr); + + sprintf(gCmdStr, "%s wpa_auth %d", rwl_client_path, bso->wpa_auth); + exec_process(gCmdStr); + + sprintf(gCmdStr, "%s ssid %s", rwl_client_path, ssidTarget); + exec_process(gCmdStr); + } +/* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ +exit: + /* End: Modified as per BRCM 1.3 ASD */ + + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + if(retVal == TRUE) + staAssocResp->status = STATUS_COMPLETE; + else + staAssocResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_ASSOCIATE_RESP_TLV, 4, (BYTE *)staAssocResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return retVal; /* Modified as per BRCM 1.3 ASD */ +} + +/* + * wfaStaReAssociate(): + * The function is to force the station wireless I/F to re/associate + * with the AP. + */ +int wfaStaReAssociate(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCommand_t *assoc = (dutCommand_t *)caCmdBuf; + dutCmdResponse_t *staAssocResp = &gGenericResp; + + DPRINT_INFO(WFA_OUT, "entering wfaStaAssociate ...\n"); + sprintf(gCmdStr, "%s mpc 0", rwl_client_path); + exec_process(gCmdStr); + sprintf(gCmdStr, "%s up", rwl_client_path); + exec_process(gCmdStr); + /* "wl reassoc" command is not able to associate completly and receives an Auto IP */ + sprintf(gCmdStr, "%s reassoc %s", rwl_client_path, assoc->cmdsu.bssid); + exec_process(gCmdStr); + + staAssocResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_ASSOCIATE_RESP_TLV, 4, (BYTE *)staAssocResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* +* wfaStaGetIpConfig(): +* This function is to retriev the ip info including +* 1. dhcp enable +* 2. ip address +* 3. mask +* 4. primary-dns +* 5. secondary-dns +* +* The current implementation is to use a script to find these information +* and store them in a file. +*/ + +int wfaStaGetIpConfig(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int i = 0; +#ifdef WIN32 + int slen; + DWORD dwStatus; + IP_ADAPTER_INFO AdapterInfo[16]; // Allocate information for up to 16 NICs + PIP_ADAPTER_INFO pAdapterInfo; + DWORD dwBufLen = sizeof(AdapterInfo); // Save the memory size of buffer +#endif + + dutCommand_t *getIpConf = (dutCommand_t *)caCmdBuf; + dutCmdResponse_t *ipconfigResp = &gGenericResp; + char *ifname = getIpConf->intf; + caStaGetIpConfigResp_t *ifinfo = &ipconfigResp->cmdru.getIfconfig; +#ifndef WIN32 + FILE *shell_fpt; + DPRINT_INFO(WFA_OUT,"Entering staGetIpConfig...\n"); + /* Start: Modified as per BRCM 1.3 ASD */ + /* Dhcp */ + sprintf(gCmdStr,"ps ax | grep -v grep | grep dhcli | wc -l >%s 2>&1", TMP_FILE_PATH); + + system(gCmdStr); + + shell_fpt = fopen(TMP_FILE_PATH, "rb"); + fread(gCmdStr, sizeof(char), 20, shell_fpt); + fclose(shell_fpt); + + remove(TMP_FILE_PATH); + if (atoi(gCmdStr) >= 1) + ifinfo->isDhcp = 1; + else + ifinfo->isDhcp = 0; + /* ipaddr */ + sprintf(gCmdStr, "%s %s | grep 'inet addr' | cut -d: -f2 | cut -d' ' -f1>%s 2>&1", + IFCONFIG_PATH, ifname, TMP_FILE_PATH); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + + system(gCmdStr); + + shell_fpt = fopen(TMP_FILE_PATH, "rb"); + ifinfo->ipaddr[0] = 0; + fread(ifinfo->ipaddr, sizeof(char), 20, shell_fpt); + ifinfo->ipaddr[strlen(ifinfo->ipaddr) - 1] = 0; /* Purge newline */ + if(ifinfo->ipaddr[0] == 0) + strncpy(ifinfo->ipaddr, "none", 15); + fclose(shell_fpt); + + remove(TMP_FILE_PATH); + /* mask */ + sprintf(gCmdStr, "%s %s | grep 'inet addr' | cut -d: -f4 >%s 2>&1", + IFCONFIG_PATH, ifname, TMP_FILE_PATH); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + + system(gCmdStr); + + shell_fpt = fopen(TMP_FILE_PATH, "rb"); + ifinfo->mask[0] = 0; + fread(ifinfo->mask, sizeof(char), 20, shell_fpt); + ifinfo->mask[strlen(ifinfo->mask) - 1] = 0; /* Purge newline */ + if(ifinfo->mask[0] == 0) + strcpy(ifinfo->mask, "none"); + fclose(shell_fpt); + + remove(TMP_FILE_PATH); + /* dns */ + sprintf(gCmdStr, "cat /etc/resolv.conf | grep nameserver | awk '{print $2}'>%s 2>&1", TMP_FILE_PATH); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + + system(gCmdStr); + + shell_fpt = fopen(TMP_FILE_PATH, "rb"); + for (i = 0; i < WFA_MAX_DNS_NUM; i++){ + fgets(ifinfo->dns[i], WFA_IP_ADDR_STR_LEN, shell_fpt); + if (ifinfo->dns[i][0]) + ifinfo->dns[i][strlen(ifinfo->dns[i]) - 1] = 0; /* Purge newline */ + else + strcpy(ifinfo->dns[i], "NOTDEF"); + } + + fclose(shell_fpt); + + remove(TMP_FILE_PATH); + /* End: Modified as per BRCM 1.3 ASD */ + +#else + /* The eth1 interface name in WinCE is BCMSDDHD1 and + * the eth0 interface name is VMINI1. The command that comes in from Linux CA + * will send the eth0 or eth1 interface, which is then translated to WinCE + * specific interface name to get the Adapters information*/ + if(!strcmp(getIpConf->intf, "eth1")) { + strcpy(getIpConf->intf , "BCMSDDHD1"); + } else if(!strcmp(getIpConf->intf, "eth0")) { + strcpy(getIpConf->intf , "VMINI1"); + } + /* Get the network interface information */ + dwStatus = GetAdaptersInfo(// Call GetAdapterInfo + AdapterInfo,// [out] buffer to receive data + &dwBufLen);// [in] size of receive data buffer + + pAdapterInfo= AdapterInfo;// Contains pointer to current adapter info + + while(pAdapterInfo){ + if(strcmp(pAdapterInfo->AdapterName, getIpConf->intf)==0){ + /*Check if DHCP Enabled*/ + if(pAdapterInfo->DhcpEnabled) + ifinfo->isDhcp = 1; + else + ifinfo->isDhcp = 0; + + /*IP Address */ + strcpy(ifinfo->ipaddr, pAdapterInfo->IpAddressList.IpAddress.String); + ifinfo->ipaddr[15]='\0'; + + /*Subnet mask*/ + strcpy(ifinfo->mask,pAdapterInfo->IpAddressList.IpMask.String); + slen = strlen(ifinfo->mask); + ifinfo->mask[slen+1] = '\0'; + + /*Primary DNS*/ + strcpy(ifinfo->dns[0], pAdapterInfo->PrimaryWinsServer.IpAddress.String); + slen = strlen(ifinfo->dns[0]); + + /*Secondary DNS*/ + strcpy(ifinfo->dns[1], pAdapterInfo->SecondaryWinsServer.IpAddress.String); + slen = strlen(ifinfo->dns[1]); + } + pAdapterInfo = pAdapterInfo->Next; + } +#endif + /* + * Report back the results + */ + ipconfigResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_GET_IP_CONFIG_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)ipconfigResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + DPRINT_INFO(WFA_OUT, "%i %i %s %s %s %s %i\n", ipconfigResp->status, + ifinfo->isDhcp, ifinfo->ipaddr, ifinfo->mask, + ifinfo->dns[0], ifinfo->dns[1], *respLen); + return TRUE; +} + +/* +* wfaStaSetIpConfig(): +* The function is to set the ip configuration to a wireless I/F. +* 1. IP address +* 2. Mac address +* 3. default gateway +* 4. dns nameserver (pri and sec). +* +* Set the IP address and the mask value only if the the DHCP(ipconfig->isDhcp) +* is disabled. Otherwise enable the DHCP for the network interface. +*/ +int wfaStaSetIpConfig(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCommand_t *setIpConf = (dutCommand_t *)caCmdBuf; + caStaSetIpConfig_t *ipconfig = &setIpConf->cmdsu.ipconfig; + dutCmdResponse_t *staSetIpResp = &gGenericResp; + +#ifndef WIN32 + pid_t pid; + int status; + DPRINT_INFO(WFA_OUT, "interface = %s, ipaddr = %s, dhcp = %d\r\n",ipconfig->intf,ipconfig->ipaddr,ipconfig->isDhcp); + /* Start: Modified as per BRCM 1.3 ASD */ + if(!ipconfig->isDhcp) + { + if (!strlen(ipconfig->intf) || !strlen(ipconfig->ipaddr) || !strlen(ipconfig->mask)) + { + staSetIpResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_IP_CONFIG_RESP_TLV, 4, (BYTE *)staSetIpResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; /* changed to be FALSE? */ + } + sprintf(gCmdStr, "killall -9 dhclient"); + exec_process(gCmdStr); + sprintf(gCmdStr, "%s %s %s ", IFCONFIG_PATH, ipconfig->intf, ipconfig->ipaddr); + if (strlen(ipconfig->mask)) + sprintf(&gCmdStr[strlen(gCmdStr)], "netmask %s ", ipconfig->mask); + exec_process(gCmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", "doing ifconfig"); + /* End: Modified as per BRCM 1.3 ASD */ + + /* use command 'route add' to set set gatewway (linux specific) */ + if(ipconfig->defGateway[0] != '\0') + { + sprintf(gCmdStr, "%s add default gw %s > /dev/null 2>&1", ROUTE_PATH, ipconfig->defGateway); + exec_process(gCmdStr); + DPRINT_INFO(WFA_OUT, "%s\n", "doing route add"); + } + + /* set dns (linux specific) */ + + /* Start: Modified as per BRCM 1.3 ASD */ + /* if somedata is given as primary-dns then we'll display it + else we'll show it as NOTDEF */ + if(strcmp(ipconfig->pri_dns, "\0")) + { + /* set dns (linux specific) */ + sprintf(gCmdStr, "cp /etc/resolv.conf /tmp/resolv.conf.bk"); + exec_process(gCmdStr); + sprintf(gCmdStr, "echo nameserver %s > /etc/resolv.conf", ipconfig->pri_dns); + exec_process(gCmdStr); + /* if no secondary-dns is given along with primary-dns + then we'll have to show it as NOTDEF */ + if(strcmp(ipconfig->sec_dns, "\0")) + sprintf(gCmdStr, "echo nameserver %s >> /etc/resolv.conf", ipconfig->sec_dns); + else + sprintf(gCmdStr, "echo nameserver %s >> /etc/resolv.conf", "NOTDEF"); + exec_process(gCmdStr); + } + /* In case,no primary or secondary dns is given,it will print them as + NOTDEF */ + else + { + + sprintf(gCmdStr, "cp /etc/resolv.conf /tmp/resolv.conf.bk"); + exec_process(gCmdStr); + sprintf(gCmdStr, "echo nameserver %s > /etc/resolv.conf", "NOTDEF"); + exec_process(gCmdStr); + sprintf(gCmdStr, "echo nameserver %s >> /etc/resolv.conf", "NOTDEF"); + exec_process(gCmdStr); + } + } + else + { + /* dhcp is enabled */ + sprintf(gCmdStr, "killall -9 dhclient"); + exec_process(gCmdStr); + /* Wait for couple of seconds for dhclient to exit cleanly */ + asd_sleep(2); + if((pid = fork()) == 0) + { + close(gagtSockfd); + close(g_serv_sock_desc); + sprintf(gCmdStr, "%s %s",DHCLIENT_PATH, ipconfig->intf); + /* execl("/sbin/dhclient",gCmdStr,NULL);*/ + exec_process(gCmdStr); + _exit(0); + } + wait(&status); + } + /* End: Modified as per BRCM 1.3 ASD */ +#endif + + /* + * report status + */ + staSetIpResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_IP_CONFIG_RESP_TLV, 4, (BYTE *)staSetIpResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* +* wfaStaVerifyIpConnection(): +* The function is to verify if the station has IP connection with an AP by +* send ICMP/pings to the AP. +*/ + +int wfaStaVerifyIpConnection(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCommand_t *verip = (dutCommand_t *)caCmdBuf; + dutCmdResponse_t *verifyIpResp = &gGenericResp; + + +#ifdef WIN32 + char tempip[30]; +#else + char *tempip; + FILE *shell_fpt; +#endif + +#ifndef WFA_PING_UDP_ECHO_ONLY + + DPRINT_INFO(WFA_OUT, "Entering wfaStaVerifyIpConnection ...\n"); +#ifndef WIN32 + tempip = (char*)malloc(30); +#endif + /* set timeout value in case not set */ + if(verip->cmdsu.verifyIp.timeout <= 0) + { + verip->cmdsu.verifyIp.timeout = 10; + } + + if (strlen(verip->cmdsu.verifyIp.dipaddr) == 0 ) + { + verifyIpResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV, 4, (BYTE *)&verifyIpResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + DPRINT_ERR(WFA_ERR, "Could not execute %s\n", gCmdStr); + return FALSE; + } + + strcpy(tempip,verip->cmdsu.verifyIp.dipaddr); + + strtok(tempip,". "); + strtok(tempip,". "); + strtok(tempip,". "); + strtok(tempip,". "); + + if( atoi(tempip) >= 255 ) + { + verifyIpResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV, 4, (BYTE *)&verifyIpResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + +#ifndef WIN32 + /* Start: Modified as per BRCM 1.3 ASD */ + /* execute the ping command and pipe the result to a tmp file */ + memset(gCmdStr, 0, sizeof(gCmdStr)); + sprintf(gCmdStr, "%s -c 3 -q %s >>%s", PING_PATH, verip->cmdsu.verifyIp.dipaddr, PINGOUT_FILE_PATH); + exec_process(gCmdStr); + + asd_sleep(1); + verifyIpResp->status = STATUS_COMPLETE; + sprintf(gCmdStr, "cat %s | grep transmitted | awk '{print $4}'>%s 2>&1", + PINGOUT_FILE_PATH, TMP_FILE_PATH); + + if (system(gCmdStr) < 0) { + DPRINT_ERR(WFA_ERR, "\n Not able to execute verify ip cmd\n"); + verifyIpResp->cmdru.connected = 0; + } + + + shell_fpt = fopen(TMP_FILE_PATH, "rb"); + + if (shell_fpt == NULL) { + DPRINT_ERR(WFA_ERR, "\nShell Cmd:File open error\n"); + verifyIpResp->cmdru.connected = 0; + } + + fread(gCmdStr, sizeof(char), 20, shell_fpt); + fclose(shell_fpt); + + remove(TMP_FILE_PATH); + remove(PINGOUT_FILE_PATH); + if(atoi(gCmdStr) == 0) + verifyIpResp->cmdru.connected = 0; + else + verifyIpResp->cmdru.connected = 1; + + printf("\ngCmdStr is:%s\n", gCmdStr); +#ifdef DEBUG + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); +#endif + /* End: Modified as per BRCM 1.3 ASD */ +#else +#endif + +#else + int btSockfd; + struct pollfd fds[2]; + int timeout = 2000; + char anyBuf[64]; + struct sockaddr_in toAddr; + int done = 1, cnt = 0, ret, nbytes; + + verifyIpResp->status = STATUS_COMPLETE; + verifyIpResp->cmdru.connected = 0; + + btSockfd = wfaCreateUDPSock("127.0.0.1", WFA_UDP_ECHO_PORT); + + if(btSockfd == -1) + { + verifyIpResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV, 4, (BYTE *)verifyIpResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return FALSE; + } + + toAddr.sin_family = AF_INET; + toAddr.sin_addr.s_addr = inet_addr(verip->cmdsu.verifyIp.dipaddr); + toAddr.sin_port = htons(WFA_UDP_ECHO_PORT); + + while(done) + { + wfaTrafficSendTo(btSockfd, (char *)anyBuf, 64, (struct sockaddr *)&toAddr); + cnt++; + + fds[0].fd = btSockfd; + fds[0].events = POLLIN | POLLOUT; + + ret = poll(fds, 1, timeout); + switch(ret) + { + case 0: + /* it is time out, count a packet lost*/ + break; + case -1: + /* it is an error */ + default: + { + switch(fds[0].revents) + { + case POLLIN: + case POLLPRI: + case POLLOUT: + nbytes = wfaTrafficRecv(btSockfd, (char *)anyBuf, (struct sockaddr *)&toAddr); + if(nbytes != 0) + verifyIpResp->cmdru.connected = 1; + done = 0; + break; + default: + /* errors but not care */ + ; + } + } + } + if(cnt == 3) + { + done = 0; + } + } +#endif + + wfaEncodeTLV(WFA_STA_VERIFY_IP_CONNECTION_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)verifyIpResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return TRUE; +} + +/* +* wfaSetEncryption(): +* The function is to set the wireless interface with WEP or none. +* Input parameters: +* 1. I/F +* 2. ssid +* 3. encpType - wep or none +* Optional: +* 4. key1 +* 5. key2 +* 6. key3 +* 7. key4 +* 8. activeKey Index +*/ + +int wfaSetEncryption(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetEncryption_t *setEncryp = (caStaSetEncryption_t *)caCmdBuf; + dutCmdResponse_t *setEncrypResp = &gGenericResp; + int idx; /* Modified as per BRCM 1.3 ASD */ + /* Start: Modified as per BRCM 1.3 ASD */ + int retVal = TRUE; + bcmSsidObj_t *bso; + char * ssidStr; + + DPRINT_INFO(WFA_OUT, "wfaSetEncryption()\n"); + + /* Save the settings for when we need them */ + + ssidStr = setEncryp->ssid; + + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + /* set Key management to NONE (NO WPA) for plaintext or WEP */ + bso->wpa_auth = BCM_WPA_AUTH_DISABLED; + + for(idx = 0; idx < 4; idx++) { + if(setEncryp->keys[idx][0] != '\0') { + strcpy(bso->keys[idx], setEncryp->keys[idx]); + } else { + memset(bso->keys[idx],0,BCM_WEP_KEY_SIZE_MAX); + } + } + + if ((setEncryp->activeKeyIdx > 0) && (setEncryp->activeKeyIdx < 5)) { + /* move the index range from (1 to 4) to (0 to 3) */ + bso->primary_key = setEncryp->activeKeyIdx - 1; + } + + bso->wsec = (!setEncryp->encpType) ? 0 : 1; + + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + +exit: + /* End: Modified as per BRCM 1.3 ASD */ + + setEncrypResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_ENCRYPTION_RESP_TLV, 4, (BYTE *)setEncrypResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return retVal; /* Modified as per BRCM 1.3 ASD */ +} + + +int wfaSetEncryption1(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetEncryption_t *setEncryp = (caStaSetEncryption_t *)caCmdBuf; + dutCmdResponse_t *setEncrypResp = &gGenericResp; + int idx; + /* Start: Modified as per BRCM 1.3 ASD */ + int retVal = TRUE; + bcmSsidObj_t *bso; + char * ssidStr; + + DPRINT_INFO(WFA_OUT, "wfaSetEncryption1()\n"); + + /* Save the settings for when we need them */ + + ssidStr = setEncryp->ssid; + /* SetSSID */ + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + /* set Key management to NONE (NO WPA) for plaintext or WEP */ + bso->wpa_auth = BCM_WPA_AUTH_DISABLED; + + for(idx = 0; idx < 4; idx++) { + if(setEncryp->keys[idx][0] != '\0') { + strcpy(bso->keys[idx], setEncryp->keys[idx]); + } else { + memset(bso->keys[idx], 0, BCM_WEP_KEY_SIZE_MAX); + } + } + + if ((setEncryp->activeKeyIdx > 0) && (setEncryp->activeKeyIdx < 5)) { + /* move the index range from (1 to 4) to (0 to 3) */ + bso->primary_key = setEncryp->activeKeyIdx - 1; + } + + bso->wsec = (!setEncryp->encpType) ? 0 : 1; + + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + +exit: + /* End: Modified as per BRCM 1.3 ASD */ + + setEncrypResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_ENCRYPTION_RESP_TLV, 4, (BYTE *)setEncrypResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return retVal; /* Modified as per BRCM 1.3 ASD */ +} + + +/* +* wfaStaSetEapTLS(): +* This is to set +* 1. ssid +* 2. encrypType - tkip or aes-ccmp +* 3. keyManagementType - wpa or wpa2 +* 4. trustedRootCA +* 5. clientCertificate +*/ +int wfaStaSetEapTLS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetEapTLS_t *setTLS = (caStaSetEapTLS_t *)caCmdBuf; + dutCmdResponse_t *setEapTlsResp = &gGenericResp; + bcmSsidObj_t *bso; + char ssidTarget[WFA_SSID_NAME_LEN]; + + DPRINT_INFO(WFA_OUT, "Entering wfaStaSetEapTLS ...\n"); + + memcpy(ssidTarget, setTLS->ssid, WFA_SSID_NAME_LEN); + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + return FALSE; + } + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + } + memcpy(&(bso->eapObj.setEapTLS), setTLS, sizeof(caStaSetEapTLS_t)); + bso->eapType = BCM_EAP_TYPE_TLS; + + if(strstr(bso->eapObj.setEapTLS.encrptype,"aes-ccmp")) + strncpy(bso->eapObj.setEapTLS.encrptype, AES_ENCPTYPE, AES_LEN) ; + setEapTlsResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_EAPTLS_RESP_TLV, 4, (BYTE *)setEapTlsResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; +} + +/* +* The function is to set +* 1. ssid +* 2. passPhrase +* 3. keyMangementType - wpa/wpa2 +* 4. encrypType - tkip or aes-ccmp +*/ + +int wfaStaSetPSK(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetPSK_t *setPSK = (caStaSetPSK_t *)caCmdBuf; + dutCmdResponse_t *setPskResp = &gGenericResp; + + /* Start: Modified as per BRCM 1.3 ASD */ + int retVal = TRUE; + bcmSsidObj_t *bso; + char *ssidStr; + + DPRINT_INFO(WFA_OUT, "wfaStaSetPSK()"); + + ssidStr = setPSK->ssid; + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + if (!strcmp(setPSK->keyMgmtType, "wpa")) { + bso->wpa_auth = BCM_WPA_AUTH_PSK; /* WPA-PSK/WPA-Personal */ + } else if (!strcmp(setPSK->keyMgmtType, "wpa2")) { + bso->wpa_auth = BCM_WPA2_AUTH_PSK; /* WPA2-PSK/WPA2-Personal */ + } else { + DPRINT_ERR(WFA_OUT, "invalid key_mgmt %s", setPSK->keyMgmtType); + retVal = FALSE; + goto exit; + } + + DPRINT_INFO(WFA_OUT, "wpa_auth %d\n", bso->wpa_auth); + + if (setPSK->encpType == ENCRYPT_TKIP) { + bso->wsec = 3; + } else if (setPSK->encpType == ENCRYPT_AESCCMP) { + bso->wsec = 7; + } else { + DPRINT_ERR(WFA_OUT, "invalid encpType %d", setPSK->encpType); + goto exit; + } + DPRINT_INFO(WFA_OUT, "encpType %d wsec %d\n", setPSK->encpType, bso->wsec); + + + strncpy((char *)bso->passphrase, (char *)setPSK->passphrase, 64); + bso->auth = 0; + + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + retVal = TRUE; + +exit: + /* End: Modified as per BRCM 1.3 ASD */ + + setPskResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_PSK_RESP_TLV, 4, (BYTE *)setPskResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return retVal; /* Modified as per BRCM 1.3 ASD */ +} + + +/* +* wfaStaGetInfo(): +* Get vendor specific information in name/value pair by a wireless I/F. +*/ +int wfaStaGetInfo(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t infoResp; + dutCommand_t *getInfo = (dutCommand_t *)caCmdBuf; + FILE *tmpfd; + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetInfo.....\n"); + /* + * Normally this is called to retrieve the vendor information + * from a interface, no implement yet + */ +#ifndef WIN32 + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s nmode &> %s", rwl_client_path, TEMP_FILE_PATH); +#else + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s nmode > %s 2>&1", rwl_client_path, TEMP_FILE_PATH); +#endif + exec_process(gCmdStr); + if((tmpfd = fopen(TEMP_FILE_PATH, "r")) == NULL){ + infoResp.status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_GET_INFO_RESP_TLV, 4, (BYTE *)&infoResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + fgets(gCmdStr, sizeof(gCmdStr), tmpfd); + Cleanup_File(tmpfd); +/* + * If it is n mode supported card then it wont reply Unsupported or error + */ + if (((strstr(gCmdStr, "Unsupported")) != NULL) || + ((strstr(gCmdStr, "error")) != NULL)) { + S_N_PRINTF(infoResp.cmdru.info, sizeof(infoResp.cmdru.info), "interface,%s,vendor,Broadcom,cardtype,802.11a/b/g", getInfo->intf); + } + else { + S_N_PRINTF(infoResp.cmdru.info, sizeof(infoResp.cmdru.info), "interface,%s,vendor,Broadcom,cardtype,802.11a/b/g/n", getInfo->intf); + } + infoResp.status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_GET_INFO_RESP_TLV, sizeof(infoResp), (BYTE *)&infoResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(infoResp); + return TRUE; +} + +int wfaStaGetTestData(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + // dutCmdResponse_t dataResp; + // dutCommand_t *testData = (dutCommand_t *)caCmdBuf; + + /* + * This is to trasfer the test log (file) back to console + * It has not decided to use in-band or out of band. Will be updated + * in a new release soon. + */ + + return TRUE; +} + +/* +* wfaStaSetEapTTLS(): +* This is to set +* 1. ssid +* 2. username +* 3. passwd +* 4. encrypType - tkip or aes-ccmp +* 5. keyManagementType - wpa or wpa2 +* 6. trustedRootCA +*/ +int wfaStaSetEapTTLS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + + caStaSetEapTTLS_t *setTTLS = (caStaSetEapTTLS_t *)caCmdBuf; + dutCmdResponse_t *setEapTtlsResp = &gGenericResp; + bcmSsidObj_t *bso; + char ssidTarget[WFA_SSID_NAME_LEN]; + + memcpy(ssidTarget, setTTLS->ssid, WFA_SSID_NAME_LEN); + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + return FALSE; + + } + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + } + + memcpy(&(bso->eapObj.setEapTTLS), setTTLS, sizeof(caStaSetEapTTLS_t)); + bso->eapType = BCM_EAP_TYPE_TTLS; + + if(strstr(bso->eapObj.setEapTTLS.encrptype,"aes-ccmp")) + strncpy(bso->eapObj.setEapTTLS.encrptype, AES_ENCPTYPE, AES_LEN) ; + setEapTtlsResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_EAPTTLS_RESP_TLV, 4, (BYTE *)setEapTtlsResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* +* wfaStaSetEapSIM(): +* This is to set +* 1. ssid +* 2. user name +* 3. passwd +* 4. encrypType - tkip or aes-ccmp +* 5. keyMangementType - wpa or wpa2 +*/ +int wfaStaSetEapSIM(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetEapSIM_t *setSIM = (caStaSetEapSIM_t *)caCmdBuf; + dutCmdResponse_t *setEapSimResp = &gGenericResp; + bcmSsidObj_t *bso; + char ssidTarget[WFA_SSID_NAME_LEN]; + + memcpy(ssidTarget, setSIM->ssid, WFA_SSID_NAME_LEN); + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + return FALSE; + } + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + } + + memcpy(&(bso->eapObj.setEapSIM), setSIM, sizeof(caStaSetEapSIM_t)); + bso->eapType = BCM_EAP_TYPE_SIM; + + if(strstr(bso->eapObj.setEapSIM.encrptype,"aes-ccmp")) + strncpy(bso->eapObj.setEapSIM.encrptype, AES_ENCPTYPE, AES_LEN) ; + setEapSimResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_EAPSIM_RESP_TLV, 4, (BYTE *)setEapSimResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* +* wfaStaSetPEAP() +* This is to set +* 1. ssid +* 2. user name +* 3. passwd +* 4. encryType - tkip or aes-ccmp +* 5. keyMgmtType - wpa or wpa2 +* 6. trustedRootCA +* 7. innerEAP +* 8. peapVersion +*/ +int wfaStaSetPEAP(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetEapPEAP_t *setPEAP = (caStaSetEapPEAP_t *)caCmdBuf; + dutCmdResponse_t *setPeapResp = &gGenericResp; + bcmSsidObj_t *bso; + char ssidTarget[WFA_SSID_NAME_LEN]; + + memcpy(ssidTarget, setPEAP->ssid, WFA_SSID_NAME_LEN); + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + return FALSE; + } + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + } + + memcpy(&(bso->eapObj.setEapPEAP), setPEAP, sizeof(caStaSetEapPEAP_t)); + bso->eapType = BCM_EAP_TYPE_PEAP; + + if(strstr(bso->eapObj.setEapPEAP.encrptype,"aes-ccmp")) + strncpy(bso->eapObj.setEapPEAP.encrptype, AES_ENCPTYPE, AES_LEN) ; + setPeapResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_PEAP_RESP_TLV, 4, (BYTE *)setPeapResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* +* wfaStaSetUAPSD() +* This is to set +* 1. maxSPLength - 0,1,2,or 4 +* 2. acBE +* 3. acBK +* 4. acVI +* 5. acVO +*/ +int wfaStaSetUAPSD(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int retVal = TRUE; + caStaSetUAPSD_t *setUAPSD = (caStaSetUAPSD_t *)caCmdBuf; + /* char *ifname = setUAPSD->intf; */ /* Removed as per BRCM 1.3 ASD */ + dutCmdResponse_t *setUAPSDResp = &gGenericResp; + /* Start: Modified as per BRCM 1.3 ASD */ + bcmSsidObj_t *bso; + char *ssidStr; + + DPRINT_INFO(WFA_OUT, "Entering StaSetUAPSD ...\n"); + DPRINT_INFO(WFA_OUT, "maxSPLength %d acBE %d acBK %d acVI %d acVO %d\n", + setUAPSD->maxSPLength, setUAPSD->acBE, setUAPSD->acBK, setUAPSD->acVI, setUAPSD->acVO); + + ssidStr = setUAPSD->ssid; + + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + if (rwl_wifi_flag) { + /* Use the batching mode */ + asd_sleep(1); + sprintf (gCmdStr,"%s seq_start",rwl_client_path); + exec_process (gCmdStr); + } + + /* Get the driver down */ + sprintf (gCmdStr,"%s down",rwl_client_path); + exec_process (gCmdStr); + bso->maxSPLength = setUAPSD->maxSPLength; + bso->acBE = setUAPSD->acBE; + bso->acBK = setUAPSD->acBK; + bso->acVI = setUAPSD->acVI; + bso->acVO = setUAPSD->acVO; + + sprintf(gCmdStr,"%s wme_apsd_sta %d %d %d %d %d",rwl_client_path, + bso->maxSPLength,bso->acBE,bso->acBK,bso->acVI,bso->acVO); + exec_process(gCmdStr); + /* Get the driver up*/ + sprintf (gCmdStr,"%s up",rwl_client_path); + exec_process (gCmdStr); + + sleep (1); + /* Setting up ssid */ + sprintf (gCmdStr,"%s join %s",rwl_client_path,setUAPSD->ssid); + exec_process(gCmdStr); + + if (rwl_wifi_flag) { + /* End the batching sequence */ + asd_sleep(1); + sprintf (gCmdStr,"%s seq_stop",rwl_client_path); + exec_process (gCmdStr); + } + +exit: + /* End: Modified as per BRCM 1.3 ASD */ + setUAPSDResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_UAPSD_RESP_TLV, 4, (BYTE *)setUAPSDResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return retVal; /* Modified as per BRCM 1.3 ASD */ +} + + +/* +* This funciton is to retrieve a list of interfaces and return +* the list back to Agent control. +* +*/ +int wfaDeviceListIF(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t *infoResp = &gGenericResp; + dutCommand_t *ifList = (dutCommand_t *)caCmdBuf; + caDeviceListIFResp_t *ifListResp = &infoResp->cmdru.ifList; +#ifndef WIN32 + char adapter [10]; +#endif + DPRINT_INFO(WFA_OUT, "Entering wfaDeviceListIF ...\n"); + + switch(ifList->cmdsu.iftype) + { + case IF_80211: + infoResp->status = STATUS_COMPLETE; + ifListResp->iftype = IF_80211; + /*In case of the WinCE the wireless interface is BCMSDDHD1*/ +#ifndef WIN32 + GetWirelessAdapter(adapter); + + strcpy(ifListResp->ifs[0], adapter); +#else + strcpy(ifListResp->ifs[0], "BCMSDDHD1"); +#endif + strcpy(ifListResp->ifs[1], "NULL"); + strcpy(ifListResp->ifs[2], "NULL"); + break; + + case IF_ETH: + infoResp->status = STATUS_COMPLETE; + ifListResp->iftype = IF_ETH; + /*In case of the WinCE the ethernet interface is VMINI1*/ +#ifndef WIN32 + strcpy(ifListResp->ifs[1], "eth0 "); +#else + strcpy(ifListResp->ifs[1], "VMINI1"); +#endif + strcpy(ifListResp->ifs[1], "NULL"); + strcpy(ifListResp->ifs[2], "NULL"); + break; + default: + { + infoResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_DEVICE_LIST_IF_RESP_TLV, 4, (BYTE *)infoResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + } + + wfaEncodeTLV(WFA_DEVICE_LIST_IF_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)infoResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return TRUE; +} + +int wfaStaDebugSet(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t *debugResp = &gGenericResp; + dutCommand_t *debugSet = (dutCommand_t *)caCmdBuf; + + DPRINT_INFO(WFA_OUT, "Entering wfaStaDebugSet ...\n"); + + if(debugSet->cmdsu.dbg.state == 1) /* enable */ + wfa_defined_debug |= debugSet->cmdsu.dbg.level; + else + wfa_defined_debug = (~debugSet->cmdsu.dbg.level & wfa_defined_debug); + + debugResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_GET_INFO_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)debugResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return TRUE; +} + + + +/* +* wfaStaSetIBSS() +* This is to set +* 1. ssid +* 2. channel +* 3. encrypType - none or wep +* optional +* 4. key1 +* 5. key2 +* 6. key3 +* 7. key4 +* 8. activeIndex - 1, 2, 3, or 4 +*/ +int wfaStaSetIBSS(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetIBSS_t *setIBSS = (caStaSetIBSS_t *)caCmdBuf; + dutCmdResponse_t *setIbssResp = &gGenericResp; + + /* Start: Modified as per BRCM 1.3 ASD */ + int retVal = TRUE; + bcmSsidObj_t *bso; + int idx; + char *ssidStr; + + DPRINT_INFO(WFA_OUT, "wfaStaSetIBSS()\n"); + + /* Save the settings for when we need them */ + + ssidStr = setIBSS->ssid; + + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + } + + bso->bssType = BCM_BSS_INDEPENDENT; + + if (setIBSS->channel) { + bso->channel = setIBSS->channel; + } + + bso->wsec = (!setIBSS->encpType) ? 0 : 1; + + for(idx = 0; idx < 4; idx++) { + if(setIBSS->keys[idx][0] != '\0') { + strcpy(bso->keys[idx], setIBSS->keys[idx]); + } else { + memset(bso->keys[idx],0, BCM_WEP_KEY_SIZE_MAX); + } + } + + if ((setIBSS->activeKeyIdx > 0) && (setIBSS->activeKeyIdx < 5)) { + /* move the index range from (1 to 4) to (0 to 3) */ + bso->primary_key = setIBSS->activeKeyIdx - 1; + } + + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } +exit: + /* End: Modified as per BRCM 1.3 ASD */ + + setIbssResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_IBSS_RESP_TLV, 4, (BYTE *)setIbssResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return retVal; /* Modified as per BRCM 1.3 ASD */ +} + +/* +* wfaSetMode(): +* The function is to set the wireless interface with a given mode (possible +* adhoc) +* Input parameters: +* 1. I/F +* 2. ssid +* 3. mode adhoc or managed +* 4. encType +* 5. channel +* 6. key(s) +* 7. active key +*/ +int wfaStaSetMode(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetMode_t *setmode = (caStaSetMode_t *)caCmdBuf; + dutCmdResponse_t *SetModeResp = &gGenericResp; + int i; + bcmSsidObj_t *bso; + char *ssidStr; + int retVal = TRUE; + + DPRINT_INFO(WFA_OUT,"Entering wfaStaSetMode\r\n"); + + ssidStr = setmode->ssid; + if (!(bso = bcmWfaSsidTblSsidFind(ssidStr))) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidStr))) { + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed.\n", ssidStr); + retVal = FALSE; + goto exit; + } + else + { + //DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd added: (%s)\n", ssidStr); + } + } + + if (setmode->channel) { + bso->channel = setmode->channel; + /* Set the channel */ + sprintf(gCmdStr, "%s channel %d",rwl_client_path, setmode->channel); + exec_process(gCmdStr); + } + + /* destroy the interface */ + sprintf(gCmdStr, "%s disassoc", rwl_client_path); + exec_process(gCmdStr); + + /* re-create the interface in the given mode */ + if(setmode->mode) + { + bso->bssType = BCM_BSS_INDEPENDENT; + sprintf(gCmdStr, "%s infra %d", rwl_client_path, setmode->mode); + exec_process(gCmdStr); + sprintf(gCmdStr, "%s join %s imode ibss", rwl_client_path, setmode->ssid); + exec_process(gCmdStr); + } + else + { + sprintf(gCmdStr, "%s infra %d", rwl_client_path, setmode->mode); + exec_process(gCmdStr); + sprintf(gCmdStr, "%s join %s", rwl_client_path, setmode->ssid); + exec_process(gCmdStr); + } + bso->wsec = (!setmode->encpType) ? 0 : 1; + asd_sleep(3); + sprintf(gCmdStr, "%s wsec %d", rwl_client_path, bso->wsec); + exec_process(gCmdStr); + + if(setmode->encpType == ENCRYPT_WEP) { + for (i = 0; i < 4; i++) { + if (setmode->keys[i][0] != '\0') { + strcpy(bso->keys[i], setmode->keys[i]); + sprintf(gCmdStr, "%s addwep %d %s", rwl_client_path, i, setmode->keys[i]); + exec_process(gCmdStr); + } + else { + memset(bso->keys[i],0, BCM_WEP_KEY_SIZE_MAX); + } + } + /* set active key */ + if ((setmode->activeKeyIdx > 0) && (setmode->activeKeyIdx < 5)) { + /* move the index range from (1 to 4) to (0 to 3) */ + bso->primary_key = setmode->activeKeyIdx - 1; + sprintf(gCmdStr, "%s primary_key %d", rwl_client_path, bso->primary_key); + exec_process(gCmdStr); + } + } +exit: + + SetModeResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_MODE_RESP_TLV, 4, (BYTE *)SetModeResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* Following functions are specific to Win XP CA or Linux CA */ +/* +* wfaStaGetMacAddress() +* This function is to retrieve the MAC address of a wireless I/F. +*/ +int wfaStaGetMacAddress(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t *getmacResp = &gGenericResp; + + FILE *tmpfd; + + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetMacAddress ...\n"); + + /* Start: Modifed as per BRCM 1.3 ASD*/ +#ifndef WIN32 + /* Modified on 28/12/07 after getting wl dump error in 4325*/ + //sprintf(gCmdStr, "ifconfig %s|grep HWaddr|cut -f3 -dr", ifname); + sprintf(gCmdStr, "%s cur_etheraddr", rwl_client_path); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); +#else + strcpy(gCmdStr,rwl_client_path); + strcat(gCmdStr," cur_etheraddr >"); +#endif + if((tmpfd = asd_Config(gCmdStr,TEMP_FILE_PATH)) == NULL){ + getmacResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_GET_MAC_ADDRESS_RESP_TLV, 4, (BYTE *)getmacResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + DPRINT_ERR(WFA_ERR, "Failed to get mac address\n"); + return FALSE; + } + fgets(gCmdStr, 15, tmpfd); + /*End:Modified on 28/12/07 after getting wl dump error in 4325 */ + fgets(getmacResp->cmdru.mac, sizeof(getmacResp->cmdru.mac), tmpfd); + getmacResp->cmdru.mac[strlen(getmacResp->cmdru.mac) - 1] = 0; /* Get rid of NL */ + printf("get_mac_addr: returning mac :%s:\n", getmacResp->cmdru.mac); + Cleanup_File(tmpfd); + + getmacResp->status = STATUS_COMPLETE; + + wfaEncodeTLV(WFA_STA_GET_MAC_ADDRESS_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)getmacResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + return TRUE; +} + +int wfaStaSetPwrSave(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetPwrSave_t *setps = (caStaSetPwrSave_t *)caCmdBuf; + dutCmdResponse_t *SetPSResp = &gGenericResp; + + sprintf(gCmdStr, "%s PM %d", rwl_client_path, setps->mode); + exec_process(gCmdStr); + + SetPSResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_SET_PWRSAVE_RESP_TLV, 4, (BYTE *)SetPSResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* +* wfaStaIsConnected(): +* The function is to check whether the station's wireless I/F has +* already connected to an AP. +*/ +int wfaStaIsConnected(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + /* Removed as per BRCM 1.3 ASD */ + FILE *tmpfd; + dutCmdResponse_t *staConnectResp = &gGenericResp; + +#ifdef WIN32 + unsigned int position; +#endif + DPRINT_INFO(WFA_OUT, "Entering isConnected ...\n"); + + /* Start: Added as per BRCM 1.3 ASD */ + /* Associated gets long response */ +#ifndef WIN32 + sprintf(gCmdStr, "%s assoc | wc -l", rwl_client_path); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); +#else + strcpy(gCmdStr, rwl_client_path); + strcat(gCmdStr, " assoc >"); +#endif + if((tmpfd = asd_Config(gCmdStr,TEMP_FILE_PATH)) == NULL){ + staConnectResp->status = STATUS_ERROR; + printf("assoc failed\n"); + wfaEncodeTLV(WFA_STA_IS_CONNECTED_RESP_TLV, 4, (BYTE *)staConnectResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + DPRINT_ERR(WFA_ERR, "isconnected failed\n"); + return FALSE; + } + +#ifndef WIN32 + fgets(gCmdStr, sizeof(gCmdStr), tmpfd); + /* Short response means not associated */ + if (atoi(gCmdStr) <= 2) + staConnectResp->cmdru.connected = 0; + else + staConnectResp->cmdru.connected = 1; + /* End: Added as per BRCM 1.3 ASD */ +#else + if((FileSearch(tmpfd, L"Not associated", &position))!= -1) + staConnectResp->cmdru.connected = 0; + else + staConnectResp->cmdru.connected = 1; +#endif + /* + * Report back the status: Complete or Failed. + */ + Cleanup_File(tmpfd); + staConnectResp->status = STATUS_COMPLETE; + + wfaEncodeTLV(WFA_STA_IS_CONNECTED_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)staConnectResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + return TRUE; +} + +/* +* wfaStaGetStats(): +* The function is to retrieve the statistics of the I/F's layer 2 txFrames, +* rxFrames, txMulticast, rxMulticast, fcsErrors/crc, and txRetries. +* Currently there is not definition how to use these info. +*/ +int wfaStaGetStats(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t *statsResp = &gGenericResp; + FILE *fd; /* Added as per BRCM 1.3 ASD */ + caStaGetStatsResp_t *castatsResp = &statsResp->cmdru.ifStats; /* Added as per BRCM 1.3 ASD */ +#ifdef WIN32 + char cmdStr[256]; + unsigned int position; +#endif + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetStats ...\n"); +#ifndef WIN32 + /* Start: Modified as per BRCM 1.3 ASD */ + sprintf(gCmdStr, "%s counters | grep txframe | awk '{print $2,\"\\n\",$10}'", rwl_client_path); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + /* wl dump replaced with wl counters to get statistics */ + if ((fd = popen(gCmdStr, "r")) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get txframe stats\n"); + goto wfaStaGetStats_error; + } else { + fgets(gCmdStr, sizeof(gCmdStr), fd); /* line 1: tx frame */ + castatsResp->txFrames = atoi(gCmdStr); + fgets(gCmdStr, sizeof(gCmdStr), fd); /* line 2: rx frame */ + castatsResp->rxFrames = atoi(gCmdStr); + pclose(fd); + } + + sprintf(gCmdStr, "%s counters | grep d11_txmulti | awk '{print $4,\"\\n\",$8}' ", rwl_client_path); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + if ((fd = popen(gCmdStr,"r")) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get d11_txmulti stats\n"); + goto wfaStaGetStats_error; + } else { + fgets(gCmdStr, sizeof(gCmdStr), fd); + castatsResp->txMulticast = atoi(gCmdStr); + fgets(gCmdStr, sizeof(gCmdStr), fd); + castatsResp->txRetries = atoi(gCmdStr); + pclose(fd); + } + sprintf(gCmdStr, "%s counters | grep d11_rxmulti | awk '{print $4}'", rwl_client_path); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + if ((fd = popen(gCmdStr ,"r")) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get rxMultiFrame stats\n"); + goto wfaStaGetStats_error; + } else { + fgets(gCmdStr, sizeof(gCmdStr), fd); + castatsResp->rxMulticast = atoi(gCmdStr); + pclose(fd); + } + + sprintf(gCmdStr, "%s counters | grep rxbadfcs | awk '{print $8}'", rwl_client_path); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + if ((fd = popen(gCmdStr, "r")) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get rxbadfcs stats\n"); + goto wfaStaGetStats_error; + } else { + fgets(gCmdStr, sizeof(gCmdStr), fd); + castatsResp->fcsErrors = atoi(gCmdStr); + pclose(fd); + } +#else + strcpy(cmdStr,rwl_client_path); + strcat(cmdStr," counters >"); + /*Open the file to read the statistics*/ + if((fd = asd_Config(cmdStr,TEMP_FILE_PATH)) == NULL){ + DPRINT_ERR(WFA_ERR, "Couldn't get rxbadfcs stats\n"); + goto wfaStaGetStats_error; + } + else { + + GetStats(fd, L"txframe ", &position," "); + castatsResp->txFrames = position; + + GetStats(fd, L"rxframe ", &position," "); + castatsResp->rxFrames =position; + + GetStats(fd, L"d11_txmulti ", &position," "); + castatsResp->txMulticast =position; + + GetStats(fd, L"d11_rxmulti ", &position," "); + castatsResp->rxMulticast = position; + + GetStats(fd, L"d11_txretrie ", &position," "); + castatsResp->txRetries = position; + + GetStats(fd, L"rxbadfcs ", &position," "); + castatsResp->fcsErrors= position ; + } + Cleanup_File(fd); +#endif + /* End: Modified as per BRCM 1.3 ASD */ + statsResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_GET_STATS_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)statsResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + return TRUE; + +wfaStaGetStats_error: + statsResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_GET_STATS_RESP_TLV, 4, (BYTE *)statsResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return FALSE; +} + +int wfaDeviceGetInfo(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t *infoResp = &gGenericResp; + /*a vendor can fill in the proper info or anything non-disclosure */ + caDeviceGetInfoResp_t dinfo = {"WFA Lab", "DemoUnit", WFA_SYSTEM_VER}; + /* Start: Modified as per BRCM 1.3 ASD */ + FILE *fd; + +#ifndef WIN32 + /* get the 7th word in the string(1st line ignored( as it contains the value + * for dinfo.version */ + sprintf(gCmdStr,"%s ver | awk '{print $7}'", rwl_client_path); +#ifdef DEBUG + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); +#endif +#else + strcpy(gCmdStr,rwl_client_path); + strcat(gCmdStr," ver >"); +#endif + if((fd = asd_Config(gCmdStr,TEMP_FILE_PATH)) == NULL){ + printf("Error executing ver\n"); + infoResp->status = STATUS_ERROR; + } + else { +#ifndef WIN32 + fgets(gCmdStr, sizeof(gCmdStr), fd); /* Ignore first line */ + fgets(gCmdStr, sizeof(gCmdStr), fd); + gCmdStr[strlen(gCmdStr) - 1] = 0; /* Get rid of NL */ +#else + /* The string next to version contains value for dinfo.version */ + while ((fscanf(fd, "%s\n", gCmdStr)) != EOF) { + if (strncmp(gCmdStr, "version", sizeof("version")) == 0) { + fscanf(fd, "%s\n", gCmdStr); + break; + } + } +#endif + } + Cleanup_File(fd); + memset(&dinfo, 0, sizeof(dinfo)); + infoResp->status = STATUS_COMPLETE; + sprintf(dinfo.vendor, "%.16s", "Broadcom"); + sprintf(dinfo.version, "%.16s", gCmdStr); + sprintf(dinfo.model, "%.16s", "BRCM"); + + DPRINT_INFO(WFA_OUT, "Entering wfaDeviceGetInfo ...\n"); + DPRINT_INFO(WFA_OUT, "status,%i,vendor,%s,model,%s,version %s\n", infoResp->status, + dinfo.vendor,dinfo.model, dinfo.version); + memcpy(&infoResp->cmdru.devInfo, &dinfo, sizeof(caDeviceGetInfoResp_t)); + + infoResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_DEVICE_GET_INFO_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)infoResp, respBuf); + + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + /* End: Modified as per BRCM 1.3 ASD */ + return TRUE; +} + +/* +* wfaStaGetBSSID(): +* This function is to retrieve BSSID of a specific wireless I/F. +*/ +int wfaStaGetBSSID(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + FILE *tmpfd; + dutCmdResponse_t *bssidResp = &gGenericResp; + DPRINT_INFO(WFA_OUT, "Entering wfaStaGetBSSID ...\n"); + +#ifndef WIN32 + /* Start: Modified for BRCM 1.3 ASD */ + /* Associated gets long response */ + sprintf(gCmdStr, "%s assoc | wc -l", rwl_client_path); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); +#else + memset(gCmdStr, 0, sizeof(gCmdStr)); + strcpy(gCmdStr, rwl_client_path); + strcat(gCmdStr, " bssid >"); +#endif + + if((tmpfd = asd_Config(gCmdStr,TEMP_FILE_PATH)) == NULL){ + printf("BSSID failed\n"); + bssidResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_GET_BSSID_RESP_TLV, 4, (BYTE *)bssidResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + } + fgets(gCmdStr, sizeof(gCmdStr), tmpfd); + Cleanup_File(tmpfd); + +#ifndef WIN32 + /* Short response means not associated */ + if (atoi(gCmdStr) <= 2) { + strcpy(bssidResp->cmdru.bssid, "00:00:00:00:00:00"); + } else { + sprintf(gCmdStr, "%s bssid", rwl_client_path); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + if ((tmpfd = popen(gCmdStr, "r")) == NULL){ + printf("bssid failed\n"); + } + fgets(gCmdStr, sizeof(gCmdStr), tmpfd); + pclose(tmpfd); + gCmdStr[17] = 0; /* Get rid of CR or NL */ + strcpy(bssidResp->cmdru.bssid, gCmdStr); + } +#else + gCmdStr[17] = 0; /* Get rid of CR or NL */ + if (gCmdStr[2] != ':'){ + strcpy(bssidResp->cmdru.bssid, "00:00:00:00:00:00"); + } + else { + strcpy(bssidResp->cmdru.bssid, gCmdStr); + } +#endif + bssidResp->status = STATUS_COMPLETE; + /* End Modified as per BRCM 1.3 ASD */ + wfaEncodeTLV(WFA_STA_GET_BSSID_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)bssidResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + return TRUE; +} + +/* + * exec_addts(): + * This function will call ./wl cac_addts + */ +int +exec_addts(caStaSetWMM_t *setwmm) +{ + char pwr_save_str[TSPEC_BUF_SIZE], direction[TSPEC_BUF_SIZE]; + int stat; + + DPRINT_INFO(WFA_OUT, "ADDTS AC PARAMS: \n \ + dialog id: %d, \t TID: %d, \t DIRECTION: %d, \n \ + PSB: %d, \t UP: %d, \t Fixed %d, \n \ + MSDU Size: %d, \t Max MSDU Size %d, \n \ + MIN SERVICE INTERVAL: %d, \t MAX SERVICE INTERVAL: %d, \n \ + INACTIVITY: %d, \t SUSPENSION %d, \n \ + SERVICE START TIME: %d, \t MIN DATARATE: %d, \n \ + MEAN DATA RATE: %d, \t PEAK DATA RATE: %d, \n \ + BURSTSIZE: %d, \t DELAY BOUND: %d, \t PHYRATE: %d, \n \ + SPLUSBW: %f, \t MEDIUM TIME: %d, \t ACCESSCAT: %d\n", \ + setwmm->actions.addts.dialog_token, \ + setwmm->actions.addts.tspec.tsinfo.TID, \ + setwmm->actions.addts.tspec.tsinfo.direction, \ + setwmm->actions.addts.tspec.tsinfo.PSB, \ + setwmm->actions.addts.tspec.tsinfo.UP, \ + setwmm->actions.addts.tspec.Fixed, \ + setwmm->actions.addts.tspec.size, \ + setwmm->actions.addts.tspec.maxsize, \ + setwmm->actions.addts.tspec.min_srvc, \ + setwmm->actions.addts.tspec.max_srvc, \ + setwmm->actions.addts.tspec.inactivity, \ + setwmm->actions.addts.tspec.suspension, \ + setwmm->actions.addts.tspec.srvc_strt_tim, \ + setwmm->actions.addts.tspec.mindatarate, \ + setwmm->actions.addts.tspec.meandatarate, \ + setwmm->actions.addts.tspec.peakdatarate, \ + setwmm->actions.addts.tspec.burstsize, \ + setwmm->actions.addts.tspec.delaybound, \ + setwmm->actions.addts.tspec.PHYrate, \ + setwmm->actions.addts.tspec.sba, \ + setwmm->actions.addts.tspec.medium_time, \ + setwmm->actions.addts.accesscat); + + if (setwmm->actions.addts.tspec.tsinfo.direction == WMMAC_UPLINK) + S_N_PRINTF(direction, sizeof(direction), "uplink"); + else if (setwmm->actions.addts.tspec.tsinfo.direction == WMMAC_DOWNLINK) + S_N_PRINTF(direction, sizeof(direction), "downlink"); + else if (setwmm->actions.addts.tspec.tsinfo.direction == WMMAC_BIDIR) + S_N_PRINTF(direction, sizeof(direction), "bi-directional"); + + if (setwmm->actions.addts.tspec.tsinfo.PSB == 1) + S_N_PRINTF(pwr_save_str, sizeof(pwr_save_str), "U-APSD"); + else if (setwmm->actions.addts.tspec.tsinfo.PSB == 0) + S_N_PRINTF(pwr_save_str, sizeof(pwr_save_str), "legacy"); + + if(setwmm->send_trig) { + int Sockfd; + struct sockaddr_in psToAddr; + unsigned int TxMsg[512]; + Sockfd = wfaCreateUDPSock(setwmm->dipaddr, 12346); + memset(&psToAddr, 0, sizeof(psToAddr)); + psToAddr.sin_family = AF_INET; + psToAddr.sin_addr.s_addr = inet_addr(setwmm->dipaddr); + psToAddr.sin_port = htons(12346); + usleep(becon_int); + wfaTGSetPrio(Sockfd, setwmm->trig_ac); + printf("\r\nSending dummy Hello to %s\n",setwmm->dipaddr); + create_apts_msg(APTS_HELLO, TxMsg,0); + wfaTrafficSendTo(Sockfd, (char *)TxMsg, 256, (struct sockaddr *)&psToAddr); + asd_closeSocket(Sockfd); + } + + S_N_PRINTF(gCmdStr, sizeof(gCmdStr), "%s cac_addts %d %d %d %s %s %d %d %d" \ + " %d %d %d %d %d %d %d %d %d %d %d %d", \ + rwl_client_path, \ + TSPEC_VER, \ + setwmm->actions.addts.dialog_token, \ + setwmm->actions.addts.tspec.tsinfo.TID, \ + direction, \ + pwr_save_str, \ + setwmm->actions.addts.tspec.tsinfo.UP, \ + setwmm->actions.addts.tspec.size, \ + setwmm->actions.addts.tspec.Fixed, \ + setwmm->actions.addts.tspec.maxsize, \ + setwmm->actions.addts.tspec.min_srvc, \ + setwmm->actions.addts.tspec.max_srvc, \ + setwmm->actions.addts.tspec.inactivity, \ + setwmm->actions.addts.tspec.suspension, \ + setwmm->actions.addts.tspec.mindatarate, \ + setwmm->actions.addts.tspec.meandatarate, \ + setwmm->actions.addts.tspec.peakdatarate, \ + setwmm->actions.addts.tspec.burstsize, \ + setwmm->actions.addts.tspec.delaybound, \ + (int)setwmm->actions.addts.tspec.sba, \ + setwmm->actions.addts.tspec.PHYrate); + if ((stat = exec_wmmCmd(gCmdStr)) != 0) { + return FALSE; + } + return TRUE; +} + +/* + * exec_delts(): + * This function will call ./wl cac_delts + */ + +int +exec_delts(caStaSetWMM_t *setwmm) +{ + char *token_buf = NULL; + char temp_buf[WFA_BUFF_128], tsinfo_buf[MAX_TOKENS][TSPEC_BUF_SIZE], temp_resp[WFA_BUFF_128]; + int token_count, stat, nbyte = 0, tsinfo_flag; + FILE *output_fp, *error_fp; + + DPRINT_INFO(WFA_OUT, "DELTS AC PARAMS: TID: %d\n", setwmm->actions.delts); + S_N_PRINTF(gCmdStr, sizeof(gCmdStr), "%s cac_tslist", rwl_client_path); + + /* Execute the command "wl cac_tslist" */ + if ((stat = asd_Config_wmm(gCmdStr, TEMP_STD_OUT_FILE)) != 0) { + if ((error_fp = fopen(TEMP_STD_ERR_FILE, "r")) == NULL) { + DPRINT_ERR(WFA_ERR, "Error in reading error message. \n"); + } + memset(temp_resp, 0, sizeof(temp_resp)); + fgets(temp_resp, sizeof(temp_resp), error_fp); + DPRINT_ERR(WFA_ERR, "Error in executing wl cac_tslist :: %s \n", temp_resp); + return FALSE; + } + + tsinfo_flag = NO_TSINFO; + if ((output_fp = fopen(TEMP_STD_OUT_FILE, "r")) == NULL) { + printf("\nTEMP_STD_OUT_FILE::File open error\n"); + return FALSE; + } + else { + while ((feof(output_fp) == 0)) { + if (fseek(output_fp, nbyte, SEEK_SET) < 0) { + tsinfo_flag = NO_TSINFO; + return FALSE; + } + memset(temp_resp, 0, sizeof(temp_resp)); + fgets(temp_resp, sizeof(temp_resp), output_fp); + nbyte = nbyte + strlen(temp_resp); + + /* Get the wl cac_tslist results in temp_resp */ + + if (strlen(temp_resp) == 0) { + DPRINT_ERR(WFA_ERR, "temp_resp length 0. Can't execute wl cac_delts \n"); + tsinfo_flag = NO_TSINFO; + break; + } + + token_buf = (char *)strtok_r(temp_resp, " ", (char **) temp_buf); + token_count = 0; + while (token_buf != NULL) { + token_buf = (char *)strtok_r(NULL, " ", (char **) temp_buf); + if (token_buf != NULL) { + S_N_PRINTF(tsinfo_buf[token_count], + sizeof(tsinfo_buf[token_count]), "%s", token_buf); + token_count++; + } + } + /* if tid of cac_tslist matches with tid of sta_set_wmm then delts is performed */ + if (atoi(tsinfo_buf[TID_INDEX]) == setwmm->actions.delts) { + S_N_PRINTF(gCmdStr, sizeof(gCmdStr), "%s cac_delts %d %s %s %s", \ + rwl_client_path, TSPEC_VER, tsinfo_buf[BYTE_0], \ + tsinfo_buf[BYTE_1], tsinfo_buf[BYTE_2]); + /* Execute wl cac_delts */ + if ((stat = exec_wmmCmd(gCmdStr)) != 0) { + return FALSE; + } + return TRUE; + } + else { + tsinfo_flag = TID_MISMATCH; + } + } /* End of while */ + fclose(output_fp); + if (tsinfo_flag == NO_TSINFO) { + DPRINT_ERR(WFA_ERR, "Error. Cannot Execute wl cac_delts \n"); + return FALSE; + } + else if (tsinfo_flag == TID_MISMATCH) { + DPRINT_ERR(WFA_ERR, "tid did not match. Can't Execute wl cac_delts \n"); + return FALSE; + } + } + return TRUE; +} + + +/* + * wfaStaSetWMM(): + * The function is to set the WMM related parameters at the DUT. + * Currently the function is used for GROUPS WMM-AC and WMM general configuration for setting + * RTS Threshhold, Fragmentation threshold and wmm (ON/OFF) + * It is expected that this function will set all the WMM related parametrs for a particular GROUP. +*/ + +int wfaStaSetWMM(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetWMM_t *setwmm = (caStaSetWMM_t *)caCmdBuf; + char *ifname = setwmm->intf; + dutCmdResponse_t *setwmmResp = &gGenericResp; + int stat; + int Sockfd; + struct sockaddr_in psToAddr; + unsigned int TxMsg[512]; + + switch(setwmm->group) + { + case GROUP_WMMAC: + if (setwmm->send_trig) + { + Sockfd = wfaCreateUDPSock(setwmm->dipaddr, 12346); + memset(&psToAddr, 0, sizeof(psToAddr)); + psToAddr.sin_family = AF_INET; + psToAddr.sin_addr.s_addr = inet_addr(setwmm->dipaddr); + psToAddr.sin_port = htons(12346); + switch (setwmm->trig_ac) + { + + case WMMAC_AC_VO: + wfaTGSetPrio(Sockfd, 7); + create_apts_msg(APTS_CK_VO, TxMsg, 0); + printf("\r\nSending AC_VO trigger packet\n"); + break; + + case WMMAC_AC_VI: + wfaTGSetPrio(Sockfd, 5); + create_apts_msg(APTS_CK_VI, TxMsg, 0); + printf("\r\nSending AC_VI trigger packet\n"); + break; + + case WMMAC_AC_BK: + wfaTGSetPrio(Sockfd, 2); + create_apts_msg(APTS_CK_BK, TxMsg, 0); + printf("\r\nSending AC_BK trigger packet\n"); + break; + + default: + case WMMAC_AC_BE: + wfaTGSetPrio(Sockfd, 0); + create_apts_msg(APTS_CK_BE, TxMsg, 0); + printf("\r\nSending AC_BE trigger packet\n"); + break; + } + sendto(Sockfd, TxMsg, 256, 0, (struct sockaddr *)&psToAddr, + sizeof(struct sockaddr)); + asd_closeSocket(Sockfd); + usleep(1000000); + } + else if (setwmm->action == WMMAC_ADDTS) { + if ((stat = exec_addts(setwmm)) == FALSE) { + setwmmResp->status = STATUS_ERROR; + break; + } + } + else if (setwmm->action == WMMAC_DELTS) { + if ((stat = exec_delts(setwmm)) == FALSE) { + setwmmResp->status = STATUS_ERROR; + break; + } + } + setwmmResp->status = STATUS_COMPLETE; + break; + + case GROUP_WMMCONF: + S_N_PRINTF(gCmdStr, sizeof(gCmdStr), "iwconfig %s rts_thr %d", \ + ifname,setwmm->actions.config.rts_thr); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, sizeof(gCmdStr), "iwconfig %s frag_thr %d", \ + ifname,setwmm->actions.config.frag_thr); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, sizeof(gCmdStr), "iwpriv %s wmm %d", \ + ifname,setwmm->actions.config.wmm); + exec_process(gCmdStr); + setwmmResp->status = STATUS_COMPLETE; + break; + + default: + DPRINT_ERR(WFA_ERR, "The group %d is not supported\n",setwmm->group); + setwmmResp->status = STATUS_ERROR; + break; + } + + wfaEncodeTLV(WFA_STA_SET_WMM_RESP_TLV, 4, (BYTE *)setwmmResp, respBuf); + DPRINT_INFO(WFA_OUT, "tag is %d\n",WFA_STA_SET_WMM_RESP_TLV); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; +} + +/* Start: Added BCM functions as per BRCM 1.3 ASD */ +int bcmSsidIsGood(char *ssidStr) +{ + int ssidLen = strlen(ssidStr); + + if ((ssidLen == 0) || (ssidLen > BCM_SSID_LEN_MAX)) { + return (FALSE); + } else { + return (TRUE); + } +} + +bcmSsidObj_t *bcmWfaSsidTblFreeEntry() +{ + bcmSsidObj_t *bso; + int idx; + + DPRINT_INFO(WFA_OUT, "bcmWfaSsidTblFreeEntry\n"); + + for (idx = 0; idx < BCM_SSID_MAX; idx++) { + bso = &bsotbl.ssidObj[idx]; + if (bcmSsidIsGood(bso->ssidStr) == FALSE) { + return bso; + } + } + + DPRINT_ERR(WFA_OUT, "bcmWfaSsidTblFreeEntry: no free entry available.\n"); + return (NULL); +} + +bcmSsidObj_t *bcmWfaSsidTblSsidFind(char *ssidStr) +{ + bcmSsidObj_t *bso; + bcmSsidObj_t *bsoFound= NULL; + int idx; + + if (bcmSsidIsGood(ssidStr) == FALSE) { + return (NULL); + } + + for (idx = 0; idx < BCM_SSID_MAX; idx++) { + bso = &bsotbl.ssidObj[idx]; + if (bcmSsidIsGood(ssidStr) == FALSE) { + continue; + } + + if (strcmp(ssidStr, bso->ssidStr)) { + continue; + } else { + bsoFound = bso; + break; + } + } + + return (bsoFound); +} + +bcmSsidObj_t *bcmWfaSsidObjTblAdd(char *ssidStr) +{ + bcmSsidObj_t *bso; + int idx; + + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblAdd: ssidStr %s\n", ssidStr); + + if (bcmSsidIsGood(ssidStr) == FALSE) { + return (NULL); + } + + if ((bso = bcmWfaSsidTblSsidFind(ssidStr))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s): ssid already exists\n", ssidStr); + return (bso); + } + + if (!(bso = bcmWfaSsidTblFreeEntry())) { + DPRINT_INFO(WFA_OUT, "no free entry\n"); + return (NULL); + } + + memset(bso,0, sizeof(bcmSsidObj_t)); + strcpy(bso->ssidStr, ssidStr); + bso->bssType = BCM_BSS_INFRA; /* init it to infrastructure bss */ + bso->primary_key = BCM_PRI_KEY_BAD; /* init it to bad one */ + bso->eapType = BCM_DEFAULT_SEC_MODE; /* init to non-eap mode */ + + for (idx = 0; idx < 4; idx++) { + S_N_PRINTF (bso->keys[idx], 2, "%s", "\0"); + } + + bsotbl.addCnt++; + bsotbl.entries++; + + return (bso); +} + +void bcmWfaSsidObjTblDel(char *ssidStr) +{ + bcmSsidObj_t *bso; + + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblDel: ssidStr %s\n", ssidStr); + + bso = bcmWfaSsidTblSsidFind(ssidStr); + if (bso == NULL) { + return; + } + + DPRINT_INFO(WFA_OUT, "bcmWfaSsidObjTblDel: deleting bso %p\n", bso); + memset(bso,0, sizeof(bcmSsidObj_t)); + bsotbl.delCnt++; + bsotbl.entries--; +} + +void bcmWfaSsidObjPrint(bcmSsidObj_t *bso) +{ + int idx; + + if (bcmSsidIsGood(bso->ssidStr) == FALSE) { + fprintf(WFA_OUT, "bso %p is blank.\n", bso); + return; + } + + fprintf(WFA_OUT, "bso %p\n", bso); + fprintf(WFA_OUT, "\tssid %s", bso->ssidStr); + fprintf(WFA_OUT, "\tbssType %d\n", bso->bssType); + fprintf(WFA_OUT, "\tchannel %d\n", bso->channel); + fprintf(WFA_OUT, "\twsec %d\n", bso->wsec); + fprintf(WFA_OUT, "\tauth %d\n", bso->auth); + fprintf(WFA_OUT, "\twpa_auth %d\n", bso->wpa_auth); + fprintf(WFA_OUT, "\tpowerSave %d\n", bso->powerSave); + fprintf(WFA_OUT, "\tuapsd %d\n", bso->uapsd); + + for (idx = 0; idx < 4; idx++) { + fprintf(WFA_OUT, "\tkeys[%d] : %s\n", idx, bso->keys[idx]); + } + fprintf(WFA_OUT, "\tprimary_key %d\n", bso->primary_key); + fprintf(WFA_OUT, "\tpassphrase : %s\n", bso->passphrase); +} + +void bcmWfaSsidObjTblPrint(void) +{ + int idx; + + fprintf(WFA_OUT, "entries %d addCnt %d delCnt %d\n", + bsotbl.entries, bsotbl.addCnt, bsotbl.delCnt); + for (idx = 0; idx < BCM_SSID_MAX; idx++) { + bcmWfaSsidObjPrint(&bsotbl.ssidObj[idx]); + } +} + +/*Do the initialisation for the driver */ +void bcmWfaInit(void) +{ + memset(&bsotbl,0, sizeof(bsotbl)); + + sprintf(gCmdStr, "%s ap 0", rwl_client_path); /* not AP */ + exec_process(gCmdStr); + + sprintf(gCmdStr, "%s radio on", rwl_client_path); /* not AP */ + exec_process(gCmdStr); + + sprintf(gCmdStr, "%s wsec 0", rwl_client_path); + exec_process(gCmdStr); + + sprintf(gCmdStr, "%s auth 0", rwl_client_path); + exec_process(gCmdStr); + + sprintf(gCmdStr, "%s wpa_auth 0", rwl_client_path); + exec_process(gCmdStr); + + sprintf(gCmdStr, "%s sup_wpa 1", rwl_client_path); /* enable in-driver supplicant */ + exec_process(gCmdStr); + + /* Driver should not be made up explicitly + * as we need to execute uapsd command in the beginning. + */ +} + +/* + * Implementing set systemtime + */ + +int wfaStaSetSystime(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int retVal = TRUE; + dutCmdResponse_t *SetSystime = &gGenericResp; + dutCommand_t *systime = (dutCommand_t *)caCmdBuf; +#ifndef WIN32 + char *month[]= {"NULL","JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"}; +#else + SYSTEMTIME newtime; + int err; +#endif + DPRINT_INFO(WFA_OUT, "Entering set systime ...\n"); +#ifndef WIN32 + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "date -s \"%d %s %d %d:%d:%d\"", systime->cmdsu.stime.date, month[systime->cmdsu.stime.month], + systime->cmdsu.stime.year, systime->cmdsu.stime.hours, systime->cmdsu.stime.minutes, systime->cmdsu.stime.seconds); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + exec_process(gCmdStr); +#else + newtime.wDay = systime->cmdsu.stime.date; + newtime.wMonth = systime->cmdsu.stime.month; + newtime.wYear = systime->cmdsu.stime.year; + newtime.wHour = systime->cmdsu.stime.hours; + newtime.wMinute = systime->cmdsu.stime.minutes; + newtime.wSecond = systime->cmdsu.stime.seconds; + if ((err = SetLocalTime(&newtime)) == 0) { + DPRINT_ERR(WFA_OUT, "error at set system time % d\n", GetLastError()); + retVal = FALSE; + } +#endif /* WIN32 */ + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + if(retVal == TRUE) + SetSystime->status = STATUS_COMPLETE; + else + SetSystime->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_SYSTIME_RESP_TLV, 4, (BYTE *)SetSystime, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; +} + +/* + * Part of sigma 11n implementation. + * Implementing set 1n functionalities + */ +int wfaStaSet11n(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ +#ifdef WFA_STA_TB + int retVal = TRUE; + FILE *tmpfd; + dutCmdResponse_t *Set11nresp = &gGenericResp; + dutCommand_t *Set11n = (dutCommand_t *)caCmdBuf; + DPRINT_INFO(WFA_OUT, "Entering set 11n ...\n"); + /* Run the commands in the batching mode in case of wifi transport*/ + if(rwl_wifi_flag) { + asd_sleep(1); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s seq_start", rwl_client_path); + exec_process(gCmdStr); + } + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s down", rwl_client_path); + exec_process(gCmdStr); + /* + * Showing unsupported yet to be implemented + * wl mimo_bw_cap need to be implemented by brcm + */ + if (Set11n->cmdsu.set11n.width == 20) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s mimo_bw_cap 0", rwl_client_path); + exec_process(gCmdStr); + } + else if((Set11n->cmdsu.set11n.width) == 40 || (Set11n->cmdsu.set11n.width == -1)) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s mimo_bw_cap 1", rwl_client_path); + exec_process(gCmdStr); + } + if (Set11n->cmdsu.set11n.addba_reject == 2) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s ampdu 0", rwl_client_path); + exec_process(gCmdStr); + } + else if(Set11n->cmdsu.set11n.addba_reject == 1) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s ampdu 1", rwl_client_path); + exec_process(gCmdStr); + } + if (Set11n->cmdsu.set11n.ampdu == 2) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s amsdu 0", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s ampdu 1", rwl_client_path); + exec_process(gCmdStr); + } + else if(Set11n->cmdsu.set11n.ampdu == 1) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s ampdu 0", rwl_client_path); + exec_process(gCmdStr); + } + if (Set11n->cmdsu.set11n.amsdu == 2) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s amsdu 1", rwl_client_path); + exec_process(gCmdStr); + } + else if(Set11n->cmdsu.set11n.amsdu == 1) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s amsdu 0", rwl_client_path); + exec_process(gCmdStr); + } + if (Set11n->cmdsu.set11n.greenfield == 2) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s mimo_preamble 1", rwl_client_path); + exec_process(gCmdStr); + } + else if(Set11n->cmdsu.set11n.greenfield == 1) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s mimo_preamble 0", rwl_client_path); + exec_process(gCmdStr); + } + if (Set11n->cmdsu.set11n.stbc_rx == 0) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s stbc_tx 0", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s stbc_rx 0", rwl_client_path); + exec_process(gCmdStr); + } + else if (Set11n->cmdsu.set11n.stbc_rx > 0) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s stbc_tx 1", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s stbc_rx 1", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s nrate -m 5 -w 2", rwl_client_path); + exec_process(gCmdStr); + } + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s up", rwl_client_path); + exec_process(gCmdStr); + if(rwl_wifi_flag) { + asd_sleep(1); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s seq_stop", rwl_client_path); + exec_process(gCmdStr); + } + if (Set11n->cmdsu.set11n.intolerant_40 == 2) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s obss_coex 1", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s intol40 1", rwl_client_path); + exec_process(gCmdStr); + } + else if(Set11n->cmdsu.set11n.intolerant_40 == 1) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s obss_coex 0", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s intol40 0", rwl_client_path); + exec_process(gCmdStr); + } + + if (Set11n->cmdsu.set11n.sgi20 == 2) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s sgi_tx %d", rwl_client_path, -1); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s sgi_rx %d", rwl_client_path, 3); + exec_process(gCmdStr); + } + else if(Set11n->cmdsu.set11n.sgi20 == 1) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s sgi_tx %d", rwl_client_path, 0); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s sgi_rx %d", rwl_client_path, 0); + exec_process(gCmdStr); + } + /* + * SMPS related commands can be ignored as of now till + * mimo_ps command gets implemented + */ + if (Set11n->cmdsu.set11n.smps == 1) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s mimo_ps 1", rwl_client_path); /* dynamic */ + exec_process(gCmdStr); + } + else if(Set11n->cmdsu.set11n.smps == 2) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s mimo_ps 0", rwl_client_path); /* static */ + exec_process(gCmdStr); + } + else if(Set11n->cmdsu.set11n.smps == 3) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s mimo_ps 3", rwl_client_path); /* no limit */ + exec_process(gCmdStr); + } + if ((Set11n->cmdsu.set11n.mcs_fixedrate >= 0) && (Set11n->cmdsu.set11n.mcs_fixedrate <= 31)) { + +#ifndef WIN32 + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s nrate -m %d &> %s", rwl_client_path, Set11n->cmdsu.set11n.mcs_fixedrate, TEMP_FILE_PATH); +#else + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s nrate -m %d > %s 2>&1", rwl_client_path, Set11n->cmdsu.set11n.mcs_fixedrate, TEMP_FILE_PATH); +#endif + exec_process(gCmdStr); + if((tmpfd = fopen(TEMP_FILE_PATH, "r")) == NULL){ + Set11nresp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_11N_RESP_TLV, 4, (BYTE *)Set11nresp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + fgets(gCmdStr, sizeof(gCmdStr), tmpfd); + Cleanup_File(tmpfd); +/* + * wl rate is issued to check if the 11N supported chip is SISO or MIMO. + * If the response is 72Mbps then it is SISO, + * Checking if wl returning saying not in range, then invalid + */ + if ((strstr(gCmdStr, "Range")) != NULL) { + DPRINT_INFO(WFA_OUT, "This card Doesnt Support this range\n"); + Set11nresp->status = STATUS_INVALID; + wfaEncodeTLV(WFA_STA_SET_11N_RESP_TLV, 4, (BYTE *)Set11nresp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + + } + + + + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + if(retVal == TRUE) + Set11nresp->status = STATUS_COMPLETE; + else + Set11nresp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_11N_RESP_TLV, 4, (BYTE *)Set11nresp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; +#endif /* WFA_STA_TB */ + return TRUE; +} + +/* + * Part of sigma 11n implementation. + * Implementing RIFS test + */ + +int wfaStaSetRifsTest(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ +#ifdef WFA_STA_TB + int retVal = TRUE; + dutCmdResponse_t *RIFStest = &gGenericResp; + dutCommand_t *rifstest = (dutCommand_t *)caCmdBuf; + if(rifstest->cmdsu.action_rifs == 2) { /* enabled */ + if(rwl_wifi_flag) { + asd_sleep(1); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s seq_start", rwl_client_path); + exec_process(gCmdStr); + } + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s down", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s ampdu 0", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s up", rwl_client_path); + exec_process(gCmdStr); + if(rwl_wifi_flag) { + asd_sleep(1); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s seq_stop", rwl_client_path); + exec_process(gCmdStr); + } + /* + * nrate support 0-7 in SISO + * nrate support 0-31 in MIMO + */ + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s nrate -m 12", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s rifs 1", rwl_client_path); + exec_process(gCmdStr); + } + else if(rifstest->cmdsu.action_rifs == 1) { /* disable */ + if(rwl_wifi_flag) { + asd_sleep(1); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s seq_start", rwl_client_path); + exec_process(gCmdStr); + } + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s down", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s up", rwl_client_path); + exec_process(gCmdStr); + if(rwl_wifi_flag) { + asd_sleep(1); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s seq_stop", rwl_client_path); + exec_process(gCmdStr); + } + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s rifs 0", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s band b", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s rate -1", rwl_client_path); + exec_process(gCmdStr); + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s band auto", rwl_client_path); + exec_process(gCmdStr); + } + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + if(retVal == TRUE) + RIFStest->status = STATUS_COMPLETE; + else + RIFStest->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_RIFS_TEST_RESP_TLV, 4, (BYTE *)RIFStest, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; +#endif /* WFA_STA_TB */ + return TRUE; +} + +/* + * Part of sigma 11n implementation. + * Implementing set wireless utility + */ + +int wfaStaSetWireless(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ +#ifdef WFA_STA_TB + int retVal = TRUE; + dutCmdResponse_t *SetWireless = &gGenericResp; + dutCommand_t *wireless = (dutCommand_t *)caCmdBuf; + if(strcasecmp(wireless->cmdsu.wireless_band, "2.4") == 0) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s band b", rwl_client_path); + exec_process(gCmdStr); + } + else if(strcasecmp(wireless->cmdsu.wireless_band, "5") == 0) { + /* + * Band a setting doesnt supported + * Gives error -13 + */ + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s band a", rwl_client_path); + exec_process(gCmdStr); + } + else { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s band auto", rwl_client_path); + exec_process(gCmdStr); + } + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + if(retVal == TRUE) + SetWireless->status = STATUS_COMPLETE; + else + SetWireless->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_WIRELESS_RESP_TLV, 4, (BYTE *)SetWireless, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; +#endif /* WFA_STA_TB */ + return TRUE; +} + +int wfaStaResetDefault(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaResetDefault_t *reset = (caStaResetDefault_t *)caCmdBuf; + dutCmdResponse_t *ResetResp = &gGenericResp; + + /* need to implement based on program, defaults for each program set. */ + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s prog %s ", rwl_client_path, reset->prog); + exec_process(gCmdStr); + + ResetResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_STA_RESET_DEFAULT_RESP_TLV, 4, (BYTE *)ResetResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* + * Part of sigma 11n implementation. + * Implementing send addba + */ + +int wfaStaSendAddba(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ +#ifdef WFA_STA_TB + int retVal = TRUE; + dutCmdResponse_t *SendAddba = &gGenericResp; + dutCommand_t *addba = (dutCommand_t *)caCmdBuf; + FILE *tmpfd; + char mac[WFA_MAC_ADDR_STR_LEN]; + if(addba->cmdsu.tid) { +#ifndef WIN32 + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s bssid", rwl_client_path); +#else + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s bssid >", rwl_client_path); +#endif + if((tmpfd = asd_Config(gCmdStr,TEMP_FILE_PATH)) == NULL) { + DPRINT_ERR(WFA_OUT, "Error executing ssid\n"); + SendAddba->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SEND_ADDBA_RESP_TLV, 4, (BYTE *)SendAddba, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + else { + while((fscanf(tmpfd, "%s\n", gCmdStr)) != EOF) { + memset(mac, 0, WFA_MAC_ADDR_STR_LEN); + strncpy(mac, gCmdStr, strlen(gCmdStr)); + } + } + Cleanup_File(tmpfd); + if (mac[2] != ':') /* if STA is not associated */ + strcpy(mac, "00:00:00:00:00:00"); + DPRINT_INFO(WFA_OUT, "MAC %s\n", mac); + /* + * If STA not associated then error -2 displays + */ + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s ampdu_send_addba %d %s", + rwl_client_path, addba->cmdsu.tid, mac); + exec_process(gCmdStr); + + } + else + retVal = FALSE; + + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + if(retVal == TRUE) + SendAddba->status = STATUS_COMPLETE; + else + SendAddba->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SEND_ADDBA_RESP_TLV, 4, (BYTE *)SendAddba, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; +#endif /* WFA_STA_TB */ + return TRUE; +} + + +/* + * Part of sigma 11n implementation. + * Implementing sending coexist management + */ + +int wfaStaSendCoexistMgmt(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ +#ifdef WFA_STA_TB + int retVal = FALSE; /* changed to make sure one of BSS or MHZ value presnt */ + dutCmdResponse_t *CoexistMgmt = &gGenericResp; + dutCommand_t *coexist = (dutCommand_t *)caCmdBuf; + int mhz, bss; + /* + * Either of BSS, MHZ value should be present in the option + */ + if (coexist->cmdsu.coexistmgmt.Mhz[0] != '\0') { + mhz = atoi(coexist->cmdsu.coexistmgmt.Mhz); + retVal = TRUE; + } + else { + mhz = 0; + } + if (coexist->cmdsu.coexistmgmt.bss[0] != '\0') { + bss = atoi(coexist->cmdsu.coexistmgmt.bss); + retVal = TRUE; + } + else { + bss = 0; + } + if (bss > 1 || bss < 0 || mhz >1 || mhz < 0) { + /* they can only have 0/1 */ + DPRINT_INFO(WFA_OUT, "BSS or MHz can have value 1/0\n"); + retVal = FALSE; + } + /* + * This command also yet to be implemented from brcm + */ + if (coexist->cmdsu.coexistmgmt.ChnlRepo[0] != '\0' && + coexist->cmdsu.coexistmgmt.ChnlRepo) { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s obss_coex_action -i %d -w %d -c %s", rwl_client_path, mhz, bss, + coexist->cmdsu.coexistmgmt.ChnlRepo); + } + else { + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s obss_coex_action -i %d -w %d", rwl_client_path, mhz, bss); + } + if (retVal == TRUE) + exec_process(gCmdStr); + else + DPRINT_INFO(WFA_OUT, "should enter atleast one option in MHZ or BSS\n"); + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + if(retVal == TRUE) + CoexistMgmt->status = STATUS_COMPLETE; + else + CoexistMgmt->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SEND_COEXIST_MGMT_RESP_TLV, 4, (BYTE *)CoexistMgmt, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; +#endif /* WFA_STA_TB */ + return TRUE; +} + +/* + * Part of sigma 11n implementation. + * Implementing disconnect + */ + +int wfaStaSetDisconnect(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ +#ifdef WFA_STA_TB + int retVal = TRUE; + dutCmdResponse_t *Disconnect = &gGenericResp; + dutCommand_t *discon = (dutCommand_t *)caCmdBuf; + DPRINT_INFO(WFA_OUT, "Entering set disconnect...\n"); + DPRINT_INFO(WFA_OUT, "interface entered %s\n", discon->intf); + + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s disassoc", rwl_client_path); + exec_process(gCmdStr); + if(retVal == TRUE) + Disconnect->status = STATUS_COMPLETE; + else + Disconnect->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_DISCONNECT_RESP_TLV, 4, (BYTE *)Disconnect, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; +#endif /* WFA_STA_TB */ + return TRUE; +} + +/* + * Part of sigma 11n implementation. + * Implementing sending neighborhood request + */ + +int wfaStaSendNeigreq(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ +#ifdef WFA_STA_TB + int retVal = TRUE; + dutCmdResponse_t *SendNeigreq = &gGenericResp; + dutCommand_t *neigreq = (dutCommand_t *)caCmdBuf; + char ssidTarget[WFA_SSID_NAME_LEN]; + bcmSsidObj_t *bso; + DPRINT_INFO(WFA_OUT, "Entering send neighbourhood request ...\n"); + memcpy(ssidTarget, neigreq->cmdsu.ssid, WFA_SSID_NAME_LEN); + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + return FALSE; + } + } + /* + * wl rrm_nbr_req need to have support for ssid parameter, currently it takes + * something else which is not recommended by wi-fi + */ + S_N_PRINTF(gCmdStr, WFA_CMD_STR_SZ, "%s rrm_nbr_req %s", rwl_client_path, ssidTarget); + DPRINT_INFO(WFA_OUT, "%s\n", gCmdStr); + exec_process(gCmdStr); + /* + * Then report back to control PC for completion. + * This does not have failed/error status. The result only tells + * a completion. + */ + if(retVal == TRUE) + SendNeigreq->status = STATUS_COMPLETE; + else + SendNeigreq->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SEND_NEIGREQ_RESP_TLV, 4, (BYTE *)SendNeigreq, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; +#endif /* WFA_STA_TB */ + return TRUE; +} + +/* +* wfaStaSetFAST() +* This is to set +* 1. ssid +* 2. user name +* 3. passwd +* 4. encryType - tkip or aes-ccmp +* 5. keyMgmtType - wpa or wpa2 +* 6. trustedRootCA +* 7. innerEAP +* 8. validateserver +* 9. PACfile +*/ +int wfaStaSetEapFAST(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetEapFAST_t *setFAST = (caStaSetEapFAST_t *)caCmdBuf; + int retVal = TRUE; + dutCmdResponse_t *setFastResp = &gGenericResp; + bcmSsidObj_t *bso; + char ssidTarget[WFA_SSID_NAME_LEN]; + + memcpy(ssidTarget, setFAST->ssid, WFA_SSID_NAME_LEN); + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + retVal = FALSE; + } + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + } + + memcpy(&(bso->eapObj.setEapFAST), setFAST, sizeof(caStaSetEapFAST_t)); + bso->eapType = BCM_EAP_TYPE_FAST; + + if(strstr(bso->eapObj.setEapFAST.encrptype,"aes-ccmp")) + strncpy(bso->eapObj.setEapFAST.encrptype, AES_ENCPTYPE, AES_LEN) ; + if(retVal == TRUE) + setFastResp->status = STATUS_COMPLETE; + else + setFastResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_EAPFAST_RESP_TLV, 4, (BYTE *)setFastResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* +* wfaStaSetEapAKA() +* This is to set +* 1. ssid +* 2. user name +* 3. passwd +* 4. encryType - tkip or aes-ccmp +* 5. keyMgmtType - wpa or wpa2 +*/ +int wfaStaSetEapAKA(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + caStaSetEapAKA_t *setAKA = (caStaSetEapAKA_t *)caCmdBuf; + dutCmdResponse_t *setAkaResp = &gGenericResp; + bcmSsidObj_t *bso; + int retVal = TRUE; + char ssidTarget[WFA_SSID_NAME_LEN]; + + memcpy(ssidTarget, setAKA->ssid, WFA_SSID_NAME_LEN); + bso = bcmWfaSsidTblSsidFind(ssidTarget); + if (!bso) { + if (!(bso = bcmWfaSsidObjTblAdd(ssidTarget))) { + DPRINT_ERR(WFA_OUT, "bcmWfaSsidObjTblAdd(%s) failed\n", ssidTarget); + retVal = FALSE; + } + if (wfa_defined_debug & (WFA_DEBUG_ERR | WFA_DEBUG_INFO)) { + bcmWfaSsidObjPrint(bso); + } + + } + + memcpy(&(bso->eapObj.setEapAKA), setAKA, sizeof(caStaSetEapAKA_t)); + bso->eapType = BCM_EAP_TYPE_AKA; + + if(strstr(bso->eapObj.setEapAKA.encrptype,"aes-ccmp")) + strncpy(bso->eapObj.setEapAKA.encrptype, AES_ENCPTYPE, AES_LEN) ; + if(retVal == TRUE) + setAkaResp->status = STATUS_COMPLETE; + else + setAkaResp->status = STATUS_ERROR; + wfaEncodeTLV(WFA_STA_SET_EAPAKA_RESP_TLV, 4, (BYTE *)setAkaResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_miscs.c b/src/tools/Wifi_ASD_test/lib/wfa_miscs.c new file mode 100644 index 0000000..9dbfa48 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_miscs.c
@@ -0,0 +1,307 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors (.$B!H.(BAuthorized Licensees.$B!I.(B)...A.N Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee.$B!G.(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below...A.N The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee.$B!G.(Bs product to their customers with or + * without such third party.$B!G.(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications...A.N Wi-Fi Alliance + * reserves all rights not expressly granted herein...A.N + *..A.N + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *..A.N + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *..A.N + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A..A.N PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + +/* + * File: wfa_miscs.c - misc functions for agents. + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA release by qhu + * 2006/06/13 -- 00.02 release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/09/01 -- 01.05 Release by qhu + * 2007/01/11 -- 01.10 Released by qhu + * 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * + */ +#include <stdio.h> +#include <stdlib.h> + +#include "wfa_debug.h" +#include "wfa_sock.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_tg.h" +#include "wfa_miscs.h" +#include "wfa_cmds.h" +#ifdef WIN32 +#include "io.h" +#endif /* #ifdef WIN32 */ +#include "stdlib.h" + +#ifndef SIOCGIWNAME +#define SIOCGIWNAME 0x8B01 +#endif + +extern unsigned short wfa_defined_debug; +extern tgStream_t *theStreams; +extern char PingStr[]; +tgStream_t *findStreamProfile(int id); + +/* + * printProfile(): a debugging function to display a profile info based on + * a streamId + */ + +void printProfile(tgProfile_t *pf) +{ + DPRINT_INFO(WFA_OUT, "profile type %i direction %i Dest ipAddr %s Dest port %i So ipAddr %s So port %i rate %i duration %i pksize %i\n", pf->profile, pf->direction, pf->dipaddr, pf->dport, pf->sipaddr, pf->sport, pf->rate, pf->duration, pf->pksize); +} + + +int isString(char *str) +{ + if(*str == '\0') + return FALSE; + + if((str[0] >= 'a' && str[0] <= 'z') + || (str[0] > 'A' && str[0] < 'Z')) + return TRUE; + else + return FALSE; +} + +int isNumber(char *str) +{ + if(*str == '\0') + return FALSE; + + if (str[0] >= '0' && str[0] <= '9') + return TRUE; + else + return FALSE; +} + +int isIpV4Addr(char *str) +{ + int dots = 0; + char *tmpstr = str; + + if(*str == '\0') + return FALSE; + + while(*tmpstr != '\0') + { + if(*tmpstr == '.') + { + dots++; + } + + tmpstr++; + } + + if(dots <3) + return FALSE; + else + return TRUE; +} + + + +inline double wfa_timeval2double(struct timeval *tval) +{ + return ((double) tval->tv_sec + (double) tval->tv_usec*1e-6); +} + +inline void wfa_double2timeval(struct timeval *tval, double dval) +{ + tval->tv_sec = (long int) dval; + tval->tv_usec = (long int) ((dval - tval->tv_sec) * 1000000); +} + +inline double wfa_ftime_diff(struct timeval *t1, struct timeval *t2) +{ + double dtime; + + dtime = wfa_timeval2double(t2) - wfa_timeval2double(t1); + return dtime ; +} + +int wfa_itime_diff(struct timeval *t1, struct timeval *t2) +{ + int dtime; + int sec = t2->tv_sec - t1->tv_sec; + int usec = t2->tv_usec - t1->tv_usec; + + if(usec < 0) + { + sec -=1; + usec += 1000000; + } + + dtime = sec*1000000 + usec; + return dtime; +} + + +/* + * THe following two functions are converting Little Endian to Big Endian. + * If your machine is already a Big Endian, you may flag it out. + */ +inline void int2BuffBigEndian(int val, char *buf) +{ + char *littleEn = (char *)&val; + + buf[0] = littleEn[3]; + buf[1] = littleEn[2]; + buf[2] = littleEn[1]; + buf[3] = littleEn[0]; +} + +int bigEndianBuff2Int(char *buff) +{ + int val; + char *strval = (char *)&val; + + strval[0] = buff[3]; + strval[1] = buff[2]; + strval[2] = buff[1]; + strval[3] = buff[0]; + + return val; +} + + +/* + * The following functions will execute the function by calling asd_Config + * and results are captured in strstrParams. + * The stderr is captured in temporary file. + */ + +int +asd_Config_wmm(char *strFunct, char *strstrParams) +{ + FILE *pipe_fp, *err_fp; + char temp[280]; + int stat, err_file_size, newErrFd; + + if ((err_fp = fopen(TEMP_STD_ERR_FILE, "w+")) == NULL) { + DPRINT_ERR(WFA_ERR, "\nFile open error\n"); + return -1; + } + newErrFd = DUP(STD_ERR); + + if ((stat = DUP2(fileno(err_fp), STD_ERR)) == -1) { + DPRINT_ERR(WFA_ERR, "Error in dup2(fd, STD_ERR) \n"); + return 0; + } + + sprintf(strFunct, "%s > %s", strFunct, strstrParams); + + /* Execute the command */ + if((pipe_fp = asd_Config(strFunct, strstrParams)) == NULL){ + DPRINT_ERR(WFA_ERR, "asd_Config_wmm:: Error in executing asd_Config\n"); + return -1; + } + fflush(stderr); + fgets(temp, sizeof(temp), pipe_fp); + Cleanup_File(pipe_fp); + + /* obtain error file size */ + if (fseek(err_fp, 0, SEEK_END) < 0) + return -1; + err_file_size = ftell(err_fp); + fclose(err_fp); + + if ((stat = DUP2(newErrFd, STD_ERR)) == -1) { + DPRINT_ERR(WFA_ERR, "Error in dup2(newErrFd, STD_ERR) \n"); + return 0; + } + + return err_file_size; +} + +/* + * The following functions will execute the function by calling exec_process + * The stderr is captured in temporary file. + */ + +int +exec_wmmCmd(char* command) +{ + int newErrFd, stat, file_size; + FILE *fp; + + fp = fopen(TEMP_STD_ERR_FILE, "w+"); + if ((newErrFd = DUP(STD_ERR)) == -1) { + DPRINT_ERR(WFA_ERR, "\nError in dup(2)\n"); + return newErrFd; + } + + if ((stat = DUP2(fileno(fp), STD_ERR)) == -1) { + DPRINT_ERR(WFA_ERR, "\nError in dup2(fd, 2)\n"); + return stat; + } + + exec_process(command); + + /* obtain file size */ + fflush(stderr); + if (fseek(fp, 0, SEEK_END) < 0) + file_size = 0; + file_size = ftell(fp); + fclose(fp); + + if ((stat = DUP2(newErrFd, STD_ERR)) == -1) { + DPRINT_ERR(WFA_ERR, "\nError in dup2(newErrFd, 2)\n"); + return stat; + } + return file_size; +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_miscs_linux.c b/src/tools/Wifi_ASD_test/lib/wfa_miscs_linux.c new file mode 100755 index 0000000..fc9f794 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_miscs_linux.c
@@ -0,0 +1,260 @@ +/* + * Linux port of asd command line utility + * + * Copyright 2002, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied or + * duplicated in any form, in whole or in part, without the prior written + * permission of Broadcom Corporation. + * + */ +#include <arpa/inet.h> +#include <strings.h> +#include <sys/socket.h> +#include <unistd.h> +#include <linux/if.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/utsname.h> +#include <sys/types.h> +#include <sys/wait.h> +#include "wfa_debug.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_tg.h" +#include "wfa_miscs.h" +#include "wfa_cmds.h" + +#ifndef SIOCGIWNAME +#define SIOCGIWNAME 0x8B01 +#endif +extern unsigned short wfa_defined_debug; +extern tgStream_t *theStreams; +extern char PingStr[]; +tgStream_t *findStreamProfile(int id); +void +asd_sleep(int SleepTime) +{ + + sleep(SleepTime); + +} + +void +uapsd_sleep(int SleepTime) +{ + + usleep(SleepTime); + +} + +void +asd_closeSocket(int sockfd) +{ + close(sockfd); + +} +void +asd_shutDown(int Sockfd) +{ + shutdown(Sockfd, SHUT_WR); + +} +void +exec_process(char* command) +{ + system(command); +} + +int +Start_Socket_Service() +{ + return 0; +} +int +Stop_Socket_Service() +{ + return 0; +} + +void +wfaGetSockOpt(int sockfd, int* tosval, socklen_t* size) +{ + getsockopt(sockfd, IPPROTO_IP, IP_TOS, tosval, size); +} + +int +wfaSetSockOpt(int sockfd, int* tosval, int size) +{ + int sockOpt; + sockOpt = setsockopt(sockfd, IPPROTO_IP, IP_TOS, tosval, size); + return sockOpt; +} + +int +wfa_estimate_timer_latency() +{ + struct timeval t1, t2, tp2; + int sleep=20000; /* two miniseconds */ + int latency =0; + + gettimeofday(&t1, NULL); + usleep(sleep); + + gettimeofday(&t2, NULL); + + tp2.tv_usec = t1.tv_usec + 20000; + if( tp2.tv_usec >= 1000000) + { + tp2.tv_sec = t1.tv_sec +1; + tp2.tv_usec -= 1000000; + } + else + tp2.tv_sec = t1.tv_sec; + + return latency = (t2.tv_sec - tp2.tv_sec) * 1000000 + (t2.tv_usec - tp2.tv_usec); +} + +/* This function returns the wireless adapter in Linux systems. + * This is for getting wireless adapter name programmatically */ +void +GetWirelessAdapter(char *adapter_name) +{ + char buf[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int sck; + int nInterfaces; + int i; + struct utsname name; + uname(&name); + /* Checking for x86 architecture */ + if (!strcmp(name.machine, "i386") || !strcmp(name.machine, "i686") || !strcmp(name.machine, "i586")) { + + /* Get a socket handle. */ + sck = socket(AF_INET, SOCK_DGRAM, 0); + if (sck < 0) { + perror("socket"); + return ; + } + + /* Query available interfaces. */ + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl(sck, SIOCGIFCONF, &ifc) < 0) { + perror("ioctl(SIOCGIFCONF)"); + close (sck); + return ; + } + + /* Iterate through the list of interfaces. */ + ifr = ifc.ifc_req; + nInterfaces = ifc.ifc_len / sizeof(struct ifreq); + for (i = 0; i < nInterfaces; i++) { + struct ifreq *item = &ifr[i]; + if (ioctl(sck, SIOCGIWNAME, item) == 0) { + strncpy(adapter_name,item->ifr_name, sizeof(item->ifr_name)); + close(sck); + return; + } + } + close (sck); + } +#ifdef TARGETENV_android + else { /* If its android */ + strncpy (adapter_name, "eth0", 15); + } +#else + else { /* If its ARM */ + strncpy (adapter_name,"eth1", 15); + } +#endif + return; + +} + + + +FILE* +asd_Config(char *strFunct, char *strstrParams) +{ + FILE* fp = NULL; + if ((fp = popen(strFunct, "r")) == NULL) { + printf("popen failed\n"); + return NULL; + } + return fp; +} +void +Cleanup_File(FILE* fp) +{ + pclose(fp); +} + +int exec_process_cnclient (char *buf, char *rwl_client_path, int rwl_wifi_flag) +{ + int pid, status,timeout_count = 30; + FILE *tmpfd; + char gCmdStr[WFA_CMD_STR_SZ]; + + if (rwl_wifi_flag) { + pid = fork(); + if (pid == 0) { + if ((status=execl (SH_PATH, "sh", "-c", buf, NULL)) == -1) + exit (1); + } + /*The server can be in different channel after association + *Hence we issue a findserver and then find out if it has + *been associated to return the right status + */ + asd_sleep(3); + sprintf(gCmdStr, "%s findserver", rwl_client_path); + pid = fork(); + if (pid == 0) { + if ((status=execl (SH_PATH, "sh", "-c", gCmdStr, NULL)) == -1) + exit (1); + } + waitpid(pid,&status,0); + } + else { + pid = fork(); + if (pid == 0) { + if ((status=execl (SH_PATH, "sh", "-c", buf, NULL)) == -1) + exit (1); + } + waitpid(pid,&status,0); + } + /* while cnClient associates in the child, parent looks + * for association if it has happened + * If it has not associated within a loop of 30, it comes out + * as not associated + */ + while(timeout_count > 0){ + sprintf(gCmdStr, "%s assoc | wc -l", rwl_client_path); + if((tmpfd = asd_Config(gCmdStr,TEMP_FILE_PATH)) == NULL){ + DPRINT_ERR(WFA_ERR, "\nassoc failed\n"); + return FALSE; + } + fgets(gCmdStr, sizeof(gCmdStr), tmpfd); + /* Short response means not associated */ + if (atoi(gCmdStr) > 2) + break; + /* End: Added as per BRCM 1.3 ASD */ + Cleanup_File(tmpfd); + asd_sleep(1); + timeout_count--; + } + if(timeout_count) + return TRUE; + else + return FALSE; +} + +void p_error(char *errorString) +{ + perror(errorString); +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_miscs_win32.c b/src/tools/Wifi_ASD_test/lib/wfa_miscs_win32.c new file mode 100755 index 0000000..f7acd69 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_miscs_win32.c
@@ -0,0 +1,609 @@ +/* + * Windows port of asd command line utility + * + * Copyright 2002, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied or + * duplicated in any form, in whole or in part, without the prior written + * permission of Broadcom Corporation. + * + */ + +#include <Winsock2.h> +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <tchar.h> + + +#include "wfa_debug.h" +#include "wfa_sock.h" +#include "wfa_main.h" +#include "wfa_types.h" +#include "wfa_tg.h" +#include "wfa_miscs.h" +#include "wfa_cmds.h" + +#ifndef SIOCGIWNAME +#define SIOCGIWNAME 0x8B01 +#endif + +#define RECV_OFFSET 22 + +extern unsigned short wfa_defined_debug; +extern tgStream_t *theStreams; +extern char PingStr[]; +tgStream_t *findStreamProfile(int id); +HANDLE processHandle = NULL; +HANDLE processThread = NULL; + +void +asd_sleep(int SleepTime) +{ + + Sleep(SleepTime * 1000); + +} + +void +uapsd_sleep(int SleepTime) +{ + + usleep(SleepTime/1000); + +} + +void +asd_closeSocket(int sockfd) +{ + closesocket(sockfd); + +} + +void +asd_shutDown(int Sockfd) +{ + + shutdown(Sockfd, SD_SEND); +} + +void +wfaGetSockOpt(int sockfd, int* tosval, socklen_t* size) +{ + getsockopt(sockfd, IPPROTO_IP, IP_TOS, (char FAR*)tosval, size); +} + +int +wfaSetSockOpt(int sockfd, int* tosval, int size) +{ + int sockOpt; + sockOpt = setsockopt(sockfd, IPPROTO_IP, IP_TOS, (char FAR*)tosval, size); + return sockOpt; +} + +int +exec_process_cnclient (char *buf, char *rwl_client_path, int rwl_wifi_flag) +{ + unsigned int position; + char gCmdStr[WFA_CMD_STR_SZ]; + int timeout_count = 30; + FILE *tmpfd; + /* Create Process related variables */ + PROCESS_INFORMATION ProcessInfo; + char Args[WFA_BUFF_512]; + TCHAR pDefaultCMD[WFA_BUFF_512]; + STARTUPINFO StartupInfo; + + if (rwl_wifi_flag){ + /*The server can be in different channel after association + *Hence we issue a findserver and then find out if it has + *been associated to return the right status + */ + + memset(Args, 0, WFA_BUFF_512); + sprintf(Args, "%s", (const char *)buf); + memset(&ProcessInfo, 0, sizeof(ProcessInfo)); + memset(&StartupInfo, 0, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + /* "/C" option - Do the command and EXIT the command processor */ + _tcscpy(pDefaultCMD, _T("cmd.exe /C ")); + _tcscat(pDefaultCMD, Args); + if(!CreateProcess(NULL,(LPTSTR)pDefaultCMD, NULL,NULL,FALSE,FALSE,NULL,NULL, + &StartupInfo,&ProcessInfo)){ + processHandle = ProcessInfo.hProcess; + processThread = ProcessInfo.hThread; + return FALSE; + } + asd_sleep(3); + sprintf(gCmdStr, "%s findserver", rwl_client_path); + exec_process(gCmdStr); + } + else { + exec_process(buf); + } + + /* while cnClient associates in the child, parent looks + * for association if it has happened + * If it has not associated within a loop of 30, it comes out + * as not associated + */ + while(timeout_count > 0){ + strcpy(gCmdStr, rwl_client_path); + strcat(gCmdStr, " assoc >"); + if((tmpfd = asd_Config(gCmdStr,TEMP_FILE_PATH)) == NULL){ + DPRINT_ERR(WFA_ERR, "\nassoc failed\n"); + return FALSE; + } + if((FileSearch(tmpfd, L"Not associated", &position))== -1) { + Cleanup_File(tmpfd); + break; + } + Cleanup_File(tmpfd); + asd_sleep(1); + timeout_count--; + } + if(timeout_count) + return TRUE; + else + return FALSE; +} + +void +exec_process(char* command) +{ + char wl_cmd[WFA_BUFF_256]; + memset(wl_cmd,0,sizeof(wl_cmd)); + strncpy(wl_cmd, command, strlen(command)); + DPRINT_INFO(WFA_OUT,"%s\n",wl_cmd); + asd_Config(wl_cmd," "); +} + +int +Start_Socket_Service() +{ + int err = 0; + WORD wVersionRequested; + WSADATA wsaData; + /* Initialize winsock library */ + wVersionRequested = MAKEWORD( 2, 2 ); + err = WSAStartup(wVersionRequested, &wsaData); + return err; +} + +int +Stop_Socket_Service() +{ + return WSACleanup(); +} + +char * strtok_r(char *s1, const char *s2, char **lasts) +{ + char *ret; + + if (s1 == NULL) + s1 = *lasts; + + while(*s1 && strchr(s2, *s1)) + ++s1; + + if(*s1 == '\0') + return NULL; + + ret = s1; + + while(*s1 && !strchr(s2, *s1)) + ++s1; + + if(*s1) + *s1++ = '\0'; + + *lasts = s1; + + return ret; +} + +int strcasecmp(const char *s1, const char *s2) +{ + const unsigned char *us1 = (const unsigned char *)s1; + const unsigned char *us2 = (const unsigned char *)s2; + + while (tolower(*us1) == tolower(*us2)) { + if (*us1++ == '\0') + return (0); + us2++; + } + return (tolower(*us1) - tolower(*us2)); +} + +int strncasecmp(const char *s1,const char *s2, unsigned int length) +{ + unsigned char u1, u2; + + for (; length != 0; length--, s1++, s2++) { + u1 = (unsigned char) *s1; + u2 = (unsigned char) *s2; + + if (tolower(u1) != tolower(u1)) { + return tolower(u1) - tolower(u1); + } + if (u1 == '\0') { + return 0; + } + } + return 0; +} + +__inline int wmemcmp(const wchar_t *_S1, const wchar_t *_S2, size_t _N) + {for (; 0 < _N; ++_S1, ++_S2, --_N) + if (*_S1 != *_S2) + return (*_S1 < *_S2 ? -1 : +1); + return (0); } +__inline wchar_t *wmemcpy(wchar_t *_S1, const wchar_t *_S2, size_t _N) + {wchar_t *_Su1 = _S1; + for (; 0 < _N; ++_Su1, ++_S2, --_N) + *_Su1 = *_S2; + return (_S1); } +__inline wchar_t *wmemmove(wchar_t *_S1, const wchar_t *_S2, size_t _N) + {wchar_t *_Su1 = _S1; + if (_S2 < _Su1 && _Su1 < _S2 + _N) + for (_Su1 += _N, _S2 += _N; 0 < _N; --_N) + *--_Su1 = *--_S2; + else + for (; 0 < _N; --_N) + *_Su1++ = *_S2++; + return (_S1); } +__inline wchar_t *wmemset(wchar_t *_S, wchar_t _C, size_t _N) + {wchar_t *_Su = _S; + for (; 0 < _N; ++_Su, --_N) + *_Su = _C; + return (_S); } + +int GetPingStat(FILE* pFile, const wchar_t* lpszSearchString , unsigned int *recv,unsigned int *sent, const char* delim) +{ + unsigned long ulFileSize, ulBufferSize; + wchar_t lpBuffer[WFA_BUFF_512]; + char mbsbuffer[WFA_BUFF_512], str[WFA_BUFF_128]; + unsigned int *ulCurrentPosition, *ulReceived, *ulsent; + int retval; + + ulCurrentPosition=recv; + ulReceived= recv; + ulsent = sent; + + //make sure we were passed a valid, if it isn't return -1 + if ((!pFile)||(!lpszSearchString)) { + return -1; + } + + //get the size of the file + fseek(pFile,0,SEEK_END); + + ulFileSize=ftell(pFile); + + fseek(pFile,0,SEEK_SET); + + //if the file is empty return -1 + if (!ulFileSize) { + return -1; + } + + //get the length of the string we're looking for, this is + //the size the buffer will need to be + ulBufferSize=wcslen(lpszSearchString); + + if (ulBufferSize>ulFileSize) { + return -1; + } + + *ulCurrentPosition=0; + + //this is where the actual searching will happen, what happens + //here is we set the file pointer to the current position + //is incrimented by one each pass, then we read the size of + //the buffer into the buffer and compare it with the string + //we're searching for, if the string is found we return the + //position at which it is found + while (*ulCurrentPosition<ulFileSize-ulBufferSize) { + fseek(pFile,*ulCurrentPosition,SEEK_SET); + wmemset(lpBuffer, 0, WFA_BUFF_512); + //read ulBufferSize bytes from the file + fread(mbsbuffer,1,ulBufferSize,pFile); + + retval = mbstowcs(lpBuffer, mbsbuffer, strlen(mbsbuffer)); + + //if the data read matches the string we're looking for + //read from the offset where recieve data starts + if (!wmemcmp(lpBuffer, lpszSearchString, ulBufferSize)) { + fread(str, 1, RECV_OFFSET, pFile); + *ulReceived = atoi(str); + strtok(str, (const char*)ulReceived); + //fread(str,1,ulBufferSize,pFile); + //strtok(str, delim); + *ulsent= atoi(str); + //return the position the string was found at + return *ulCurrentPosition; + } + + ++*ulCurrentPosition; + } + return -1; +} + +int GetStats(FILE* pFile, const wchar_t* lpszSearchString , unsigned int *pos, const char* delim) +{ + + char* lpBuffer; + char* str; + char mbsString[128]; + unsigned long ulFileSize, ulBufferSize; + unsigned int *ulCurrentPosition; + ulCurrentPosition = pos; + + memset(mbsString, 0, 128); + /* convert the wide character search string to multibyte */ + wcstombs(mbsString,lpszSearchString, wcslen(lpszSearchString) ); + /* make sure we were passed a valid, if it isn't return -1 */ + if ((!pFile)||(!lpszSearchString)) { + return -1; + } + + /* get the size of the file */ + fseek(pFile,0,SEEK_END); + + ulFileSize=ftell(pFile); + + fseek(pFile,0,SEEK_SET); + + /* if the file is empty return -1 */ + if (!ulFileSize) { + return -1; + } + + /* get the length of the string we're looking for, this is + * the size the buffer will need to be */ + ulBufferSize=wcslen(lpszSearchString); + + if (ulBufferSize>ulFileSize) { + return -1; + } + /* allocate the memory for the buffer */ + lpBuffer=(char*)malloc(strlen(mbsString)); + str = (char*)malloc(strlen(mbsString)); + /* if malloc() returned a null pointer (which probably means + * there is not enough memory) then return -1 */ + if (!lpBuffer ) + { + return -1; + } + *ulCurrentPosition=0; + + /* this is where the actual searching will happen, what happens + * here is we set the file pointer to the current position + * is incrimented by one each pass, then we read the size of + * the buffer into the buffer and compare it with the string + * we're searching for, if the string is found we return the + * position at which it is found */ + + while (*ulCurrentPosition<ulFileSize-ulBufferSize) { + fseek(pFile,*ulCurrentPosition,SEEK_SET); + /* if the data read matches the string we're looking for */ + fread(lpBuffer,1,ulBufferSize,pFile); + if (!memcmp(lpBuffer,mbsString,ulBufferSize)) + { + fread(str,1,ulBufferSize,pFile); + strtok(str, delim); + *ulCurrentPosition = atoi(str); + + /* free the buffer */ + if(lpBuffer != NULL || str != NULL){ + free(lpBuffer); + free(str); + } + /* return the position the string was found at */ + return *ulCurrentPosition; + } + /* incriment the current position by one */ + ++*ulCurrentPosition; + } + + /* if we made it this far the string was not found in the file + * so we free the buffer */ + if(lpBuffer != NULL || str != NULL){ + free(str); + free(lpBuffer); + } + return -1; +} + +int FileSearch(FILE* pFile, const wchar_t* lpszSearchString , unsigned int *pos) +{ + + char* lpBuffer; + char mbsString[128]; + unsigned long ulFileSize = 0, ulBufferSize; + unsigned long *ulCurrentPosition; + ulCurrentPosition= pos; + memset(mbsString, 0, 128); + /* convert the wide character search string to multibyte */ + wcstombs(mbsString,lpszSearchString, wcslen(lpszSearchString) ); + /* make sure we were passed a valid, if it isn't return -1 */ + if ((!pFile)||(!lpszSearchString)) { + return -1; + } + + /* get the size of the file */ + fseek(pFile,0,SEEK_END); + + ulFileSize=ftell(pFile); + + fseek(pFile,0,SEEK_SET); + + /* if the file is empty return -1 */ + if (!ulFileSize) { + return -1; + } + + /* get the length of the string we're looking for, this is + * the size the buffer will need to be */ + ulBufferSize=wcslen(lpszSearchString); + + if (ulBufferSize > ulFileSize) { + return -1; + } + + /* allocate the memory for the buffer */ + lpBuffer=(char*)malloc(strlen(mbsString)); + /* if malloc() returned a null pointer (which probably means + * there is not enough memory) then return -1 */ + + if (!lpBuffer ) + { + return -1; + } + *ulCurrentPosition=0; + + /* this is where the actual searching will happen, what happens + * here is we set the file pointer to the current position + * is incrimented by one each pass, then we read the size of + * the buffer into the buffer and compare it with the string + * we're searching for, if the string is found we return the + * position at which it is found */ + while (*ulCurrentPosition<ulFileSize-ulBufferSize) { + fseek(pFile,*ulCurrentPosition,SEEK_SET); + /* if the data read matches the string we're looking for */ + fread(lpBuffer,1,ulBufferSize,pFile); + if (!memcmp(lpBuffer,mbsString,ulBufferSize)) + { + /* free the buffer */ + if(lpBuffer != NULL) + free(lpBuffer); + /* return the position the string was found at */ + return *ulCurrentPosition; + } + + /* incriment the current position by one */ + ++*ulCurrentPosition; + } + /* if we made it this far the string was not + * found in the file so we free the buffer */ + if(lpBuffer != NULL) + free(lpBuffer); + return -1; +} + +unsigned int uGetLocalIP() +{ + char szHostName[WFA_BUFF_256]; + struct hostent* HostData; + + GetHostName(szHostName, WFA_BUFF_256); + HostData = gethostbyname(szHostName); + if (HostData == NULL) + return 0; + + return *((unsigned int*)HostData->h_addr); +} + +char* GetHostName(char* buf, int len) +{ + if (gethostname(buf, len) == SOCKET_ERROR) + return NULL; + return buf; +} + +int wfa_Winitime_diff(SYSTEMTIME *t1, SYSTEMTIME *t2) +{ + int dtime; + int sec = t2->wSecond - t1->wSecond; + int msec = (t2->wMilliseconds - t1->wMilliseconds); + + if(msec < 0) + { + sec -=1; + msec += 1000; + } + + dtime = sec*1000 + msec; + return dtime; +} + +int wfa_Win_estimate_timer_latency() +{ + SYSTEMTIME t1, t2, tp2; + int sleep =2; + int latency =0; + + GetSystemTime(&t1); + usleep(sleep); + + GetSystemTime(&t2); + + tp2.wMilliseconds = t1.wMilliseconds +20; + if( tp2.wMilliseconds >= 1000) { + tp2.wSecond = t1.wSecond +1; + tp2.wMilliseconds -= 1000; + } + else + tp2.wSecond = t1.wSecond; + + return latency = (t2.wSecond - tp2.wSecond) + (t2.wMilliseconds - tp2.wMilliseconds); +} + + +FILE* asd_Config(char *strFunct, char *strstrParams) +{ + FILE* fp = NULL; + PROCESS_INFORMATION ProcessInfo; + char Args[WFA_BUFF_512]; + TCHAR pDefaultCMD[WFA_BUFF_512]; + STARTUPINFO StartupInfo; + ULONG rc; + + Args[0]= 0; + memset(Args, 0, WFA_BUFF_512); + sprintf(Args, "%s %s", (const char *)strFunct, (const char *)strstrParams); + memset(&ProcessInfo, 0, sizeof(ProcessInfo)); + memset(&StartupInfo, 0, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + /* "/C" option - Do the command and EXIT the command processor */ + _tcscpy(pDefaultCMD, _T("cmd.exe /C ")); + _tcscat(pDefaultCMD, Args); + + if(!CreateProcess(NULL,(LPTSTR)pDefaultCMD, NULL,NULL,FALSE,FALSE,NULL,NULL,&StartupInfo,&ProcessInfo)) + { + processHandle = ProcessInfo.hProcess; + processThread = ProcessInfo.hThread; + printf("CreateProcess function failed\n"); + return NULL; + } + + WaitForSingleObject(ProcessInfo.hProcess, INFINITE); + if(!GetExitCodeProcess(ProcessInfo.hProcess, &rc)) + rc = 0; + + CloseHandle(ProcessInfo.hThread); + CloseHandle(ProcessInfo.hProcess); + if(strlen(strstrParams) > 1){ + if((fp = fopen(TEMP_FILE_PATH, "r+")) == NULL){ + printf("fopen failed\n"); + return NULL; + } + } + return fp; +} + +void Cleanup_File(FILE* fp) +{ + fclose(fp); + if (!DeleteFile(TEMP_FILE_PATH)) { + printf("DeleteFile Failed with error:%d\n",GetLastError()); + } +} + +void p_error(char *errorString) +{ + printf("%s %d",errorString, GetLastError()); +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_sock.c b/src/tools/Wifi_ASD_test/lib/wfa_sock.c new file mode 100644 index 0000000..d60566d --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_sock.c
@@ -0,0 +1,594 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + +/* + * File: wfa_sock.c + * library functions for TCP and UDP socket creations and handling + * They are common library and shared by DUT, TC and CA. + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA release by qhu + * 2006/06/13 -- 00.02 release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/09/01 -- 01.05 Release by qhu + * 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * -- add a compilation flags to wmmfds and wmmps to setFileDesc() + * that match the defintions in wfa_dut.c reported by rmaeder. + * + */ +#ifndef WIN32 +#include <pthread.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <unistd.h> +#include <linux/if.h> +#include <sys/ioctl.h> +#include <sched.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <bcmendian.h> +#ifdef TARGETENV_android +#include <asm/mman.h> +#else +#include <sys/mman.h> +#endif +#endif + + +#include "wfa_debug.h" +#include "wfa_types.h" +#include "wfa_main.h" +#include "wfa_sock.h" +#include "wfa_miscs.h" + +int wfaGetifAddr(char *ifname, struct sockaddr_in *sa); + +extern unsigned short wfa_defined_debug; + +extern BOOL gtgTransac; +extern char gnetIf[]; + +#ifndef MAXPENDING +#define MAXPENDING 2 /* Maximum outstanding connection requests */ +#endif +#ifdef TARGETENV_android +/* These functions are defined inside sys/mman.h for linux + * For android we are defining here as dummy + */ +int mlockall(int flags) +{ + return 0; +} +int munlockall(void) +{ + return 0; +} +#endif + +/* + * wfaCreateTCPServSock(): initially create a TCP socket + * intput: port -- TCP socket port to listen + * return: socket id; + */ +int wfaCreateTCPServSock(unsigned short port) +{ + int sock; /* socket to create */ + struct sockaddr_in servAddr; /* Local address */ + const int on = 1; + + /* Create socket for incoming connections */ + if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + DPRINT_ERR(WFA_ERR, "createTCPServSock socket() failed"); + return FALSE; + } + + /* Construct local address structure */ + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; /* Internet address family */ + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + servAddr.sin_port = htons(port); /* Local port */ + + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); + /* Bind to the local address */ + if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) + { + DPRINT_ERR(WFA_ERR, "bind() failed"); + return FALSE; + } + + /* Mark the socket so it will listen for incoming connections */ + if (listen(sock, MAXPENDING) < 0) + { + DPRINT_ERR(WFA_ERR, "listen() failed"); + return FALSE; + } + + return sock; +} + +/* + * wfaCreateUDPSock(): create a UDP socket + * input: + ipaddr -- local ip address for test traffic + port -- UDP port to receive and send + * return: socket id + */ +int wfaCreateUDPSock(char *ipaddr, unsigned short port) +{ + int udpsock; /* socket to create */ + struct sockaddr_in servAddr; /* Local address */ +#ifdef WIN32 + if((udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) +#else + if((udpsock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) +#endif + { + DPRINT_ERR(WFA_ERR, "createUDPSock socket() failed"); + return FALSE; + } + + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + DPRINT_INFO(WFA_OUT, "UDP port %i\n", port); + servAddr.sin_port = htons(port); + + bind(udpsock, (struct sockaddr *) &servAddr, sizeof(servAddr)); + + return udpsock; +} + +int wfaSetSockMcastSendOpt(int sockfd) +{ +#ifdef WIN32 + int ttlval = 64; + DPRINT_INFO(WFA_OUT, "MCAST: McastSendOpt: sockfd = %d\r\n",sockfd); + return setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttlval, sizeof(int)); + +#else + unsigned char ttlval = 1; + return setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttlval, sizeof(ttlval)); + +#endif + +} + +int wfaSetSockMcastRecvOpt(int sockfd, char *mcastgroup) +{ + struct ip_mreq mcreq; + int so; + + mcreq.imr_multiaddr.s_addr = inet_addr(mcastgroup); +#ifdef WIN32 + mcreq.imr_interface.s_addr = INADDR_ANY; +#else + mcreq.imr_interface.s_addr = htonl(INADDR_ANY); +#endif +#ifdef DEBUG + DPRINT_INFO(WFA_OUT, "MCAST: McastRecvOpt: mcastgroup = %s\r\n",mcastgroup); +#endif + so = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (void *)&mcreq, sizeof(mcreq)); + return so; +} + +int wfaConnectUDPPeer(int mysock, char *daddr, unsigned short dport) +{ + struct sockaddr_in peerAddr; + + memset(&peerAddr, 0, sizeof(peerAddr)); + peerAddr.sin_family = AF_INET; +#ifndef WIN32 + inet_aton(daddr, &peerAddr.sin_addr); +#else + peerAddr.sin_addr.s_addr = inet_addr(daddr); +#endif + + peerAddr.sin_port = htons(dport); + + connect(mysock, (struct sockaddr *)&peerAddr, sizeof(peerAddr)); + return mysock; +} + +int wfaConnectTCPPeer(unsigned short sport, char *daddr, unsigned short dport) +{ + int tcpsock; /* socket to create */ + struct sockaddr_in servAddr; /* Local address */ + struct sockaddr_in peerAddr; /* peer address */ +#ifdef WIN32 + if((tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) +#else + if((tcpsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) +#endif + { + DPRINT_ERR(WFA_ERR, "wfaConnectTCPPeer socket() failed"); + return FALSE; + } + + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(sport); + + if(bind(tcpsock, (struct sockaddr *) &servAddr, sizeof(servAddr)) == -1) + { + DPRINT_ERR(WFA_ERR, "createTCPPeer bind() failed"); + return FALSE; + } + + + memset(&peerAddr, 0, sizeof(peerAddr)); + peerAddr.sin_family = AF_INET; + +#ifndef WIN32 + inet_aton(daddr, &peerAddr.sin_addr); +#else + peerAddr.sin_addr.s_addr = inet_addr(daddr); +#endif + peerAddr.sin_port = htons(dport); + + if(connect(tcpsock, (struct sockaddr *)&peerAddr, sizeof(peerAddr)) == -1) + { + DPRINT_ERR(WFA_ERR, "wfaConnectTCPPeer connect() failed"); + return FALSE; + } + return tcpsock; +} + +/* + * acceptTCPConn(): handle and accept any incoming socket connection request. + * input: serSock -- the socket id to listen + * return: the connected socket id. + */ +int wfaAcceptTCPConn(int servSock) +{ + int clntSock; /* Socket descriptor for client */ + struct sockaddr_in clntAddr; /* Client address */ + unsigned int clntLen; /* Length of client address data structure */ + + /* Set the size of the in-out parameter */ + clntLen = sizeof(clntAddr); + + /* Wait for a client to connect */ + if ((clntSock = accept(servSock, (struct sockaddr *) &clntAddr, + &clntLen)) < 0) + { + DPRINT_ERR(WFA_ERR, "accept() failed"); + exit(1); + } + + /* clntSock is connected to a client! */ + return clntSock; +} + +struct timeval *wfaSetTimer(int secs, int usecs, struct timeval *tv) +{ + struct timeval *mytv; + + if(gtgTransac != 0) + { + tv->tv_sec = secs ; /* timeout (secs.) */ + tv->tv_usec = usecs; /* 0 microseconds */ + } + else + { + tv->tv_sec = 0; + tv->tv_usec = 0; /* 0 microseconds */ + } + + if(tv->tv_sec == 0 && tv->tv_usec == 0) + mytv = NULL; + else + mytv = tv; + + return mytv; +} + +/* this only set four file descriptors, the main agent fd, control agent + * port fd and traffic generation fd, traffic generator fd. + */ +void wfaSetSockFiDesc(fd_set *fdset, int *maxfdn1, struct sockfds *fds) +{ + + int i; + + + FD_ZERO(fdset); + if(fdset != NULL) + FD_SET(*fds->agtfd, fdset); + + /* if the traffic generator socket port valid */ + if(*fds->tgfd > 0) + { + FD_SET(*fds->tgfd, fdset); + *maxfdn1 = max(*maxfdn1-1, (int)*fds->tgfd) + 1; + } + + /* if the traffic generator socket Recv port valid */ + if(*fds->tgRevfd > 0) + { + FD_SET(*fds->tgRevfd, fdset); + *maxfdn1 = max(*maxfdn1-1, (int)*fds->tgRevfd) + 1; + } + + + /* if the control agent socket fd valid */ + if(*fds->cafd >0) + { + FD_SET(*fds->cafd, fdset); + *maxfdn1 = max(*maxfdn1-1, (int)*fds->cafd) + 1; + } + + /* if any of wmm traffic stream socket fd valid */ + for(i = 0; i < WFA_MAX_TRAFFIC_STREAMS; i++) + { + if(fds->wmmfds[i] > 0) + { + if(fds->wmmfds[i] > FD_SETSIZE) + { + // DPRINT_INFO(WFA_OUT, "Size greater than FD_SETSIZE\r\n"); + } + FD_SET(fds->wmmfds[i], fdset); + *maxfdn1 = max(*maxfdn1-1, (int)fds->wmmfds[i]) +1; + } + } +#ifdef WFA_WMM_EXT +#ifdef WFA_WMM_PS_EXT + /* if the power save socket port valid */ + if(*fds->psfd > 0) + { + FD_SET(*fds->psfd, fdset); + *maxfdn1 = max(*maxfdn1-1, (int)*fds->psfd) + 1; + } +#endif + +#endif + return; +} + +/* + * wfaCtrlSend(): Send control message/response through + * control link. + * Note: the function used to wfaTcpSend(). + */ +int wfaCtrlSend(int sock, unsigned char *buf, int bufLen) +{ + int bytesSent = 0; + + if(bufLen == 0) + return FALSE; + if(buf == NULL) + DPRINT_INFO(WFA_OUT, "wfaCtrlSend: Buffer null\r\n"); + + bytesSent = send(sock, buf, bufLen, 0); + + if(bytesSent == -1) + { + DPRINT_WARNING(WFA_WNG, "Error sending tcp packet\n"); + } + + return bytesSent; +} + +/* + * wfaCtrlRecv(): Receive control message/response through + * control link. + * Note: the function used to wfaTcpRecv(). + */ +int wfaCtrlRecv(int sock, unsigned char *buf) +{ + int bytesRecvd = 0; + + bytesRecvd = recv(sock, buf, WFA_BUFF_1K-1, 0); + + return bytesRecvd; +} + +/* + * wfaTrafficSendTo(): Send Traffic through through traffic interface. + * Note: the function used to wfaUdpSendTo(). + */ +int wfaTrafficSendTo(int sock, char *buf, int bufLen, struct sockaddr *to) +{ + int bytesSent; + + bytesSent = sendto(sock, buf, bufLen, MSG_DONTWAIT, to, sizeof(struct sockaddr)); + + return bytesSent; +} + +/* + * wfaTrafficRecv(): Receive Traffic through through traffic interface. + * Note: the function used to wfaRecvSendTo(). + */ +int wfaTrafficRecv(int sock, char *buf, struct sockaddr *from) +{ + int bytesRecvd =0; + socklen_t addrLen; + +#ifdef WIN32 + struct sockaddr_in recFrom; +#endif + + /* get current flags setting */ +#ifndef WIN32 + int ioflags = fcntl(sock, F_GETFL, 0); + +#ifdef TARGETENV_android +if (gtgTransac) +usleep(50); +#endif + + /* set only BLOCKING flag to non-blocking */ + fcntl(sock, F_SETFL, ioflags | O_NONBLOCK); + + bytesRecvd = recvfrom(sock, buf, MAX_UDP_LEN, 0, from, &addrLen); +#ifdef TARGETENV_android +if (errno == EAGAIN && gtgTransac) +usleep(50); +#endif /* TARGETENV_android */ + +#else + + memset(&recFrom, 0, sizeof(recFrom)); + addrLen = sizeof(recFrom); + bytesRecvd = recvfrom(sock, buf, MAX_UDP_LEN, 0, (struct sockaddr *)&recFrom, &addrLen); +#endif + + return bytesRecvd; +} + +int wfaGetifAddr(char *ifname, struct sockaddr_in *sa) +{ + struct ifreq ifr; + int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + + if(fd < 0) + { + DPRINT_ERR(WFA_ERR, "socket open error\n"); + return FALSE; + } + + strncpy(ifr.ifr_name, ifname, strlen(ifname)); +#ifndef WIN32 + ifr.ifr_addr.sa_family = AF_INET; + if(ioctl(fd, SIOCGIFADDR, &ifr) == 0) + { + memcpy(sa, (struct sockaddr_in *)&ifr.ifr_addr, sizeof(struct sockaddr_in)); + } + else + { + return FALSE; + } + +#else + ifr.ifr_addr.sin_family = AF_INET; + memcpy(sa, (struct sockaddr_in *)&ifr.ifr_addr, sizeof(struct sockaddr_in)); +#endif + + asd_closeSocket(fd); + return FALSE; +} + +/* + * wfaSetProcPriority(): + * With the linux 2.6 kernel, it allows an application process dynamically + * adjust its running priority level. In order to achieve higher control of + * packet sending/receiving and timer response, it is helpful to raise the + * process priority level over others and lower it back once it finishes. + * + * This is purely used for performance tuning purpose and not required to + * port if it is not needed. + */ +int wfaSetProcPriority(int set) +{ +#ifndef WIN32 + int maxprio, currprio; + struct sched_param schp; + + memset(&schp, 0, sizeof(schp)); + sched_getparam(0, &schp); + + currprio = schp.sched_priority; + + if(set != 0) + { + if(geteuid() == 0) + { + maxprio = sched_get_priority_max(SCHED_FIFO); + if(maxprio == -1) + { + return FALSE; + } + + schp.sched_priority = maxprio; + if(sched_setscheduler(0, SCHED_FIFO, &schp) != 0) + { + } + } + + if(mlockall(MCL_CURRENT | MCL_FUTURE) != 0) + { + + } + } + else + { + if(geteuid() == 0) + { + schp.sched_priority = 0; + if(sched_setscheduler(0, SCHED_OTHER, &schp) != 0) + { + } + } + + munlockall(); + } + return currprio; +#else + return 0; +#endif + +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_tg.c b/src/tools/Wifi_ASD_test/lib/wfa_tg.c new file mode 100644 index 0000000..850444e --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_tg.c
@@ -0,0 +1,2474 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ +/* + * File: wfa_tg.c + * Library functions for traffic generator. + * They are shared with both TC and DUT agent. + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA release by qhu + * 2006/06/13 -- 00.02 release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/08/01 -- 01.03 fix ping result unreachable caused by random output + * timing. Add 2 seconds wait-time. + * change priority level to 40 max while traffic + * sending/receiving and 60 min for normal state. + * 2006/09/01 -- 01.05 Release by qhu + * 2006/10/26 -- 01.06 released by qhu + * 2006/10.20 -- bug fixes report by n. ojannen + * 2006/12/30 -- bug fix. a potential race condition for transaction test, * reported by c.benson. + * 2006/01/11 -- 01.10 released by qhu + * 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi + * 2007/03/15 -- develop a better rate control method for sendLong + * a major bug fix for File receive that opens socket with + * source port. It should be destination port. This was + * an early mistake because of interpretation. + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * -- revise the code for traffic throttled control + * -- take care of EAGAIN error return by socket sendto() -- suggested + * by tterhaar + */ +#ifndef WIN32 +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <sys/time.h> +#include <time.h> +#include <signal.h> +#include <fcntl.h> +#include <netdb.h> +#include <pthread.h> +#include <semaphore.h> +#else +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#endif /* !WIN32 */ +#include "wfa_debug.h" +#include "wfa_ver.h" +#include "wfa_main.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_cmds.h" +#include "wfa_sock.h" +#include "wfa_rsp.h" +#include "wfa_wmmps.h" +#include "wfa_types.h" +#include "wfa_miscs.h" + + +int usedThread = 0; +BYTE Send_dutResp[WFA_BUFF_512]; +extern void wfaSentStatsResp(BYTE*); +#ifndef WIN32 +tgWMM_t wmm_thr[WFA_THREADS_NUM]; +extern sem_t sem_wmm; +extern sem_t sem_wmm_resp; +extern sem_t sem_gtgrecv; +extern sem_t sem_iptv_gtgrecv[WFA_MAX_TRAFFIC_STREAMS]; +int gnumStreams; +pthread_t thrid[WFA_MAX_TRAFFIC_STREAMS]; +#else +extern HANDLE thr_flag_cond; +DWORD dwpingThread; +DWORD dwGenericThread; +HANDLE pinghThread = NULL; +HANDLE hTimerThread = NULL; +HANDLE hThread1 = NULL; +HANDLE hThread2 = NULL; +HANDLE g_hRecvEvent = NULL; +HANDLE send_event = NULL; +extern HANDLE g_RecvhThread; +extern HANDLE g_IPTVRecvhThread[WFA_MAX_TRAFFIC_STREAMS]; +HANDLE g_recvEvent[WFA_MAX_TRAFFIC_STREAMS]; +DWORD dwGenericThread2; +DWORD dwGenericThread1; +DWORD dwIPTVThread; +HANDLE g_TGSndThr[WFA_MAX_TRAFFIC_STREAMS]; +extern ULONG exitcode; +extern HANDLE processHandle; +extern void SendIPTVFile(LPVOID); +#endif /* !WIN32 */ +extern tgStream_t *gStreams; +extern BOOL gtgRecv; +extern BOOL gtgSend; +extern BOOL gtgTransac; +extern int btSockfd; +extern int btRecvSockfd; +extern int gTcpRecvSockfd; +extern int gTCPsock; +extern int gtimeOut; +extern int gRegSec; +extern int isExit; +extern int adj_latency; + +extern tgStream_t *findStreamProfile(int); +extern int wfaTrafficSendTo(int, char *, int, struct sockaddr *); +extern int wfaTrafficRecv(int, char *, struct sockaddr *); +extern unsigned short wfa_defined_debug; +extern int tgSockfds[]; + +extern int wfaTGSetPrio(int sockfd, int tgClass); +extern double min_rttime; +extern tgSyncTime_t gtgFinishSyncTime; +extern BOOL gtgStartSync; +extern BOOL gtgFinishSync; +extern tgE2EStats_t *e2eStats; +extern int e2eCnt; +extern void wfaRecvThrCreate(void); +extern void wfaIPTVRecvThrCreate(int); +extern void SendFile(void); +extern int IPTVprof; + + +extern tgSyncTime_t gtgStartSyncTime; +#ifdef WFA_WMM_EXT +extern tgWMM_t wmm_thr[]; + +#ifdef WFA_WMM_PS_EXT +extern int gtgWmmPS; +extern wfaWmmPS_t wmmps_info; +extern int psSockfd; +extern unsigned long psTxMsg[]; +extern unsigned long psRxMsg[]; +extern int gtgPsPktRecvd; + +dutCmdResponse_t gGenericResp; + +extern void wfaSetDUTPwrMgmt(int mode); +void wmmps_wait_state_proc(); + +#endif /* WFA_WMM_PS_EXT */ + +#endif /* WFA_WMM_EXT */ + +static int runLoop = 0; +extern volatile int gTransactrunLoop; +static int streamId = 0; +static int totalTranPkts = 0, sentTranPkts = 0; +static int slotCnt = 0; + +int clock_drift_ps = 0; // drift(usec) per second +char e2eResults[32]; + +extern dutCmdResponse_t gGenericResp; + +#ifdef WIN32 +unsigned int Timerid; +extern DWORD Win32_tmout_stop_send(LPVOID num ) ; +extern DWORD PingStart(); +char PingStr[WFA_BUFF_512]; + +#ifndef MAX_UDP_LEN +#define MAX_UDP_LEN 2048 +#endif /*MAX_UDP_LEN*/ + +#define HIGH_FRAME_RATE_VAL 500 +#define SLEEP_DENOMINATOR 5 +#endif /*WIN32*/ + +/* Some devices may only support UDP ECHO and do not have ICMP level ping */ +// #define WFA_PING_UDP_ECHO_ONLY 1 + +/* + * Each packet will have the header in the data field + */ + +void wfa_syncd_time(tgSyncTime_t *startTime, tgSyncTime_t *finishTime) +{ +#ifdef WFA_WMM_EXT +#ifndef WIN32 + DPRINT_INFO(WFA_OUT, "finish tm time %f start tm time %f\n", finishTime->tm_time, startTime->tm_time); + DPRINT_INFO(WFA_OUT, "finish dut time %f startTime dut time %f \n", finishTime->dut_time, startTime->dut_time); + + if(startTime->dtime > finishTime->dtime) + startTime->dtime = finishTime->dtime; + + DPRINT_INFO(WFA_OUT, "roundtrip delay time (usec): %i\n", (int) (1000000 * startTime->dtime)); + + clock_drift_ps = 1000000*( (finishTime->tm_time - startTime->tm_time)-(finishTime->dut_time - startTime->dut_time) ) / + (finishTime->dut_time - startTime->dut_time); + + DPRINT_INFO(WFA_OUT, "drift per second %i\n", clock_drift_ps); +#endif /* !WIN32 */ +#endif /* !WFA_WMM_EXT */ +} + +#ifndef WIN32 +/* this is to stop sending packets by timer */ +void tmout_stop_send(int num) +{ +#ifdef WFA_WMM_EXT + int i; +#endif /* WFA_WMM_EXT */ + DPRINT_INFO(WFA_OUT, "timer fired, stop sending traffic\n"); + + /* + * After runLoop reset, all sendLong will stop + */ + runLoop = 0; + gTransactrunLoop = 0; + +#ifdef WFA_WMM_EXT + /* + * once usedThread is reset, WMM tests using multithread is ended + * the threads will be reused for the next test. + */ + usedThread--; + //if(usedThread == 0) + sem_post(&sem_wmm_resp); +#endif /* WFA_WMM_EXT */ + + /* + * once the stream table slot count is reset, it implies that the test + * is done. When the next set profile command comes in, it will reset/clean + * the stream table. + */ + slotCnt = 0; + + /* + * The test is for DT3 transaction test. + * Timeout to stop it. + */ + if(gtgTransac != 0) + { + gtgSend = 0; + gtgRecv = 0; + gtgTransac = 0; + asd_closeSocket(btSockfd); + btSockfd = -1; +#ifdef WFA_WMM_EXT + /* Voice End 2 End Sync */ + min_rttime = 0xFFFFFFFF; + if(gtgStartSync != 0) + { + gtgStartSync = 0; + DPRINT_INFO(WFA_OUT, "stopping StartSync\n"); + } + + if(gtgFinishSync != 0) + { + /* derive the clock drift */ + wfa_syncd_time(>gStartSyncTime, >gFinishSyncTime); + + gtgFinishSync = 0; + DPRINT_INFO(WFA_OUT, "stoping Finish Sync\n"); + } +#endif /* WFA_WMM_EXT */ + } + +#ifdef WFA_WMM_EXT + /* + * all WMM streams also stop + */ + for(i=0; i<WFA_TRAFFIC_CLASS_NUM; i++) + { + wmm_thr[i].thr_flag = 0; + } +#endif /* WFA_WMM_EXT */ + /* all alarms need to reset */ + + alarm(0); +} +#endif /* !WIN32 */ +/* + * findStreamProfile(): search existing stream profile by stream id + * input: id - stream id; + * return: matched stream profile + */ +tgStream_t *findStreamProfile(int id) +{ + int i; + tgStream_t *myStream = gStreams; + + for(i = 0; i< WFA_MAX_TRAFFIC_STREAMS; i++) + { + if(myStream->id == id) + return myStream; + + myStream++; + } + + return NULL; +} + +/* + * wfaTGSendPing(): Instruct Traffic Generator to send ping packets + * + */ +int wfaTGSendPing(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int totalpkts; + + char cmdStr[WFA_BUFF_128]; + + int streamid = ++streamId; + float interval; /* it could be subseconds/100s minisecond */ + tgPingStart_t *staPing = (tgPingStart_t *)caCmdBuf; + dutCmdResponse_t *spresp = &gGenericResp; + +#ifdef WFA_PING_UDP_ECHO_ONLY + tgStream_t *myStream = NULL; +#endif + DPRINT_INFO(WFA_OUT, "Entering wfaTSendPing ...\n"); + if(staPing->frameSize == 0) + staPing->frameSize = 100; + + if(staPing->frameRate == 0) + staPing->frameRate = 1; + + interval = (float)1/staPing->frameRate; + + if(staPing->duration == 0) + staPing->duration = 30; + + switch(staPing->type) + { + case WFA_PING_ICMP_ECHO: +#ifndef WFA_PING_UDP_ECHO_ONLY + totalpkts = staPing->duration * staPing->frameRate; + +#ifndef WIN32 + sprintf(cmdStr, "echo streamid=%i > %s; %s -c %i -s %i -q %s >> %s 2>/dev/null&", + streamid, SPOUT_FILE_PATH, PING_PATH, totalpkts, staPing->frameSize, staPing->dipaddr, SPOUT_FILE_PATH); + system(cmdStr); + +#endif + + spresp->status = STATUS_COMPLETE; + spresp->streamId = streamid; +#else + DPRINT_INFO(WFA_OUT, "Only support UDP ECHO\n"); +#endif + break; + + case WFA_PING_UDP_ECHO: + { +#ifdef WFA_PING_UDP_ECHO_ONLY + /* + * Make this like a transaction testing + * Then make it a profile and run it + */ + myStream = &gStreams[slotCnt++]; + memset(myStream, 0, sizeof(tgStream_t)); + memcpy(&myStream->profile, caCmdBuf, len); + myStream->id = streamid; /* the id start from 1 */ + myStream->tblidx = slotCnt-1; + + btSockfd = wfaCreateUDPSock("127.0.0.1", WFA_UDP_ECHO_PORT); + if((btSockfd = wfaConnectUDPPeer(btSockfd, staPing->dipaddr, WFA_UDP_ECHO_PORT)) > 0) + { + gtgTransac = streamid; + gtgSend = streamid; + totalTranPkts = 512; + sentTranPkts = 0; + + /* + * the framerate here is used to derive the timeout + * value for waiting transaction echo responses. + */ + gtimeOut = MINISECONDS/staPing->frameRate; /* in msec */ + gRegSec = 0; + + /* set to longest time */ + if(staPing->duration == 0) + staPing->duration = 3600; + } +#else + DPRINT_INFO(WFA_OUT, "Doesn't support UDP Echo\n"); +#endif + break; + } + default: + { + spresp->status = STATUS_INVALID; + spresp->streamId = streamid; + } + } + + + wfaEncodeTLV(WFA_TRAFFIC_SEND_PING_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)spresp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return TRUE; +} + +/* + * tgStopPing(): Instruct Traffic Generator to stop ping packets + * + */ +int wfaTGStopPing(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int streamid = (int )(caCmdBuf+4); + dutCmdResponse_t *stpResp = &gGenericResp; + FILE *tmpfile = NULL; + tgStream_t *myStream; +#ifndef WIN32 + char strout[WFA_BUFF_256]; +#else + FILE *stptmpFile = NULL; + unsigned int position =0, recbfping =0, sentbfping =0, received =0, sent =0; +#endif + stpResp->status = STATUS_COMPLETE; + + DPRINT_INFO(WFA_OUT, "Entering wfaTStopPing ...\n"); + if(( gtgTransac == streamid) && (gtgSend == streamid)) + { + gtgTransac =0; + gtgSend = 0; + gtimeOut = 0; + gtgRecv = 0; +#ifndef WIN32 + alarm(0); +#endif + gRegSec = 1; + myStream = findStreamProfile(streamid); + if(myStream == NULL) + { + stpResp->status = STATUS_INVALID; + } + + stpResp->cmdru.pingStp.sendCnt = myStream->stats.txFrames; + stpResp->cmdru.pingStp.repliedCnt = myStream->stats.rxFrames; + } + else + { +#ifndef WIN32 + /* Ping will be stopped after the specified duration which will + * be specified by the user at the time send ping. For some reason popen with grep + * does not work well in Intel PXA with Linux + * Use system() call for such things and avoid using popen + */ + + sprintf(strout, "cat %s |grep transmitted | awk '{print $1,$4}' >%s 2>&1", + SPOUT_FILE_PATH, TMP_FILE_PATH); + + system(strout); + + tmpfile = fopen(TMP_FILE_PATH, "rb"); + + if (tmpfile == NULL) { + DPRINT_ERR(WFA_ERR, "\nShell Cmd:File open error\n"); + stpResp->status = STATUS_COMPLETE; + + wfaEncodeTLV(WFA_TRAFFIC_STOP_PING_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)stpResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return TRUE; + } + DPRINT_INFO(WFA_OUT,"\nCmdStr is:%s\n", strout); + fgets(strout, sizeof(strout), tmpfile); + stpResp->cmdru.pingStp.sendCnt = atoi(strout); + fgets(strout, sizeof(strout), tmpfile); + stpResp->cmdru.pingStp.repliedCnt = atoi(strout); + fclose(tmpfile); + + remove(TMP_FILE_PATH); +#else + if(exitcode ){ + TerminateProcess(processHandle, exitcode); + } + + tmpfile = fopen("temp\\RWL\\pingstats.txt", "r+"); + if(tmpfile == NULL) + { + stpResp->status = STATUS_COMPLETE; + + wfaEncodeTLV(WFA_TRAFFIC_STOP_PING_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)stpResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return FALSE; + } + + GetStats(tmpfile, L"Sent =", &position, " "); + stpResp->cmdru.pingStp.sendCnt = position; + GetStats(tmpfile, L"Received =", &position, " "); + stpResp->cmdru.pingStp.repliedCnt = position; + fclose(tmpfile); +#endif + } + wfaEncodeTLV(WFA_TRAFFIC_STOP_PING_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)stpResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + return TRUE; +} + +/* + * wfaTGConfig: store the traffic profile setting that will be used to + * instruct traffic generation. + * input: cmd -- not used + * response: send success back to controller + * return: success or fail + * Note: the profile storage is a global space. + */ +int wfaTGConfig(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf) +{ + int ret = FALSE; + tgStream_t *myStream = NULL; + dutCmdResponse_t *confResp = &gGenericResp; + + DPRINT_INFO(WFA_OUT, "slotCnt = %d\n", slotCnt); + /* if the stream table over maximum, reset it */ + if(slotCnt == WFA_MAX_TRAFFIC_STREAMS) + slotCnt = 0; + if(slotCnt == 0) + { + memset(gStreams, 0, WFA_MAX_TRAFFIC_STREAMS*sizeof(tgStream_t)); + } + + DPRINT_INFO(WFA_OUT, "entering tcConfig ...\n"); + myStream = &gStreams[slotCnt++]; + memset(myStream, 0, sizeof(tgStream_t)); + memcpy(&myStream->profile, caCmdBuf, len); + myStream->id = ++streamId; /* the id start from 1 */ + myStream->tblidx = slotCnt-1; + + DPRINT_INFO(WFA_OUT, "profile %i direction %i dest ip %s dport %i source %s sport %i rate %i duration %i size %i class %i delay %i\n", myStream->profile.profile, myStream->profile.direction, myStream->profile.dipaddr, myStream->profile.dport, myStream->profile.sipaddr, myStream->profile.sport, myStream->profile.rate, myStream->profile.duration, myStream->profile.pksize, myStream->profile.trafficClass, myStream->profile.startdelay); + + confResp->status = STATUS_COMPLETE; + confResp->streamId = myStream->id; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_CONFIG_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)confResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t); + + + return ret; +} + +/* + * wfaTGRecvStart: instruct traffic generator to start receiving + * based on a profile + * input: cmd -- not used + * response: inform controller for "running" + * return: success or failed + * + * In this function we create the UDP sockets for receiving the traffic and then + * set the global flag gtgRecv to indicate the receive thread to receive the incoming traffic. + * In the case of IPTV profile we multiple Create Events for multiple streams + */ + +int wfaTGRecvStart(int len, BYTE *parms, int *respLen, BYTE *respBuf) +{ + int status = STATUS_COMPLETE, i; + int numStreams = len/4; + int streamid, so; + tgProfile_t *theProfile; + tgStream_t *myStream; + + DPRINT_INFO(WFA_OUT, "entering tgRecvStart %i\n", numStreams); + + /* + * The function wfaSetProcPriority called here is to enhance the real-time + * performance for packet receiving. It is only for tuning and optional + * to implement + */ + //wfaSetProcPriority(60); + for(i=0; i<numStreams; i++) { + memcpy(&streamid, parms+(4*i), 4); /* changed from 2 to 4, bug reported by n.ojanen */ + + myStream = findStreamProfile(streamid); + if(myStream == NULL) + { + status = STATUS_INVALID; + return status; + } + + theProfile = &myStream->profile; + if(theProfile == NULL) + { + status = STATUS_INVALID; + return status; + } + + /* calculate the frame interval which is used to derive its jitter */ + if(theProfile->rate != 0 && theProfile->rate < 5000) + myStream->fmInterval = 1000000/theProfile->rate; /* in ms */ + else + myStream->fmInterval = 0; + + if(theProfile->direction != DIRECT_RECV) + { + status = STATUS_INVALID; + return status; + } + + memset(&myStream->stats, 0, sizeof(tgStats_t)); + switch(theProfile->profile) + { + case PROF_FILE_TX: + status = STATUS_COMPLETE; + btRecvSockfd = wfaCreateUDPSock(theProfile->dipaddr, theProfile->dport); + if(btRecvSockfd > 0) { + gtgRecv = streamid; +#ifdef WIN32 + /*Create receive event which is initially non-signalled and + * later reset the state of the signal when we call the command + * WfaRecvStop() */ + if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0) { + DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError()); + + } +#endif + /*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */ + wfaRecvThrCreate(); + } + else + { + status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + + break; + case PROF_FILE_TX_TCP: + gTCPsock = 1; + status = STATUS_COMPLETE; + gTcpRecvSockfd = wfaCreateTCPServSock(theProfile->dport); + if(gTcpRecvSockfd > 0) { + gtgRecv = streamid; +#ifdef WIN32 + /*Create receive event which is initially non-signalled and + * later reset the state of the signal when we call the command + * WfaRecvStop() */ + if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0) { + DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError()); + } +#endif + /*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */ + wfaRecvThrCreate(); + } + else + { + status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf); + respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + break; + + case PROF_MCAST: + status = STATUS_COMPLETE; + btRecvSockfd = wfaCreateUDPSock(theProfile->dipaddr, theProfile->dport); + DPRINT_INFO(WFA_OUT, "MCAST: RecvStart: btRecvSockfd = %d\r\n",btRecvSockfd); + if(btRecvSockfd > 0) + { +#ifdef WIN32 + /*Create receive event which is initially non-signalled and + * later automatically reset the state of the signal + * when the receive thread exits. */ + if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){ + DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError()); + } +#endif + gtgRecv = streamid; + /*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */ + wfaRecvThrCreate(); + + } + else + { + status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + DPRINT_INFO(WFA_OUT, "MCAST: RecvStart:before McastRecvOpt: btRecvSockfd = %d\r\n",btRecvSockfd); + /* set multicast socket option for receiver */ + DPRINT_INFO(WFA_OUT, "MCAST: RecvStart: McastRecvOpt: theProfile->dipaddr = %s\r\n",theProfile->dipaddr); + so = wfaSetSockMcastRecvOpt(btRecvSockfd, theProfile->dipaddr); + if(so < 0) + { + DPRINT_INFO(WFA_OUT, "MCAST: RecvStart: McastRecvOpt: so<0: btRecvSockfd = %d\r\n",btRecvSockfd); + asd_closeSocket(btRecvSockfd); + gtgRecv = 0; + btRecvSockfd = -1; + status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + + break; + + case PROF_IPTV: + status = STATUS_COMPLETE; + /*Create multiple streams and get the socket values in the array*/ + tgSockfds[myStream->tblidx] = wfaCreateUDPSock(theProfile->dipaddr, theProfile->dport); + DPRINT_INFO(WFA_OUT, "sock fd prof iptv = %d , streamid = %d\n", tgSockfds[myStream->tblidx], streamid); + if(tgSockfds[myStream->tblidx] > 0){ +#ifdef WIN32 + /* Create multiple event for different recv streams and get + * the values in the array of recv handles, Which will be later used in + * WfaRecvStop() to signal the recv thread to stop the recv process. */ + if((g_recvEvent[myStream->tblidx] = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){ + DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError()); + + } + + DPRINT_INFO(WFA_OUT, "recvstart g_recvEvent[myStream->tblidx] = %i\r\n", g_recvEvent[myStream->tblidx]); +#endif + gtgRecv = streamid; + /*Create a thread to receive IPTV traffic. */ + wfaIPTVRecvThrCreate(myStream->tblidx); + } + else + { + status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + break; + + case PROF_TRANSC: + case PROF_START_SYNC: + case PROF_CALI_RTD: /* Calibrate roundtrip delay */ + status = STATUS_COMPLETE; + btRecvSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport); + totalTranPkts = 0xFFFFFFF0; + sentTranPkts = 0; + if(btRecvSockfd > 0) + { + gtgTransac = streamid; + gtgRecv = streamid; +#ifdef WIN32 + if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){ + DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError()); + + } +#endif + /*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */ + wfaRecvThrCreate(); + } + else + { + status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + + break; + + case PROF_TRANSC_TCP: + gTCPsock = 1; + status = STATUS_COMPLETE; + gTcpRecvSockfd = wfaCreateTCPServSock(theProfile->dport); + if(gTcpRecvSockfd > 0) + { + gtgTransac = streamid; + gtgRecv = streamid; +#ifdef WIN32 + if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){ + DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError()); + } +#endif + /*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */ + wfaRecvThrCreate(); + } + else + { + status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + break; + + case PROF_UAPSD: +#ifdef WFA_WMM_EXT +#ifdef WFA_WMM_PS_EXT + status = STATUS_COMPLETE; + psSockfd = wfaCreateUDPSock(theProfile->dipaddr, WFA_WMMPS_UDP_PORT); + + wmmps_info.sta_state = 0; + wmmps_info.wait_state = WFA_WAIT_STAUT_00; +#ifdef WIN32 + init_wmmps_thr(); + if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){ + DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError()); + + } +#endif + memset(&wmmps_info.psToAddr, 0, sizeof(wmmps_info.psToAddr)); + wmmps_info.psToAddr.sin_family = AF_INET; + wmmps_info.psToAddr.sin_addr.s_addr = inet_addr(theProfile->sipaddr); + wmmps_info.psToAddr.sin_port = htons(theProfile->sport); + wmmps_info.reset = 0; + + wmm_thr[usedThread].thr_flag = streamid; + wmmps_info.streamid = streamid; +#ifndef WIN32 + pthread_mutex_lock(&wmm_thr[usedThread].thr_flag_mutex); + pthread_cond_signal(&wmm_thr[usedThread].thr_flag_cond); + gtgWmmPS = streamid;; + pthread_mutex_unlock(&wmm_thr[usedThread].thr_flag_mutex); + usedThread++; +#else + SetEvent(thr_flag_cond); + gtgWmmPS = streamid; +#endif /* WIN32 */ + gtimeOut = MINISECONDS/10; /* in msec */ + gRegSec = 0; + + /* Create the receiver thread */ + wfaRecvThrCreate(); +#endif /* WFA_WMM_PS_EXT */ +#endif /* WFA_WMM_EXT */ + break; + } + } + + /* encode a TLV for response for "complete/error ..." */ + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, + (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* + * tgRecvStop: instruct traffic generator to stop receiving based on a profile + * input: cmd -- not used + * response: inform controller for "complete" + * return: success or failed + * + * In this function we will reset the gtgRecv flag, close the UDP sockets opened in the + * receive start to stop receiving the traffic from TG. We also kill the thread that was created + * in receive start*/ +int wfaTGRecvStop(int len, BYTE *parms, int *respLen, BYTE *respBuf) +{ + int status = STATUS_COMPLETE, i, j; + int numStreams = len/4; + int streamid; + tgProfile_t *theProfile; + tgStream_t *myStream=NULL; + dutCmdResponse_t statResp; + BYTE dutRspBuf[WFA_BUFF_1K]; + int id_cnt = 0; + FILE *e2eoutp = NULL; +#ifndef WIN32 + struct timeval currtime; +#else + SYSTEMTIME currtime; +#endif + + DPRINT_INFO(WFA_OUT, "entering tgRecvStop\n"); + + memset(dutRspBuf, 0, WFA_BUFF_1K); + + for(i=0; i<numStreams; i++) + { + memcpy(&streamid, parms+(4*i), 4); + myStream = findStreamProfile(streamid); + if(myStream == NULL) + { + status = STATUS_INVALID; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + + theProfile = &myStream->profile; + if(theProfile == NULL) + { + status = STATUS_INVALID; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + + if(theProfile->direction != DIRECT_RECV) + { + status = STATUS_INVALID; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV, 4, (BYTE *)&status, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + /* reset its flags , close sockets */ + gtgRecv = 0; + switch(theProfile->profile) + { + case PROF_FILE_TX: + case PROF_FILE_TX_TCP: +#ifdef WIN32 + /*Set the recv event and signal the recv thread function to stop + * Receiving the File transfer Traffic, also close the handle of the event*/ + if(SetEvent(g_hRecvEvent) == 0) { + DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError()); + } + while ((WaitForSingleObject(g_RecvhThread, INFINITE) != WAIT_OBJECT_0)); + if(g_hRecvEvent != NULL) + CloseHandle(g_hRecvEvent); + +#else + /* Waiting for signal from wfaRecvStart once the receive + * operation is complete in order to close the socket + */ + sem_wait(&sem_gtgrecv); +#endif + if(gTcpRecvSockfd != -1) { + gTCPsock = 0; + asd_closeSocket(gTcpRecvSockfd); + gTcpRecvSockfd = -1; + } + if(btRecvSockfd != -1) { + asd_closeSocket(btRecvSockfd); + btRecvSockfd = -1; + } + break; + + case PROF_MCAST: +#ifdef WIN32 + /* Set the recv event and signal the recv thread function to stop + * Receiving the Multicast Traffic, also close the handle of the event*/ + if(SetEvent(g_hRecvEvent) == 0) { + DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError()); + } + while ((WaitForSingleObject(g_RecvhThread, INFINITE) != WAIT_OBJECT_0)); + if(g_hRecvEvent != NULL) + CloseHandle(g_hRecvEvent); +#else + /* Waiting for signal from wfaRecvStart once the receive + * operation is complete in order to close the socket + */ + sem_wait(&sem_gtgrecv); +#endif + if(btRecvSockfd != -1){ + asd_closeSocket(btRecvSockfd); + btRecvSockfd = -1; + } + break; + + case PROF_IPTV: + IPTVprof = 0; +#ifdef WIN32 + /* Set the recv event and signal the recv thread function to stop + * Receiving the IPTV traffic in the case of multiple streams, + * also close the handles of the multiple events*/ + if(SetEvent(g_recvEvent[myStream->tblidx]) == 0) { + DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError()); + } + while ((WaitForSingleObject(g_IPTVRecvhThread[myStream->tblidx], INFINITE) != WAIT_OBJECT_0)); + if(g_recvEvent[myStream->tblidx] != NULL) + CloseHandle(g_recvEvent[myStream->tblidx]); +#else + /* Waiting for signal from wfaIPTVRecvStart once the receive + * operation is complete in order to close the socket + */ + sem_wait(&sem_iptv_gtgrecv[myStream->tblidx]); +#endif + if(tgSockfds[myStream->tblidx] != -1){ + asd_closeSocket(tgSockfds[myStream->tblidx]); + tgSockfds[myStream->tblidx] = -1; + } + /* the following to report the result. There will be a + * solution to send it back to TM + */ + //#endif + break; + + case PROF_TRANSC: + case PROF_TRANSC_TCP: + case PROF_START_SYNC: + case PROF_CALI_RTD: /* Calibrate roundtrip delay */ + gtgTransac = 0; +#ifdef WIN32 + /* Set the recv event and signal the recv thread function to stop + * Receiving the Transaction Traffic, also close the handle of the event*/ + if(SetEvent(g_hRecvEvent) == 0){ + DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError()); + } + while ((WaitForSingleObject(g_RecvhThread, INFINITE) != WAIT_OBJECT_0)); + if(g_hRecvEvent != NULL) + CloseHandle(g_hRecvEvent); +#else + /* Waiting for signal from wfaRecvStart once the receive + * operation is complete in order to close the socket + */ + sem_wait(&sem_gtgrecv); +#endif + if(gTcpRecvSockfd != -1) { + gTCPsock = 0; + asd_closeSocket(gTcpRecvSockfd); + gTcpRecvSockfd = -1; + } + if(btRecvSockfd != -1){ + asd_closeSocket(btRecvSockfd); + btRecvSockfd = -1; + } + break; + case PROF_UAPSD: +#ifdef WFA_WMM_EXT +#ifdef WFA_WMM_PS_EXT + gtgWmmPS = 0; + gtgPsPktRecvd = 0; + + if(psSockfd != -1) + { + asd_closeSocket(psSockfd); + psSockfd = -1; + } + + memset(&wmmps_info, 0, sizeof(wfaWmmPS_t)); + + wfaSetDUTPwrMgmt(PS_OFF); +#endif /* WFA_WMM_PS_EXT */ +#endif /* WFA_WMM_EXT */ + break; + } + /* encode a TLV for response for "complete/error ..." */ + statResp.status = STATUS_COMPLETE; + statResp.streamId = streamid; + DPRINT_INFO(WFA_OUT, "stream Id %i rx %i total %i\n", streamid, myStream->stats.rxFrames, myStream->stats.rxPayloadBytes); + memcpy(&statResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t)); + memcpy((dutRspBuf + i * sizeof(dutCmdResponse_t)), (BYTE *)&statResp, sizeof(dutCmdResponse_t)); + id_cnt++; + memset(myStream, 0, sizeof(tgStream_t)); + } + + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV, (WORD)(id_cnt * sizeof(dutCmdResponse_t)), dutRspBuf, respBuf); + + /* done here */ + *respLen = WFA_TLV_HDR_LEN + numStreams * sizeof(dutCmdResponse_t); + return TRUE; +} + +/* + * wfaTGSendStart: instruct traffic generator to start sending based on a profile + * input: cmd -- not used + * response: inform controller for "running" + * return: success or failed + * + * In this function we will create the UDP sockets to send the traffic + * and set the global flag gtgSend, increment usedThread for each stream + * also set the socket option and type ofservice bits (TOS) in + * the case of Multicast profiles . We also + * Call the thread Win32_tmout_stop_send() which sleeps for the duration specified in the profile + * and then stops the sending of the traffic by resetting the runloop, decrement usedThread . + */ +int wfaTGSendStart(int len, BYTE *parms, int *respLen, BYTE *respBuf) +{ + int i=0, streamid=0, so; + int numStreams = len/4; + tgProfile_t *theProfile; + tgStream_t *myStream = NULL; + dutCmdResponse_t sendResp; +#ifdef WIN32 + DWORD errnum; +#endif +#ifdef WFA_DUT_SYNC +#ifndef WIN32 + pthread_attr_t ptAttr; + int ptPolicy; + + struct sched_param ptSchedParam; + struct timeval btime; +#else + SYSTEMTIME btime; +#endif +#endif + dutCmdResponse_t staSendResp; + + +#ifdef WIN32 + /*Create an event which will wait for the traffic streams to complete the send operation */ + if((send_event = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){ + DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError()); + } +#else + + gnumStreams = numStreams; +#endif + DPRINT_INFO(WFA_OUT, "Entering tgSendStart for %i streams ...\n", numStreams); + + + for(i=0; i<numStreams; i++) + { + memcpy(&streamid, parms+(4*i), 4); + myStream = findStreamProfile(streamid); + if(myStream == NULL) + { + staSendResp.status = STATUS_INVALID; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + + theProfile = &myStream->profile; + if(theProfile == NULL) + { + staSendResp.status = STATUS_INVALID; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + + if(theProfile->direction != DIRECT_SEND) + { + staSendResp.status = STATUS_INVALID; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + + /* + * need to reset the stats + */ + memset(&myStream->stats, 0, sizeof(tgStats_t)); + /* Here increment the usedThread for every time we wish to send a stream + * so as to maintain the count of streams that are running at the same time. + */ + switch(theProfile->profile) + { + case PROF_FILE_TX: + btSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport); + if((btSockfd=wfaConnectUDPPeer(btSockfd, theProfile->dipaddr, theProfile->dport)) > 0) + { + gtgSend = streamid; + usedThread++; +#ifndef WIN32 + SendFile(); +#else + g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)streamid, 0, &dwIPTVThread); + if(g_TGSndThr[i] == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } +#endif + } + else + { + gtgSend = 0; + staSendResp.status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + + break; + case PROF_FILE_TX_TCP: + if((btSockfd=wfaConnectTCPPeer(theProfile->sport, theProfile->dipaddr, theProfile->dport)) > 0) + { + gtgSend = streamid; + usedThread++; +#ifndef WIN32 + SendFile(); +#else + g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)streamid, 0, &dwIPTVThread); + if(g_TGSndThr[i] == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } +#endif + } + else + { + gtgSend = 0; + staSendResp.status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + break; + case PROF_MCAST: + btSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport); + if(btSockfd > 0) + { + gtgSend = streamid; + usedThread ++; + } + else + { + staSendResp.status = STATUS_ERROR; + + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + + so = wfaSetSockMcastSendOpt(btSockfd); + if (so < 0) + { +#ifdef WIN32 + DPRINT_INFO(WFA_OUT, "setsockopt for mcast: %d\n",WSAGetLastError()); +#endif + gtgSend = 0; + asd_closeSocket(btSockfd); + btSockfd = -1; + staSendResp.status = STATUS_ERROR; + + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } +#ifndef WIN32 + SendFile(); +#else + g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)gtgSend, 0, &dwIPTVThread); + if(g_TGSndThr[i] == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } +#endif + break; + case PROF_IPTV: + + IPTVprof = 1; + gtgSend = streamid; + usedThread++; +#ifndef WIN32 + + /* + * singal the thread to Sending WMM traffic + */ + wmm_thr[usedThread].thr_flag = streamid; + pthread_mutex_lock(&wmm_thr[usedThread].thr_flag_mutex); + pthread_cond_signal(&wmm_thr[usedThread].thr_flag_cond); + pthread_mutex_unlock(&wmm_thr[usedThread].thr_flag_mutex); +#else + /* Create thread to send the IPTV stream, and store the handle of the thread in the array of the handles. + * New thread is created everytime in the case of multiple streams, to send the traffic simultaneously. + */ + g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendIPTVFile, (LPVOID)streamid, 0, &dwIPTVThread); + DPRINT_INFO(WFA_OUT, "Thread create Handle %x\n", g_TGSndThr[i]); + if(g_TGSndThr[i] == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } + +#endif + DPRINT_INFO(WFA_OUT, "wfa_wmm_thread: myProfile->startdelay %i\n", theProfile->startdelay); + /* if delay is too long, it must be something wrong */ + DPRINT_INFO(WFA_OUT, "sleep for %d\n", theProfile->startdelay); + + +#ifdef WFA_DUT_SYNC + //reset clock by estimate drift + gettimeofday(&btime, NULL); + + DPRINT_INFO(WFA_OUT, "btime.tv_sec %u, btime.tv_usec %u last sync time %f\n", (unsigned int) btime.tv_sec, (unsigned int) btime.tv_usec, gtgStartSyncTime.dut_time); + + double bdftime = wfa_timeval2double(&btime) - (gtgStartSyncTime.dut_time); + traf_start_drift = clock_drift_ps * bdftime; + + DPRINT_INFO(WFA_OUT, "time gap %lf traf_start_drift %i\n", bdftime, traf_start_drift); + + if(abs(traf_start_drift) > 50) + { + DPRINT_INFO(WFA_OUT, "traf_start_drift %i\n", traf_start_drift); + + btime.tv_usec += traf_start_drift; + if(btime.tv_usec < 0) + { + btime.tv_sec -= 1; + btime.tv_usec +=1000000; + } + else if(btime.tv_usec >=1000000) + { + btime.tv_sec +=1; + btime.tv_usec -= 1000000; + } + + // clock get reset + settimeofday(&btime, NULL); + + // ajust the sync time for the next run. + gtgStartSyncTime.dut_time = wfa_timeval2double(&btime); + clock_drift_ppk = (double) clock_drift_ps / (double) theProfile->rate; + } +#endif + break; + + case PROF_TRANSC: + { + btSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport); + if((btSockfd = wfaConnectUDPPeer(btSockfd, theProfile->dipaddr, theProfile->dport)) > 0) + { + gtgTransac = streamid; + gtgSend = streamid; + totalTranPkts = theProfile->rate * theProfile->duration; + sentTranPkts = 0; + /* + * the framerate here is used to derive the timeout + * value for waiting transaction echo responses. + */ + if(theProfile->rate == 0){ + gtimeOut = MINISECONDS; /* in msec */ + } else { + gtimeOut = MINISECONDS/theProfile->rate; /* in msec */ + } + gRegSec = 0; + usedThread++; + } + else + { + staSendResp.status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; + } + + /* set duration for the test */ +#ifndef WIN32 + signal(SIGALRM, tmout_stop_send); + alarm(theProfile->duration); +#else + if(hThread1 != NULL){ + CloseHandle(hThread1); + } + hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Win32_tmout_stop_send, (LPVOID)(theProfile->duration *1000), 0, &dwGenericThread1); + if(hThread1 == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } +#endif +#ifndef WIN32 + SendFile(); +#else + g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)gtgSend, 0, &dwIPTVThread); + if(g_TGSndThr[i] == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } +#endif + } + break; + case PROF_TRANSC_TCP: + if((btSockfd=wfaConnectTCPPeer(theProfile->dport, theProfile->dipaddr, theProfile->dport)) > 0) + { + gtgTransac = streamid; + gtgSend = streamid; + totalTranPkts = theProfile->rate * theProfile->duration; + sentTranPkts = 0; + /* + * the framerate here is used to derive the timeout + * value for waiting transaction echo responses. + */ + if(theProfile->rate == 0){ + gtimeOut = MINISECONDS; /* in msec */ + } else { + gtimeOut = MINISECONDS/theProfile->rate; /* in msec */ + } + gRegSec = 0; + usedThread++; + } + else + { + staSendResp.status = STATUS_ERROR; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + return TRUE; + } + + /* set duration for the test */ +#ifndef WIN32 + signal(SIGALRM, tmout_stop_send); + alarm(theProfile->duration); +#else + if(hThread1 != NULL){ + CloseHandle(hThread1); + } + hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Win32_tmout_stop_send, (LPVOID)(theProfile->duration *1000), 0, &dwGenericThread1); + if(hThread1 == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } +#endif +#ifndef WIN32 + SendFile(); +#else + g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)gtgSend, 0, &dwIPTVThread); + if(g_TGSndThr[i] == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } +#endif + break; +#ifdef WFA_WMM_EXT + case PROF_START_SYNC: + case PROF_CALI_RTD: + { + DPRINT_INFO(WFA_OUT, "profile port %i\n", theProfile->sport); + btSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport); + if((btSockfd = wfaConnectUDPPeer(btSockfd, theProfile->dipaddr, theProfile->dport)) > 0) + { + gtgTransac = streamid; + gtgSend = streamid; + totalTranPkts = theProfile->rate * theProfile->duration; + sentTranPkts = 0; + if(theProfile->profile == PROF_START_SYNC) + gtgStartSync = streamid; + else if(theProfile->profile == PROF_CALI_RTD) + gtgFinishSync = streamid; + + /* + * the framerate here is used to derive the timeout + * value for waiting transaction echo responses. + */ + gtimeOut = MINISECONDS/theProfile->rate; /* in msec */ + } + else + { + DPRINT_INFO(WFA_OUT, "connection failed\n"); + } + + /* set duration for the test */ +#ifndef WIN32 + signal(SIGALRM, tmout_stop_send); + alarm(theProfile->duration+1); +#else + if(hThread2 != NULL){ + CloseHandle(hThread2); + } + hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Win32_tmout_stop_send, (LPVOID)((theProfile->duration+1) *1000), 0, &dwGenericThread2); + if(hThread2 == NULL){ + errnum = GetLastError(); + DPRINT_INFO(WFA_OUT, "Could not create the thread1\n"); + return TRUE; + } +#endif + } + break; +#endif + default : + DPRINT_INFO(WFA_OUT, "No profile match findStreams problem\n"); + } + } + +#ifdef WIN32 + /* Wait fo the event to be signalled from the timeout function, after all + * the threads have finished sending the traffic. + * + */ + + Sleep(theProfile->duration*1000); + if(SetEvent(send_event)== 0 ){ + DPRINT_INFO(WFA_OUT, "SetEvent failure %d \n", GetLastError()); + } + for(i = 0; i < numStreams; i++) + while ((WaitForSingleObject(g_TGSndThr[i], INFINITE) != WAIT_OBJECT_0)); + if(IPTVprof == 1) { + memset(Send_dutResp, 0, WFA_BUFF_512); + wfaSentStatsResp(Send_dutResp); + } + + + if(send_event != NULL) { + CloseHandle(send_event); + send_event = NULL; + } + +#else + sem_wait(&sem_wmm_resp); + if(IPTVprof) { + sem_wait(&sem_wmm); + memset(Send_dutResp, 0, WFA_BUFF_512); + wfaSentStatsResp(Send_dutResp); + } +#endif + /* update the response */ + if(! IPTVprof) { + memset(Send_dutResp, 0, WFA_BUFF_512); + sendResp.status = STATUS_COMPLETE; + sendResp.streamId = myStream->id; + memcpy(&sendResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t)); + memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t)); + } + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, (WORD)(numStreams* sizeof(dutCmdResponse_t)),Send_dutResp, (BYTE*)respBuf); + + /* done here */ + *respLen = WFA_TLV_HDR_LEN + numStreams * sizeof(dutCmdResponse_t); + + DPRINT_INFO(WFA_OUT, "Leaving send start Check btsockfd = %d\n", btSockfd); + return TRUE; +} + +int wfaTGReset(int len, BYTE *parms, int *respLen, BYTE *respBuf) +{ + dutCmdResponse_t *resetResp = &gGenericResp; + + gtgRecv = 0; + gtgSend = 0; + /* need to reset all traffic socket fds */ + if(btSockfd != -1 ) { + asd_closeSocket(btSockfd); + btSockfd = -1; + } + + if (btRecvSockfd != -1) { + asd_closeSocket(btRecvSockfd); + btRecvSockfd = -1; + } + + /* reset the timer alarm if it was armed */ +#ifndef WIN32 + alarm(0); +#endif + + /* just reset the flags for the command */ + usedThread = 0; + gtgTransac = 0; + totalTranPkts = 0; + gtimeOut = 0; + gRegSec = 1; /* mewly added */ + IPTVprof = 0; + runLoop = 0; + gTransactrunLoop = 0; + +#ifdef WFA_WMM_EXT + e2eCnt = 0; + /* changed now */ + memset(e2eStats, 0, 6000*sizeof(tgE2EStats_t)); + + /* Start : Modified as per BRCM 1.3 ASD */ + +#ifdef WFA_WMM_PS_EXT + gtgWmmPS = 0; + gtgPsPktRecvd = 0; + + if(psSockfd != -1) + { + asd_closeSocket(psSockfd); + psSockfd = -1; + } + + memset(&wmmps_info, 0, sizeof(wfaWmmPS_t)); + + wfaSetDUTPwrMgmt(PS_OFF); +#endif /* WFA_WMM_EXT */ + + /* End : Modified as per BRCM 1.3 ASD */ + + +#endif + + /* Also need to clean up WMM streams NOT DONE YET!*/ + slotCnt = 0; /* reset stream profile container */ + + + /* encode a TLV for response for "complete ..." */ + resetResp->status = STATUS_COMPLETE; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_RESET_RESP_TLV, 4, + (BYTE *)resetResp, respBuf); + *respLen = WFA_TLV_HDR_LEN + 4; + + return TRUE; +} + +/* + * calculate the sleep time for different frame rate + * It should be done according the device + * This is just one way to adjust the packet delivery speed. If you find + * you device does not meet the test requirements, you MUST re-adjust + * the method. + */ + +/* The HZ value could be found in the build header file */ +/* 100 -> 10ms, 1000 -> 1ms , etc */ +#define WFA_KERNEL_MIN_TIMER_RES 100 /* HZ Value for 10 ms */ + +void wfaTxSleepTime(int profile, int rate, int *sleepTime, int *throttledRate) +{ + *sleepTime=0; /* in microseconds */ + /* calculate the sleep time based on frame rate */ + + /* + * Framerate is still required for Multicast traffic + * Sleep and hold for a timeout. + * + * For WMM traffic, the framerate must also need for VO and VI. + * the framerate 500, OS may not handle it precisely. + */ + switch(profile) + { + /* + * Vendor must find ways to better adjust the speed for their own device + */ + case PROF_MCAST: + case PROF_IPTV: + case PROF_FILE_TX: + case PROF_FILE_TX_TCP: + case PROF_TRANSC: + case PROF_TRANSC_TCP: + if(rate >=100 || rate == 0) + { + /* + * this sleepTime indeed is now being used for time period + * to send packets in the throttled Rate. + * The idea here is that in each fixed 50 minisecond period, + * The device will send rate/20 (rate = packets / second), + * then go sleep for rest of time. + */ +#ifndef WIN32 + *sleepTime = 50000; /* fixed 50 miniseconds */ +#else + *sleepTime = 50; /* CHANGED FROM 50000 TO 50 fixed 50 miniseconds */ +#endif + *throttledRate = (rate?rate:3000)/20; + DPRINT_INFO(WFA_OUT, "Sleep time %i, throttledRate %i\n", *sleepTime, *throttledRate); + } + else if (rate > 0 && rate <= 50) /* typically for voice */ + { + *throttledRate = 1; +#ifndef WIN32 + *sleepTime = 1000*1000/rate; +#else + *sleepTime = 1000/rate; +#endif + } + break; + default: + DPRINT_ERR(WFA_ERR, "Incorrect profile\n"); + } +} + +#ifndef WIN32 +#define WFA_TIME_DIFF(before, after, rtime, dtime) \ + dtime = rtime + (after.tv_sec*1000000 + after.tv_usec) - (before.tv_sec*1000000 + before.tv_usec); +#else +#define WFA_TIME_DIFF(before, after, rtime, dtime) \ + dtime = rtime + (after.wSecond +after.wMilliseconds ) - (before.wSecond + before.wMilliseconds ); +#endif + +void buzz_time(int delay) +{ +#ifndef WIN32 + struct timeval now, stop; +#else + SYSTEMTIME now, stop; +#endif + int diff; + int remain_time = 0; + +#ifndef WIN32 + gettimeofday(&stop, 0); + + stop.tv_usec += delay; + if(stop.tv_usec > 1000000) + { + stop.tv_usec -=1000000; + stop.tv_sec +=1; + } +#else + GetSystemTime(&stop); + stop.wMilliseconds +=delay; + if(stop.wMilliseconds > 1000) + { + stop.wMilliseconds -=1000; + stop.wSecond+=1; + } +#endif + + do + { +#ifndef WIN32 + gettimeofday(&now, 0); + WFA_TIME_DIFF(now, stop, remain_time, diff); +#else + GetSystemTime(&now); + WFA_TIME_DIFF(stop, now, remain_time, diff); +#endif + + } while(diff>0); +} + +/**************************************************/ +/* the actually functions to send/receive packets */ +/**************************************************/ + +/* This is going to be a blocking SEND till it finishes */ +int wfaSendLongFile(int mySockfd, int streamid, BYTE *aRespBuf, int *aRespLen) +{ + tgProfile_t *theProf = NULL; + tgStream_t *myStream = NULL; + struct sockaddr_in toAddr; + char *packBuf; + int packLen; + int bytesSent; + dutCmdResponse_t sendResp; + int sleepTime = 0; + int throttledRate = 0; + int errsv; +#ifndef WIN32 + struct timeval before, after, stime; +#else + SYSTEMTIME before, after, stime; +#endif + int difftime = 0; + int counter = 0; + int throttled_est_cost; + int act_sleep_time; + + DPRINT_INFO(WFA_OUT, "Entering sendLongFile %i\n", streamid); + + /* find the profile */ + myStream = findStreamProfile(streamid); + if(myStream == NULL) + { + return FALSE; + } + + theProf = &myStream->profile; + + if(theProf == NULL) + { + return FALSE; + } + + packLen = theProf->pksize; + + /* allocate a buf */ + packBuf = (char *)malloc(packLen); + memset(packBuf, 1, packLen); + + /* fill in the header */ + strncpy(packBuf, "1345678", sizeof(tgHeader_t)); + + /* initialize the destination address */ + memset(&toAddr, 0, sizeof(toAddr)); + toAddr.sin_family = AF_INET; + toAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr); + toAddr.sin_port = htons(theProf->dport); + + /* if a frame rate and duration are defined, then we know + * interval for each packet and how many packets it needs to + * send. + */ + + if(theProf->duration != 0) + { + DPRINT_INFO(WFA_OUT, "duration %i\n", theProf->duration); + /* + * use this to decide periodical interval sleep time and frames to send + * int the each interval. + * Each device should adopt a own algorithm for better performance + */ + wfaTxSleepTime(theProf->profile, theProf->rate, &sleepTime, &throttledRate); + /* + * alright, we need to raise the priority level of the process + * to improve the real-time performance of packet sending. + * Since this is for tuning purpose, it is optional implementation. + */ + //wfaSetProcPriority(60); + + //interval = 1*1000000/theProf->rate ; // in usec; + + // Here assumes it takes 20 usec to send a packet + throttled_est_cost = throttledRate * 20; // MUST estimate the cost per ppk + act_sleep_time = sleepTime - adj_latency - throttled_est_cost; + if (act_sleep_time <= 0) + act_sleep_time = sleepTime; + + DPRINT_INFO(WFA_OUT, "sleep time %i act_sleep_time %i\n", sleepTime, act_sleep_time); + + runLoop=1; +#ifndef WIN32 + while (runLoop) +#else + while ((WaitForSingleObject(send_event,0) != WAIT_OBJECT_0)) +#endif + { + counter++; + /* fill in the counter */ + int2BuffBigEndian(counter, &((tgHeader_t *)packBuf)->hdr[8]); + + + /* + * the following code is only used to slow down + * over fast traffic flooding the buffer and cause + * packet drop or the other end not able to receive due to + * some limitations, purely for experiment purpose. + * each implementation needs some fine tune to it. + */ + if(counter ==1) + { +#ifndef WIN32 + gettimeofday(&before, NULL); + + before.tv_usec += sleepTime; + if(before.tv_usec > 1000000) + { + before.tv_usec -= 1000000; + before.tv_sec +=1; + } +#else + GetSystemTime(&before); + before.wMilliseconds +=sleepTime; + if(before.wMilliseconds > 1000) + { + before.wMilliseconds -= 1000; + before.wMilliseconds += 1; + + } +#endif + } + + if(throttledRate != 0) + { + if(counter%throttledRate == 0) + { + // sleep that much time +#ifndef WIN32 + usleep(act_sleep_time); + gettimeofday(&after, NULL); + difftime = wfa_itime_diff(&after, &before); +#else + /* In case of win32 for higher frame rate we are sleeping + * less to meet the required Tx frame rate efficiency. + */ + + if (theProf->rate > HIGH_FRAME_RATE_VAL) + usleep(act_sleep_time / SLEEP_DENOMINATOR); + else + usleep(act_sleep_time); + GetSystemTime(&after); + difftime = wfa_Winitime_diff(&before,&after ); +#endif + // burn the rest to absort latency + if(difftime >0) + buzz_time(difftime); +#ifndef WIN32 + before.tv_usec += sleepTime; + if(before.tv_usec > 1000000) + { + before.tv_usec -= 1000000; + before.tv_sec +=1; + } + } + } // otherwise, it floods +#else + before.wMilliseconds += sleepTime; + if(before.wMilliseconds > 1000) + { + before.wMilliseconds -= 1000; + before.wSecond +=1; + } + } + } // otherwise, it floods +#endif + + /* + * Fill the timestamp to the header. + */ +#ifndef WIN32 + gettimeofday(&stime, NULL); + + int2BuffBigEndian(stime.tv_sec, &((tgHeader_t *)packBuf)->hdr[12]); + int2BuffBigEndian(stime.tv_usec, &((tgHeader_t *)packBuf)->hdr[16]); +#else + GetSystemTime(&stime); + int2BuffBigEndian(stime.wSecond, &((tgHeader_t *)packBuf)->hdr[12]); + int2BuffBigEndian(stime.wMilliseconds , &((tgHeader_t *)packBuf)->hdr[16]); +#endif + + if(theProf->profile == PROF_FILE_TX_TCP || theProf->profile == PROF_TRANSC_TCP) + bytesSent = wfaCtrlSend(mySockfd, (unsigned char*)packBuf, packLen); + else + bytesSent = wfaTrafficSendTo(mySockfd, packBuf, packLen, (struct sockaddr *)&toAddr); + + if(bytesSent != -1) + { + myStream->stats.txPayloadBytes += bytesSent; + myStream->stats.txFrames++ ; + } + else + { +#ifndef WIN32 + errsv = errno; + switch(errsv) + { + case EAGAIN: + case ENOBUFS: + //DPRINT_INFO(WFA_OUT, "send error\n"); + usleep(50); + counter-- ; + //myStream->stats.txFrames--; + + break; + case ECONNRESET: + runLoop = 0; + break; + case EPIPE: + runLoop = 0; + break; + default: + { + DPRINT_INFO(WFA_OUT, "Packet sent error\n"); + } + } +#else + errsv = WSAGetLastError(); + + switch(errsv) + { + case WSATRY_AGAIN: + case WSAENOBUFS: + DPRINT_INFO(WFA_OUT, "send error\n"); + usleep(1); /* hold for 1 ms */ + counter-- ; + // myStream->stats.txFrames--; + + break; + case WSAECONNRESET: + runLoop = 0; + break; + case WSAESHUTDOWN: + runLoop = 0; + break; + default: + DPRINT_INFO(WFA_OUT, "Packet sent error\n"); + break; + } +#endif + } + } + + /* + * lower back to an original level if the process is raised previously + * It is optional. + */ + //wfaSetProcPriority(30); + } + else /* invalid parameters */ + { + /* encode a TLV for response for "invalid ..." */ + sendResp.status = STATUS_INVALID; + memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t)); + return DONE; + } + + gtgSend = 0; + + /* free the buffer */ + free(packBuf); + + /* Populate the statistics of the sent response in Send_dutResp . In the case of multiple streams + * Send_dutResp buffer will have all the response at the end of the send process of all the streams. + */ + sendResp.status = STATUS_COMPLETE; + sendResp.streamId = myStream->id; + memcpy(&sendResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t)); + memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t)); +#ifndef WIN32 + gnumStreams = gnumStreams -1; + if(IPTVprof == 1) { + if(gnumStreams == 0) + sem_post(&sem_wmm); + + } +#endif + return DONE; +} + +/* this only sends one packet a time */ +int wfaSendShortFile(int mySockfd, int streamid, BYTE *sendBuf, int pksize, BYTE *aRespBuf, int *aRespLen) +{ + BYTE *packBuf = sendBuf; + struct sockaddr_in toAddr; + tgProfile_t *theProf; + tgStream_t *myStream; + int packLen, bytesSent=-1; + dutCmdResponse_t sendResp; + int errsv; + DPRINT_INFO(WFA_OUT, "---------SendShortFile----------:%d\r\n", mySockfd); + if(mySockfd == -1) + { + /* stop */ + gtgTransac = 0; + gtimeOut = 0; + gtgRecv = 0; + gtgSend = 0; + DPRINT_INFO(WFA_OUT, "stop short traffic\n"); + + myStream = findStreamProfile(streamid); + if(myStream != NULL) + { + sendResp.status = STATUS_COMPLETE; + sendResp.streamId = streamid; + memcpy(&sendResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t)); + memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t)); + + } + + return DONE; + } + + /* find the profile */ + myStream = findStreamProfile(streamid); + + theProf = &myStream->profile; + if(theProf == NULL) { + return FALSE; + } + + if(pksize == 0) + packLen = theProf->pksize; + else + packLen = pksize; + + memset(&toAddr, 0, sizeof(toAddr)); + toAddr.sin_family = AF_INET; + toAddr.sin_addr.s_addr = inet_addr(theProf->sipaddr); + toAddr.sin_port = htons(theProf->sport); + + if(gtgRecv && gtgTransac) + { + toAddr.sin_addr.s_addr = inet_addr(theProf->sipaddr); + toAddr.sin_port = htons(theProf->sport); + } + else if(gtgSend && gtgTransac) + { + toAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr); + toAddr.sin_port = htons(theProf->dport); + } + + int2BuffBigEndian(myStream->stats.txFrames, &((tgHeader_t *)packBuf)->hdr[8]); + + if(mySockfd != -1) + { + if(theProf->profile == PROF_FILE_TX_TCP || theProf->profile == PROF_TRANSC_TCP) + bytesSent = wfaCtrlSend(mySockfd, (unsigned char*)packBuf, packLen); + else + bytesSent = wfaTrafficSendTo(mySockfd, (char *)packBuf, packLen, (struct sockaddr *)&toAddr); + } + + + if(bytesSent > 0) + { + myStream->stats.txFrames++; + myStream->stats.txPayloadBytes += bytesSent; + } + else if(bytesSent == -1) + { +#ifndef WIN32 + errsv = errno; + switch(errsv) + { + case EAGAIN: + case ENOBUFS: + DPRINT_ERR(WFA_ERR, "send error\n"); + usleep(1000); /* hold for 1 ms */ + // myStream->stats.txFrames--; + break; + default: + break; + } +#else + errsv = WSAGetLastError(); + switch(errsv) + { + case WSATRY_AGAIN: + case WSAENOBUFS: + usleep(1); /* hold for 1 ms */ + // myStream->stats.txFrames--; + break; + default: + DPRINT_INFO(WFA_OUT, "sendto: "); + DPRINT_ERR(WFA_ERR, "send error\n"); + break; + } + +#endif + } + sentTranPkts++; + DPRINT_INFO(WFA_OUT, "SendShortFile: sentTranPkts = %d\r\n",sentTranPkts); + return DONE; +} + +/* In this function we always receive from a specified IP address and Port. We change the receive + * socket from blocking to non-blocking */ +int wfaRecvFile(int mySockfd, int streamid, char *recvBuf) +{ + /* how many packets are received */ + char *packBuf = recvBuf; + struct sockaddr_in fromAddr; + tgProfile_t *theProf; + tgStream_t *myStream; + int bytesRecvd; +#ifndef WIN32 + int ioflags; +#endif + int lostPkts; + + /* find the profile */ + myStream = findStreamProfile(streamid); + + theProf = &myStream->profile; + if(theProf == NULL) + { + return FALSE; + } + + memset(packBuf, 0, MAX_UDP_LEN); + + memset(&fromAddr, 0, sizeof(fromAddr)); + fromAddr.sin_family = AF_INET; + fromAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr); + fromAddr.sin_port = htons(theProf->dport); + + if(gtgRecv && gtgTransac) + { + fromAddr.sin_addr.s_addr = inet_addr(theProf->sipaddr); + fromAddr.sin_port = htons(theProf->sport); + } + else if(gtgSend && gtgTransac) + { + fromAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr); + fromAddr.sin_port = htons(theProf->dport); + } + + /* get current flags setting */ +#ifndef WIN32 + ioflags = fcntl(mySockfd, F_GETFL, 0); + + /* set only BLOCKING flag to non-blocking */ + fcntl(mySockfd, F_SETFL, ioflags | O_NONBLOCK); + +#endif + + /* it is always to receive at least one packet, in case more in the + queue, just pick them up. + */ + if(theProf->profile == PROF_FILE_TX_TCP || theProf->profile == PROF_TRANSC_TCP) + bytesRecvd = wfaCtrlRecv(mySockfd, (unsigned char*)packBuf); + else + bytesRecvd = wfaTrafficRecv(mySockfd, packBuf, (struct sockaddr *)&fromAddr); + + if(bytesRecvd > 0) + { + myStream->stats.rxFrames++; + myStream->stats.rxPayloadBytes +=bytesRecvd; +#ifdef WIN32 + /* + * This sleep is added to avoid driver crash at Dut side when TG sends + * traffic at unlimited frame rate for longer duration + */ + if (myStream->stats.rxFrames % 20 == 0) + usleep(1); +#endif + /* + * Get the lost packet count + */ + lostPkts =bigEndianBuff2Int(&((tgHeader_t *)packBuf)->hdr[8]) - 1 - myStream->lastPktSN; + myStream->stats.lostPkts += lostPkts; + myStream->lastPktSN = bigEndianBuff2Int(&((tgHeader_t *)packBuf)->hdr[8]); + } + return (bytesRecvd); +} + +/* This is going to be a blocking SEND till it finishes + * The code is optimized for to achieve higher through put + * by using hardcoded header buffers + */ +int wfaImprovePerfSendLongFile(int mySockfd, int streamid, BYTE *aRespBuf, int *aRespLen) +{ + tgProfile_t *theProf = NULL; + tgStream_t *myStream = NULL; + struct sockaddr_in toAddr; + char *packBuf; + int packLen; + int bytesSent; + dutCmdResponse_t sendResp; + int errsv; +#ifdef WIN32 + SYSTEMTIME stime; +#else + struct timeval stime; +#endif + + int counter = 0; + + /* find the profile */ + myStream = findStreamProfile(streamid); + if(myStream == NULL) + { + return FALSE; + } + + theProf = &myStream->profile; + + if(theProf == NULL || theProf->duration == 0) /* invalid parameters */ + { + /* encode a TLV for response for "invalid ..." */ + sendResp.status = STATUS_INVALID; + memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t)); + return DONE; + } + + packLen = theProf->pksize; + + /* allocate a buf */ + packBuf = (char *)malloc(packLen); + memset(packBuf, 1, packLen); + + /* fill in the header */ + strncpy(packBuf, "1345678", sizeof(tgHeader_t)); + + /* initialize the destination address */ + memset(&toAddr, 0, sizeof(toAddr)); + toAddr.sin_family = AF_INET; + toAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr); + toAddr.sin_port = htons(theProf->dport); + + /* if a frame rate and duration are defined, then we know + * interval for each packet and how many packets it needs to + * send. + */ + + runLoop=1; + /* + * Fill the hardcoded timestamp to the header. + */ +#ifndef WIN32 + gettimeofday(&stime, NULL); + int2BuffBigEndian(stime.tv_sec, &((tgHeader_t *)packBuf)->hdr[12]); + int2BuffBigEndian(stime.tv_usec, &((tgHeader_t *)packBuf)->hdr[16]); +#else + GetSystemTime(&stime); + int2BuffBigEndian(stime.wSecond, &((tgHeader_t *)packBuf)->hdr[12]); + int2BuffBigEndian(stime.wMilliseconds , &((tgHeader_t *)packBuf)->hdr[16]); +#endif + +#ifndef WIN32 + while (runLoop) +#else + while ((WaitForSingleObject(send_event,0) != WAIT_OBJECT_0)) +#endif + { + counter++; + /* fill in the counter */ + int2BuffBigEndian(counter, &((tgHeader_t *)packBuf)->hdr[8]); + /* + * the following code is only used to slow down + * over fast traffic flooding the buffer and cause + * packet drop or the other end not able to receive due to + * some limitations, purely for experiment purpose. + * each implementation needs some fine tune to it. + */ + if(theProf->profile == PROF_FILE_TX_TCP || theProf->profile == PROF_TRANSC_TCP) + bytesSent = wfaCtrlSend(mySockfd, (unsigned char*)packBuf, packLen); + else + bytesSent = wfaTrafficSendTo(mySockfd, packBuf, packLen, (struct sockaddr *)&toAddr); + + if(bytesSent > 0) + { + myStream->stats.txPayloadBytes += bytesSent; + myStream->stats.txFrames++ ; + } + else if(bytesSent == -1) + { +#ifndef WIN32 + errsv = errno; + switch(errsv) + { + case EAGAIN: + case ENOBUFS: + //DPRINT_INFO(WFA_OUT, "send error\n"); + usleep(50); + counter-- ; + //myStream->stats.txFrames--; + + break; + case ECONNRESET: + runLoop = 0; + break; + case EPIPE: + runLoop = 0; + break; + default: + { + DPRINT_INFO(WFA_OUT, "Packet sent error\n"); + } + } +#else + errsv = WSAGetLastError(); + + switch(errsv) + { + case WSATRY_AGAIN: + case WSAENOBUFS: + DPRINT_INFO(WFA_OUT, "send error\n"); + usleep(1); /* hold for 1 ms */ + counter-- ; + break; + case WSAECONNRESET: + runLoop = 0; + break; + case WSAESHUTDOWN: + runLoop = 0; + break; + default: + DPRINT_INFO(WFA_OUT, "Packet sent error\n"); + break; + } +#endif + } +#ifdef WIN32 + /* In case of win32 we are sleeping after every 20 frame sent. + * This is to avoid driver hang in case of windows mobile + */ + if (myStream->stats.txFrames % 20 == 0) + usleep(1); +#endif + } + gtgSend = 0; + + /* free the buffer */ + free(packBuf); + + /* Populate the statistics of the sent response in Send_dutResp . In the case of multiple streams + * Send_dutResp buffer will have all the response at the end of the send process of all the streams. + */ + sendResp.status = STATUS_COMPLETE; + sendResp.streamId = myStream->id; + memcpy(&sendResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t)); + memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t)); + +#ifndef WIN32 + gnumStreams = gnumStreams -1; + if(IPTVprof == 1) { + if(gnumStreams == 0) + sem_post(&sem_wmm); + + } +#endif + return DONE; +} + +#ifdef WIN32 +DWORD Win32_tmout_stop_send(LPVOID num ) +{ + int i; + + Sleep((DWORD)num); + DPRINT_INFO(WFA_OUT, "timer fired, stop sending traffic\n"); + /* + * After runLoop reset, all sendLong will stop + */ + runLoop = 0; + /*Reset to stop sending the short file*/ + gTransactrunLoop = 0; + /* + * Decrement the usedThread everytime the timeout function is called . + */ + --usedThread ; + + if(usedThread ==0 && IPTVprof == 1) { + asd_sleep(1); + /* Set the event when there are no more streams to send the traffic */ + if(SetEvent(send_event)== 0 ){ + DPRINT_INFO(WFA_OUT, "SetEvent failure %d \n", GetLastError()); + } + /* + * all WMM streams also stop + */ + for(i=0; i<WFA_TRAFFIC_CLASS_NUM; i++) + { + if(g_TGSndThr[i] != NULL){ + CloseHandle(g_TGSndThr[i]); + g_TGSndThr[i] = NULL; + } + } + } + /* + * once the stream table slot count is reset, it implies that the test + * is done. When the next set profile command comes in, it will reset/clean + * the stream table. + */ + slotCnt = 0; + + /* + * The test is for DT3 transaction test. + * Timeout to stop it. + */ + if(gtgTransac != 0) + { + gtgTransac = 0; + gtgSend = 0; + gtimeOut = 0; + gRegSec = 1; + gtgRecv = 0; + } + + return 0; +} + +#endif
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_thr.c b/src/tools/Wifi_ASD_test/lib/wfa_thr.c new file mode 100755 index 0000000..d0604bb --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_thr.c
@@ -0,0 +1,347 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ +/* Revision History: + * 2006/11/10 -- initial created by qhu + * 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * + */ + +/* + * For MADWIFI driver, the TOS to 11E queue mapping as: + * 0x08, 0x20 ----> WME_AC_BK; + * 0x28, 0xa0 ----> WMC_AC_VI; + * 0x30, 0xe0 0x88, 0xb8 ----> WME_AC_VO + * here 0x88 for UPSD, will be implemented later + * all other/default ----> WME_AC_BE; + */ + + +#include <stdio.h> + +#include <string.h> +#include <stdlib.h> + +#ifndef WIN32 +#include <pthread.h> +#include <sys/socket.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <signal.h> +#include <errno.h> +#endif /* !WIN32 */ +#include <wfa_debug.h> + +#include "wfa_types.h" +#include "wfa_main.h" +#include "wfa_tg.h" +#include "wfa_debug.h" +#include "wfa_tlv.h" +#include "wfa_sock.h" +#include "wfa_rsp.h" +#include "wfa_wmmps.h" +#include "wfa_miscs.h" +#include "wfa_ca_resp.h" +/* + * external global thread sync variables + */ +#ifdef WIN32 +extern HANDLE thr_flag_cond; +extern HANDLE thr_stop_cond; +extern void Win32_tmout_stop_send(LPVOID num ) ; +#endif /* WIN32 */ + +#ifdef WFA_WMM_EXT +extern tgWMM_t wmm_thr[]; +#endif /* WFA_WMM_EXT */ + +extern tgStream_t *findStreamProfile(int id); +extern int gxcSockfd; +extern int wfaSetProcPriority(int); +extern tgStream_t *gStreams; +extern int IPTVprof; +extern int resetsnd; + +#ifdef WFA_WMM_PS_EXT +extern int gtgWmmPS; +extern int psSockfd; +extern int **ac_seq; +int num_hello = 0; +int num_stops = 0; +extern wfaWmmPS_t wmmps_info; +extern void wfaSetDUTPwrMgmt(int mode); +extern void BUILD_APTS_MSG(int msg, unsigned long *txbuf); +extern void wmmps_wait_state_proc(); +extern void mpx(char *m,void *buf_v,int len); +extern unsigned int psTxMsg[]; +extern unsigned int psRxMsg[]; +int msgsize = 256; +extern StationProcStatetbl_t stationProcStatetbl[LAST_TEST+1][11]; +#endif /* WFA_WMM_PS_EXT */ + +extern void wfaGetSockOpt(int sockfd, int* tosval, socklen_t* size); +extern int wfaSetSockOpt(int sockfd, int* tosval, int size); +void tmout_stop_send(int num) ; + +/* + * wfaTGSetPrio(): This depends on the network interface card. + * So you might want to remap according to the driver + * provided. + * The current implementation is to set the TOS/DSCP bits + * in the IP header + */ +int wfaTGSetPrio(int sockfd, int tgUserPriority) +{ + int tosval; + + socklen_t size = sizeof(tosval); + + wfaGetSockOpt(sockfd, &tosval, &size); + + switch(tgUserPriority) + { + case TG_WMM_AC_BK: + tosval = TOS_BK; + break; + case TG_WMM_AC_VI: + tosval = TOS_VI; + break; + case TG_WMM_AC_UAPSD: + tosval = 0x88; + break; + case TG_WMM_AC_VO: + tosval = TOS_VO; + break; + case TG_WMM_AC_BE: + tosval = TOS_BE; + default: + tosval = 0x00; + /* default */ + ; + } +#ifdef WFA_WMM_EXT +#ifdef WFA_WMM_PS_EXT + psTxMsg[1] = tosval; +#endif /* WFA_WMM_PS_EXT*/ +#endif /* WFA_WMM_EXT*/ + + if(wfaSetSockOpt(sockfd, &tosval, sizeof(tosval)) != 0) + { + DPRINT_ERR(WFA_ERR, "Failed to set IP_TOS\n"); + } + return (tosval == 0xE0)?0xD8:tosval; +} + +#ifdef WFA_WMM_EXT +#ifdef WFA_WMM_PS_EXT +/* + * sender(): This is a generic function to send a packed for the given dsc + * (ac:VI/VO/BE/BK), before sending the packet the function + * puts the station into the PS mode indicated by psave and + * sends the packet after sleeping for sllep_period + */ +int sender(char psave,int sleep_period,int dsc) +{ + int r; + PRINTF("\nsleeping for %d",sleep_period); + wfaSetDUTPwrMgmt(psave); + uapsd_sleep(sleep_period); + PRINTF("\nAfter create sending %d\n",dsc); + create_apts_msg(APTS_DEFAULT, psTxMsg,wmmps_info.my_sta_id); + wfaTGSetPrio(psSockfd, dsc); + PRINTF("\nAfter create"); + PRINTF("\nlock met"); + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + return r; +} + +/* + * wfaStaSndConfirm(): This function sends the confirm packet + * which is sent after the console sends the + * test name to the station + */ +int WfaStaSndConfirm(char psave,int sleep_period,int *state) +{ + int r; + static int num_hello=0; + wfaSetDUTPwrMgmt(psave); + if(!num_hello) + create_apts_msg(APTS_CONFIRM, psTxMsg,0); + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + (*state)++; + + return 0; +} + +/* + * WfaStaSndVO(): This function sends a AC_VO packet + * after the time specified by sleep_period + * and advances to the next state for the given test case + */ +int WfaStaSndVO(char psave,int sleep_period,int *state) +{ + int r; + static int en=1; + PRINTF("\r\nEnterring WfastasndVO %d",en++); + if ((r=sender(psave,sleep_period,TG_WMM_AC_VO))>=0) + (*state)++; + else + PRINTF("\r\nError\n"); + + return 0; +} + +/* + * WfaStaSnd2VO(): This function sends two AC_VO packets + * after the time specified by sleep_period + * and advances to the next state for the given test case + */ +int WfaStaSnd2VO(char psave,int sleep_period,int *state) +{ + int r; + static int en=1; + + PRINTF("\r\nEnterring WfastasndVO %d",en++); + if ((r=sender(psave,sleep_period,TG_WMM_AC_VO))>=0) + { + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + mpx("STA msg",psTxMsg,64); + (*state)++; + } + else + PRINTF("\r\nError\n"); + + return 0; +} + +/* + * WfaStaSndVI(): This function sends a AC_VI packet + * after the time specified by sleep_period + * and advances to the next state for the given test case + */ +int WfaStaSndVI(char psave,int sleep_period,int *state) +{ + int r; + static int en=1; + + PRINTF("\r\nEnterring WfastasndVI %d",en++); + if ((r=sender(psave,sleep_period,TG_WMM_AC_VI))>=0) + (*state)++; + + return 0; +} + +/* + * WfaStaSndBE(): This function sends a AC_BE packet + * after the time specified by sleep_period + * and advances to the next state for the given test case + */ +int WfaStaSndBE(char psave,int sleep_period,int *state) +{ + int r; + static int en=1; + + PRINTF("\r\nEnterring WfastasndBE %d",en++); + if ((r=sender(psave,sleep_period,TG_WMM_AC_BE))>=0) + (*state)++; + + return 0; +} +/* + * WfaStaSndBK(): This function sends a AC_BK packet + * after the time specified by sleep_period + * and advances to the next state for the given test case + */ +int WfaStaSndBK(char psave,int sleep_period,int *state) +{ + int r; + static int en=1; + + PRINTF("\r\nEnterring WfastasndBK %d",en++); + if ((r=sender(psave,sleep_period,TG_WMM_AC_BK))>=0) + (*state)++; + + return 0; +} + +/* + * WfaStaSndVOCyclic(): The function is the traffic generator for the L.1 test + * caseThis function sends 3000 AC_VO packet + * after the time specified by sleep_period (20ms) + */ +int WfaStaSndVOCyclic(char psave,int sleep_period,int *state) +{ + int i; + static int en=1; + + for(i=0;i<3000;i++) + { + PRINTF("\r\nEnterring WfastasndVOCyclic %d",en++); + sender(psave,sleep_period,TG_WMM_AC_VO); + if(!(i%50)) + { + PRINTF("."); + fflush(stdout); + } + } + (*state)++; + return 0; +} +#endif /* WFA_WMM_PS_EXT */ +#endif /* WFA_WMM_EXT */
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_tlv.c b/src/tools/Wifi_ASD_test/lib/wfa_tlv.c new file mode 100644 index 0000000..30fa568 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_tlv.c
@@ -0,0 +1,204 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ + +/* + * file: wfa_tlv.c + * The file contains all TLV process functions, including Encode, Decode, etc + * TLV stands for Tag, Length, Value. + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA release by qhu + * 2006/06/13 -- 00.02 release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/09/01 -- 01.05 Release by qhu + * 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * -- make sure the the data len must be less than buffer size, + * a potential bug reported by rmaeder and ydror + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "wfa_main.h" +#include "wfa_debug.h" +#include "wfa_types.h" +#include "wfa_tlv.h" + +extern unsigned short wfa_defined_debug; + +/* + * wfaEncodeTLV(): Encoding a packet to TLV format + * input: the_tag - packet type + * the_len - the value length + * the_value - the value buffer + * + * output: tlv_data - encoded TLV packet buffer. Caller must allocate the buffer + */ +BOOL wfaEncodeTLV(WORD the_tag, WORD the_len, BYTE *the_value, BYTE *tlv_data) +{ + void *data = tlv_data; + + ((wfaTLV *)data)->tag = the_tag; + ((wfaTLV *)data)->len = the_len; + if(the_value != NULL && the_len != 0) + memcpy(((BYTE*)data+4), (BYTE *)the_value, the_len); + + return TRUE; +} + +/* + * wfaDecodeTLV(); Decoding a TLV format into actually values + * input: tlv_data - the TLV format packet buffer + * tlv_len - the total length of the TLV + * output: ptag - the TLV type + * pval_len - the value length + * pvalue - value buffer, caller must allocate the buffer + */ + +BOOL wfaDecodeTLV(BYTE *tlv_data, int tlv_len, BYTE *ptag, int *pval_len, BYTE *pvalue) +{ + wfaTLV *data = (wfaTLV *)tlv_data; + + if(pvalue == NULL) + { + DPRINT_ERR(WFA_ERR, "Parm buf invalid\n"); + return FALSE; + } + *ptag = (BYTE)data->tag; + *pval_len = data->len; + + if(tlv_len < *pval_len) + return FALSE; + + if(*pval_len != 0 && *pval_len < MAX_PARMS_BUFF) + { + memcpy(pvalue, tlv_data+4, *pval_len); + } + + return TRUE; +} + +/* + * wfaGetTLVTag(): the individual function to retrieve a TLV type. + * input: tlv_data - TLV buffer + * return: the TLV type. + */ + +WORD wfaGetTLVTag(BYTE *tlv_data) +{ + wfaTLV *ptlv = (wfaTLV *)tlv_data; + + if(ptlv != NULL) + return ptlv->tag; + + return TRUE; +} + +/* + * wfaSetTLVTag(): the individual function to set TLV type. + * input: new_tag - the new TLV type. + * Output: tlv_data - a TLV buffer, caller must allocate this buffer. + */ + +BOOL wfaSetTLVTag(BYTE new_tag, BYTE *tlv_data) +{ + wfaTLV *ptlv = (wfaTLV *)tlv_data; + + if(tlv_data == NULL) + return FALSE; + + ptlv->tag = new_tag; + + return TRUE; +} + +/* + * wfaGetTLVLen(): retrieve a TLV value length + * input: tlv_data - a TLV buffer + * return: the value length. + */ + +WORD wfaGetTLVLen(BYTE *tlv_data) +{ + wfaTLV *ptlv = (wfaTLV *)tlv_data; + + if(tlv_data == NULL) + return FALSE; + + return ptlv->len; +} + +/* + * wfaGetTLVValue(): retrieve a TLV value + * input: value_len - TLV value length + * tlv_data - a TLV data buffer + * output: pvalue - the value buffer, caller must allocate it. + */ + +BOOL wfaGetTLVvalue(int value_len, BYTE *tlv_data, BYTE *pvalue) +{ + if(tlv_data == NULL) + return FALSE; + + memcpy(pvalue, tlv_data+WFA_TLV_HEAD_LEN, value_len); + + return TRUE; +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_typestr.c b/src/tools/Wifi_ASD_test/lib/wfa_typestr.c new file mode 100644 index 0000000..9c144cb --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_typestr.c
@@ -0,0 +1,193 @@ + +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee$B!G(Bs proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below..AN The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee$B!G(Bs product to their customers with or + * without such third party$B!G(Bs private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance + * reserves all rights not expressly granted herein..AN + *.AN + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + *.AN + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + *.AN + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** + */ +/* + * wfa_typestr.c: + * global array of the mapping of command types, command strings + * to attached processing function + * + * Revision History: + * 2006/03/10 -- initially created by qhu + * 2006/06/01 -- BETA release by qhu + * 2006/06/13 -- 00.02 release by qhu + * 2006/06/30 -- 00.10 Release by qhu + * 2006/07/10 -- 01.00 Release by qhu + * 2006/09/01 -- 01.05 Release by qhu + * 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu + * 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu + * 2007/08/15 -- 02.10 WMM-Power Save release by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + */ +#include <stdio.h> +#ifndef WIN32 +#include <pthread.h> +#endif +#include "wfa_types.h" +#include "wfa_tlv.h" +#include "wfa_tg.h" +#include "wfa_cmds.h" +#include "wfa_agtctrl.h" + +extern int cmdProcNotDefinedYet(char *, BYTE *, int *); +extern int xcCmdProcGetVersion(char *, BYTE *, int *); +extern int xcCmdProcAgentConfig(char *, BYTE *, int *); +extern int xcCmdProcAgentSend(char *, BYTE *, int *); +extern int xcCmdProcAgentRecvStart(char *, BYTE *, int *); +extern int xcCmdProcAgentRecvStop(char *, BYTE *, int *); +extern int xcCmdProcAgentReset(char *, BYTE *, int *); +extern int xcCmdProcStaGetIpConfig(char *, BYTE *, int *); +extern int xcCmdProcStaSetIpConfig(char *, BYTE *, int *); +extern int xcCmdProcStaGetMacAddress(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaIsConnected(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaVerifyIpConnection(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaGetBSSID(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaGetStats(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetEncryption(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetPSK(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetEapTLS(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetEapTTLS(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetEapSIM(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetPEAP(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetIBSS(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcDeviceGetInfo(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcDeviceListIF(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaAssociate(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetUAPSD(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaGetInfo(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcAgentSendPing(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcAgentStopPing(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaDebugSet(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetMode(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetWMM(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetSystime(char *pcmdStr, BYTE *, int *); +#ifdef WFA_STA_TB +extern int xcCmdProcStaNeigreq(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSet11n(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetRIFSTest(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetWireless(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSendAddba(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSendCoexistMGMT(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaDisconnect(char *pcmdStr, BYTE *, int *); +#endif +extern int xcCmdProcStaSetEapFAST(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetEapAKA(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaReAssociate(char *pcmStr, BYTE *, int *); +extern int xcCmdProcStaResetDefault(char *pcmdStr, BYTE *, int *); +extern int xcCmdProcStaSetPwrSave(char *pcmdStr, BYTE *, int *); + +/* + * Initialize a command name table to its defined type and process function + * These commands get executed at the DUT side. + */ +typeNameStr_t nameStr[] = +{ + {0, "NO_USED_STRING", NULL}, + {WFA_GET_VERSION_TLV, "ca_get_version", xcCmdProcGetVersion}, + {WFA_TRAFFIC_SEND_PING_TLV, "traffic_send_ping", xcCmdProcAgentSendPing}, + {WFA_TRAFFIC_STOP_PING_TLV, "traffic_stop_ping", xcCmdProcAgentStopPing}, + {WFA_TRAFFIC_AGENT_CONFIG_TLV, "traffic_agent_config", xcCmdProcAgentConfig}, + {WFA_TRAFFIC_AGENT_SEND_TLV, "traffic_agent_send", xcCmdProcAgentSend}, + {WFA_TRAFFIC_AGENT_RESET_TLV, "traffic_agent_reset", xcCmdProcAgentReset}, + {WFA_TRAFFIC_AGENT_RECV_START_TLV, "traffic_agent_receive_start", xcCmdProcAgentRecvStart}, + {WFA_TRAFFIC_AGENT_RECV_STOP_TLV, "traffic_agent_receive_stop", xcCmdProcAgentRecvStop}, + {WFA_STA_GET_IP_CONFIG_TLV, "sta_get_ip_config", xcCmdProcStaGetIpConfig}, + {WFA_DEVICE_LIST_IF_TLV, "device_list_interfaces", xcCmdProcDeviceListIF}, + {WFA_STA_SET_IP_CONFIG_TLV, "sta_set_ip_config", xcCmdProcStaSetIpConfig}, + {WFA_STA_VERIFY_IP_CONNECTION_TLV, "sta_verify_ip_connection", xcCmdProcStaVerifyIpConnection}, + {WFA_STA_SET_SYSTIME_TLV, "sta_set_systime", xcCmdProcStaSetSystime}, + {WFA_STA_SET_EAPFAST_TLV, "sta_set_eapfast", xcCmdProcStaSetEapFAST}, + {WFA_STA_SET_EAPAKA_TLV, "sta_set_eapaka", xcCmdProcStaSetEapAKA}, + {-1, "", NULL} +}; + + +/* functions to be executed from RWL server + * These control commands get executed from CA which calls Rwl client with the + * required transport options + */ +typeNameStr_t nameLocalStr[] = +{ + {0, "NO_USED_STRING", NULL}, + {WFA_STA_ASSOCIATE_TLV, "sta_associate", xcCmdProcStaAssociate}, + {WFA_STA_IS_CONNECTED_TLV, "sta_is_connected", xcCmdProcStaIsConnected}, + {WFA_STA_GET_MAC_ADDRESS_TLV, "sta_get_mac_address", xcCmdProcStaGetMacAddress}, + {WFA_STA_GET_BSSID_TLV, "sta_get_bssid", xcCmdProcStaGetBSSID}, + {WFA_STA_GET_STATS_TLV, "sta_get_stats", xcCmdProcStaGetStats}, + {WFA_STA_GET_INFO_TLV, "sta_get_info", xcCmdProcStaGetInfo}, + {WFA_STA_SET_MODE_TLV, "sta_set_mode", xcCmdProcStaSetMode}, + {WFA_STA_SET_WMM_TLV, "sta_set_wmm", xcCmdProcStaSetWMM}, + {WFA_DEVICE_GET_INFO_TLV, "device_get_info", xcCmdProcDeviceGetInfo}, + {WFA_STA_SET_ENCRYPTION_TLV, "sta_set_encryption", xcCmdProcStaSetEncryption}, + {WFA_STA_SET_PSK_TLV, "sta_set_psk", xcCmdProcStaSetPSK}, + {WFA_STA_SET_EAPTLS_TLV, "sta_set_eaptls", xcCmdProcStaSetEapTLS}, + {WFA_STA_SET_EAPTTLS_TLV, "sta_set_eapttls", xcCmdProcStaSetEapTTLS}, + {WFA_STA_SET_EAPSIM_TLV, "sta_set_eapsim", xcCmdProcStaSetEapSIM}, + {WFA_STA_SET_UAPSD_TLV, "sta_set_uapsd", xcCmdProcStaSetUAPSD}, /* Added as per BRCM 1.3 ASD */ + {WFA_STA_SET_IBSS_TLV, "sta_set_ibss", xcCmdProcStaSetIBSS}, + {WFA_STA_SET_PEAP_TLV, "sta_set_peap", xcCmdProcStaSetPEAP}, + {WFA_STA_DEBUG_SET_TLV, "sta_debug_set", xcCmdProcStaDebugSet}, +#ifdef WFA_STA_TB + {WFA_STA_SEND_NEIGREQ_TLV, "sta_send_neigreq", xcCmdProcStaNeigreq}, + {WFA_STA_SET_11N_TLV, "sta_set_11n", xcCmdProcStaSet11n}, + {WFA_STA_SET_RIFS_TEST_TLV, "sta_set_rifs_test", xcCmdProcStaSetRIFSTest}, + {WFA_STA_SET_WIRELESS_TLV, "sta_set_wireless", xcCmdProcStaSetWireless}, + {WFA_STA_SEND_ADDBA_TLV, "sta_send_addba", xcCmdProcStaSendAddba}, + {WFA_STA_SEND_COEXIST_MGMT_TLV, "sta_send_coexist_mgmt", xcCmdProcStaSendCoexistMGMT}, + {WFA_STA_DISCONNECT_TLV, "sta_disconnect", xcCmdProcStaDisconnect}, +#endif + {WFA_STA_REASSOCIATE_TLV, "sta_reassociate", xcCmdProcStaReAssociate}, + {WFA_STA_RESET_DEFAULT_TLV, "sta_reset_default", xcCmdProcStaResetDefault}, + {WFA_STA_SET_PWRSAVE_TLV, "sta_set_pwrsave", xcCmdProcStaSetPwrSave}, + {-1, "", NULL} +};
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_wmmps.c b/src/tools/Wifi_ASD_test/lib/wfa_wmmps.c new file mode 100644 index 0000000..b4f4d74 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_wmmps.c
@@ -0,0 +1,737 @@ +/**************************************************************************** + * (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved + * + * + * LICENSE + * + * License is granted only to Wi-Fi Alliance members and designated + * contractors (“Authorized Licensees”). Authorized Licensees are granted + * the non-exclusive, worldwide, limited right to use, copy, import, export + * and distribute this software: + * (i) solely for noncommercial applications and solely for testing Wi-Fi + * equipment; and + * (ii) solely for the purpose of embedding the software into Authorized + * Licensee’s proprietary equipment and software products for distribution to + * its customers under a license with at least the same restrictions as + * contained in this License, including, without limitation, the disclaimer of + * warranty and limitation of liability, below. The distribution rights + * granted in clause + * (ii), above, include distribution to third party companies who will + * redistribute the Authorized Licensee’s product to their customers with or + * without such third party’s private label. Other than expressly granted + * herein, this License is not transferable or sublicensable, and it does not + * extend to and may not be used with non-Wi-Fi applications. Wi-Fi Alliance + * reserves all rights not expressly granted herein. + * + * Except as specifically set forth above, commercial derivative works of + * this software or applications that use the Wi-Fi scripts generated by this + * software are NOT AUTHORIZED without specific prior written permission from + * Wi-Fi Alliance. + * + * Non-Commercial derivative works of this software for internal use are + * authorized and are limited by the same restrictions; provided, however, + * that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of + * such derivative works under a perpetual, payment-free license to use, + * modify, and distribute such derivative works for purposes of testing Wi-Fi + * equipment. + * + * Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse + * or promote products that are derived from or that use this software without + * specific prior written permission from Wi-Fi Alliance. + * + * THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE, + * ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************** + */ + +/* Revision History: + * 2007/07/25 -- Initial created by qhu + * 2007/08/15 -- 02.10 WMM-Power Save Released by qhu + * 2007/10/10 -- 02.20 Voice SOHO beta -- qhu + * 2007/11/07 -- 02.30 Voice HSO -- qhu + * 2007/12/10 -- 02.32 no change + * 2008/02/07 -- 02.40 Upgrade the new WMM-PS method. + * 2008/03/20 -- 02.41 [Bug #18] In some devices, "num_hello" reaches its + * upper limit, causing other tests to reset. The + * counter now resets at the completion of each test. + * Affected Function(s): wfaRcvProc() + * + * [None] Print message too long and frequent. Remove + * trace messages for L1. + * + */ + +#ifdef WFA_WMM_EXT +#ifdef WFA_WMM_PS_EXT + +#ifndef WIN32 +#include <netdb.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <pthread.h> +#endif /* !WIN32 */ + +#include "wfa_debug.h" +#include "wfa_sock.h" +#include "wfa_types.h" +#include "wfa_tg.h" +#include "wfa_ca.h" +#include "wfa_wmmps.h" +#include "wfa_miscs.h" +#include "wfa_main.h" + +extern int psSockfd; +extern int num_hello; +extern tgWMM_t wmm_thr[]; + +extern unsigned int psTxMsg[512]; +extern unsigned int psRxMsg[512]; +extern int msgsize; + +int resetsnd=0; +int reset_recd=0; +int resetrcv=0; +int num_retry=0; +int gtgPsPktRecvd = 0; // need to reset + +extern wfaWmmPS_t wmmps_info; +extern void *g_wl_handle; + +extern int wfaTGSetPrio(int sockfd, int tgClass); +void wmmps_wait_state_proc(); +void wfaSetDUTPwrMgmt(int mode); + +/* APTS messages*/ +struct apts_msg apts_msgs[] ={ + {0, -1}, + {"B.D", B_D}, + {"B.H", B_H}, + {"B.B", B_B}, + {"B.M", B_M}, + {"M.D", M_D}, + {"B.Z", B_Z}, + {"M.Y", M_Y}, + {"L.1", L_1}, + {"A.Y", A_Y}, + {"B.W", B_W}, + {"A.J", A_J}, + {"M.V", M_V}, + {"M.U", M_U}, + {"A.U", A_U}, + {"M.L", M_L}, + {"B.K", B_K}, + {"M.B", M_B}, + {"M.K", M_K}, + {"M.W", M_W}, +#ifdef WFA_WMM_AC + {"ATC1", ATC1}, + {"ATC2", ATC2}, + {"ATC3", ATC3}, + {"ATC4", ATC4}, + {"ATC5", ATC5}, + {"ATC6", ATC6}, + {"ATC7", ATC7}, + {"ATC8", ATC8}, + {"ATC9", ATC9}, + {"ATC10", ATC10}, + {"ATC11", ATC11}, + {"STC1", STC1}, + {"STC2", STC2}, + {"STC3", STC3}, +#endif + {"APTS TX ", APTS_DEFAULT }, + {"APTS Hello ", APTS_HELLO }, + {"APTS Broadcast ", APTS_BCST }, + {"APTS Confirm ", APTS_CONFIRM}, + {"APTS STOP ", APTS_STOP}, + {"APTS CK BE ", APTS_CK_BE }, + {"APTS CK BK ", APTS_CK_BK }, + {"APTS CK VI ", APTS_CK_VI }, + {"APTS CK VO ", APTS_CK_VO }, + {"APTS RESET ", APTS_RESET }, + {"APTS RESET RESP ", APTS_RESET_RESP }, + {"APTS RESET STOP ", APTS_RESET_STOP }, + {0, 0 } // APTS_LAST +}; +/* The DUT recv table for each of the test cases*/ +StationRecvProcStatetbl_t stationRecvProcStatetbl[LAST_TEST+1][6] = +{ + {WfaRcvStop,0,0,0,0,0}, + /*B.D*/ {WfaRcvProc,WfaRcvVO,WfaRcvStop,0,0,0}, + /*B.H*/ {WfaRcvProc,WfaRcvVO,WfaRcvVO,WfaRcvStop,0,0}, + /*B.B*/ {WfaRcvProc,WfaRcvStop,0,0,0,0}, + /*B.M*/ {WfaRcvProc,WfaRcvStop,0,0,0,0}, + /*M.D*/ {WfaRcvProc,WfaRcvBE,WfaRcvBK,WfaRcvVI,WfaRcvVO,WfaRcvStop}, + /*B.Z*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvStop,0,0}, + /*M.Y*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvBE,WfaRcvStop,0}, + /*L.1*/ {WfaRcvProc,WfaRcvVOCyclic,0,0,0,0}, + /*A.Y*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvBE,WfaRcvStop,0}, + /*B.W*/ {WfaRcvProc,WfaRcvBE,WfaRcvVI,WfaRcvBE,WfaRcvVI,WfaRcvStop}, + /*A.J*/ {WfaRcvProc,WfaRcvVO,WfaRcvVI,WfaRcvBE,WfaRcvBK,WfaRcvStop}, + /*M.V*/ {WfaRcvProc,WfaRcvBE,WfaRcvVI,WfaRcvStop,0,0}, + /*M.U*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvVO,WfaRcvVO,WfaRcvStop}, + /*A.U*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvVO,WfaRcvStop,0}, + /*M.L*/ {WfaRcvProc,WfaRcvBE,WfaRcvStop,0,0,0}, + /*B.K*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvStop,0,0}, + /*M.B*/ {WfaRcvProc,WfaRcvStop,0,0,0,0}, + /*M.K*/ {WfaRcvProc,WfaRcvBE,WfaRcvVI,WfaRcvStop,0,0}, + /*M.W*/ {WfaRcvProc,WfaRcvBE,WfaRcvBE,WfaRcvBE,WfaRcvVI,WfaRcvStop} +#ifdef WFA_WMM_AC + /*ATC1*/ ,{WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvStop}, + /*ATC2*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvBE,WfaRcvStop}, + /*ATC3*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvBE,WfaRcvStop}, + /*ATC4*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvVO,WfaRcvVO,WfaRcvStop}, + /*ATC5*/ {WfaRcvProc,WfaRcvVI,WfaRcvVO,WfaRcvStop}, + /*ATC6*/ {WfaRcvProc,WfaRcvVO,WfaRcvVI,WfaRcvVI,WfaRcvStop}, + /*ATC7*/ {WfaRcvProc,WfaRcvVO,WfaRcvVI,WfaRcvBE,WfaRcvBK,WfaRcvStop}, + /*ATC8*/ {WfaRcvProc,WfaRcvVO,WfaRcvVI,WfaRcvStop}, + /*ATC9*/ {WfaRcvProc,WfaRcvVO,WfaRcvVI,WfaRcvBE,WfaRcvBK,WfaRcvStop}, + /*ATC10*/{WfaRcvProc,WfaRcvVO,WfaRcvVI,WfaRcvBE,WfaRcvBK,WfaRcvStop}, + /*ATC11*/{WfaRcvProc,WfaRcvVO,WfaRcvVO,WfaRcvVI,WfaRcvVO,WfaRcvStop}, + /*STC1*/ {WfaRcvProc,WfaRcvVI,WfaRcvBE,WfaRcvStop}, + /*STC2*/ {WfaRcvProc,WfaRcvBE,WfaRcvVI,WfaRcvStop}, + /*STC3*/ {WfaRcvProc,WfaRcvBE,WfaRcvBK,WfaRcvVI,WfaRcvVO,WfaRcvStop} +#endif +}; +/* The DUT send table for each of the test cases*/ + +StationProcStatetbl_t stationProcStatetbl[LAST_TEST+1][11] = { +/* Dummy*/{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}}, +/* B.D*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, + {WfaStaSndVO,P_ON,LII / 2} ,{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* B.H*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* B.B*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndBK,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2},{0,0,0},{0,0,0},{0,0,0}}, + +/* B.M*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,30000000},{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* M.D*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2},{0,0,0},{0,0,0},{0,0,0}}, + +/* B.Z*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, + {WfaStaSndVO,P_ON,LII / 2 } ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* M.Y*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, + {WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2},{0,0,0},{0,0,0},{0,0,0}}, + +/* L.1*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, + {WfaStaSndVOCyclic,P_ON,20000},{WfaStaWaitStop,P_ON,LII / 2 }}, + +/* A.Y*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, + {WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndBE,P_OFF,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2},{0,0,0},{0,0,0}}, + +/* B.W*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* A.J*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaSndVO,P_OFF,LII / 2},{WfaStaWaitStop ,P_ON,LII / 2},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* M.V*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaWaitStop ,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* M.U*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, + {WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSnd2VO,P_ON,LII / 2} ,{WfaStaWaitStop ,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* A.U*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndBE,P_OFF,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndBE,P_OFF,LII / 2} ,{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaSndVO,P_OFF,LII / 2} ,{WfaStaWaitStop ,P_ON,LII / 2},{0,0,0}}, + +/* M.L*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* B.K*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* M.B*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVO,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndBK,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, + +/* M.K*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, + +/* M.W*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaSndBE,P_ON,LII / 2} ,{WfaStaSndVI,P_ON,LII / 2} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0}} +#ifdef WFA_WMM_AC +/* ATC1*/ ,{{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVO,P_ON,1000000} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, +/* ATC2*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,1000000} ,{WfaStaSndVO,P_ON,1000000} ,{WfaStaSndBE,P_ON,1000000} ,{WfaStaSndBE,P_ON,1000000} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, +/* ATC3*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndVO,P_ON,1000000} ,{WfaStaSndBE,P_ON,1000000} ,{WfaStaSndBE,P_ON,1000000} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, +/* ATC4*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,lis_int} ,{WfaStaSndBE,P_ON,1000000} ,{WfaStaSndVO,P_ON,1000000} ,{WfaStaSndVO,P_ON,1} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, +/* ATC5*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, 1}, +{WfaStaSndVI,P_ON,lis_int} ,{WfaStaSndVO,P_ON,lis_int+2*becon_int} ,{WfaStaSndVO,P_ON,becon_int} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, +/* ATC6*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndVO,P_ON,lis_int} ,{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndVO,P_ON,becon_int} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, +/* ATC7*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndVO,P_ON,lis_int} ,{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndVO,P_ON,becon_int} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, +/* ATC8*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVO,P_ON,lis_int} ,{WfaStaSndVI,P_ON,lis_int+2*becon_int} ,{WfaStaSndVI,P_ON,becon_int} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, +/* ATC9*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndBE,P_ON,becon_int} ,{WfaStaSndVO,P_ON,lis_int} ,{WfaStaSndBE,P_ON,becon_int} ,{WfaStaSndVI,P_ON,becon_int} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, +/* ATC10*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndBE,P_ON,lis_int} ,{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndBE,P_ON,becon_int} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, +/* ATC11*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndBE,P_ON,becon_int} ,{WfaStaSndVI,P_ON,lis_int} ,{WfaStaSndBE,P_ON,becon_int} ,{WfaStaSndVO,P_ON,lis_int} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0}}, +/* STC1*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndBE,P_ON,1000000} ,{WfaStaSndVI,P_ON,1000000} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, +/* STC2*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndBE,P_ON,1000000} ,{WfaStaSndVO,P_ON,1000000} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, +/* STC3*/ {{WfaStaSndHello,P_OFF, 1000000},{WfaStaSndConfirm,P_ON, LII / 2}, +{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndVI,P_ON,becon_int} ,{WfaStaSndVI,P_ON,becon_int} ,{WfaStaWaitStop,P_ON,LII / 2} ,{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}} +#endif + +}; + +int ac_seq[APTS_LAST][6] ={ + {0, 0, 0, 0, 0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, // APTS_TESTS + {0}, // B.D + {0}, // B.2 + {0}, // B.H + {0}, // B.4 + {0}, // B_5 + {0, 0, 0, 0, 0}, // B_6 + {TG_WMM_AC_VO, TG_WMM_AC_VI, TG_WMM_AC_BE, TG_WMM_AC_BK, 0}, // B.B B_B - 4 exchanges: 1 uplink, 0 downlink + {0}, // B.E + {0}, // B.G + {0}, // B.I + {0}, // M.D + {0}, // M.G + {0}, // M.I + {0}, // B.Z 1, 1, 1, 0}, // 1 special exchange for Broadcast testing + {TG_WMM_AC_VI, TG_WMM_AC_VO, TG_WMM_AC_BE, TG_WMM_AC_BE, 0}, // M.Y M_Y 2 special exchange for Broadcast testing + {0}, // L.1 + {0}, // DLOAD + {0}, // ULOAD + {0}, // "APTS PASS" + {0}, // "APTS FAIL" + //{TOS_VI, TOS_VO, TOS_BE, TOS_BE, 0}, // A.Y A_Y special exchange for Broadcast testing + {TG_WMM_AC_VI, TG_WMM_AC_VO, TG_WMM_AC_BE, TG_WMM_AC_BE, TG_WMM_AC_BE}, // A.Y A_Y special exchange for Broadcast testing + {0}, // B.W 2 special exchange for Broadcast testing + {0}, // A.J + {TG_WMM_AC_VI, TG_WMM_AC_BE, TG_WMM_AC_VI, TG_WMM_AC_VI, TG_WMM_AC_VI}, // M.V M_V + {TG_WMM_AC_VI, TG_WMM_AC_BE, TG_WMM_AC_VO, TG_WMM_AC_VO, TG_WMM_AC_VO}, // M.U M_U + {TG_WMM_AC_VI, TG_WMM_AC_BE, TG_WMM_AC_BE, TG_WMM_AC_BE, TG_WMM_AC_VO, TG_WMM_AC_VO}, // A.U A_U + {0}, // M.L M_L + {TG_WMM_AC_VI, TG_WMM_AC_BE, TG_WMM_AC_VI, TG_WMM_AC_VI, 0}, // B.K B_K + {TG_WMM_AC_VO, TG_WMM_AC_VI, TG_WMM_AC_BE, TG_WMM_AC_BK, 0}, // M.B M_B - 4 exchanges: 1 uplink, 0 downlink + {TG_WMM_AC_VI, TG_WMM_AC_BE, TG_WMM_AC_VI, TG_WMM_AC_VI, 0}, // M.K M_K + {TG_WMM_AC_VI, TG_WMM_AC_BE, TG_WMM_AC_VI, TG_WMM_AC_VI, 0} // M.W M_W special exchange for Broadcast testing +}; +/* Generic function to create a meassage, it also fills in the AC as part of +** the payload +** */ +void create_apts_msg(int msg, unsigned int txbuf[],int id) +{ + struct apts_msg *t; + + t = &apts_msgs[msg]; + txbuf[ 0] = wmmps_info.my_cookie; + txbuf[ 1] = wmmps_info.dscp; + txbuf[ 2] = 0; + txbuf[ 3] = 0; + txbuf[ 4] = 0; + txbuf[ 5] = 0; + //txbuf[ 6] = t->param0; + //txbuf[ 7] = t->param1; + //txbuf[ 8] = t->param2; + txbuf[ 9] = id; + txbuf[ 10] = t->cmd; + strcpy((char *)&txbuf[11], t->name); + PRINTF("create_apts_msg (%s) %d\n", t->name,t->cmd); +} + +void print_hex_string(char* buf, int len) +{ + int i; + + if (len==0) { printf("<empty string>"); return; } + + for (i = 0; i < len; i++) { + printf("%02x ", *((unsigned char *)buf + i)); + if ((i&0xf)==15) printf("\n "); + } + if ((i&0xf)) + printf("\n"); +} + +/* trace print*/ +void mpx(char *m, void *buf_v, int len) +{ + char *buf = buf_v; + + printf("%s MSG: %s\n ", m, &buf[44] ); + print_hex_string(buf, len); +} + +/* function to validate the AC of the payload recd to ensure the correct +** message sequence*/ +int receiver(unsigned int *rmsg,int length,int tos,unsigned int type) +{ + int r=1; + int new_dscp=rmsg[1]; + + if((new_dscp != tos)||(rmsg[10] != type)) { + PRINTF("\r\n dscp recd is %d msg type is %d\n",new_dscp,rmsg[10]); + r=-6; + } + return r; +} + +/* WfaRcvProc: This function receives the test case name +** after sending the initial hello packet, on receiving a +** valid test case it advances onto the next receive state +*/ +int WfaRcvProc(unsigned int *rmsg,int length,int *state) +{ + int sta_test; + int usedThread = wmmps_info.ps_thread; + num_hello=0; + sta_test = wmmps_info.sta_test = rmsg[10]; + mpx("STA recv\n", rmsg, 64); + if(!((sta_test >=B_D)&&(sta_test <= LAST_TEST))) + return -1; + wmmps_info.my_sta_id = rmsg[9]; + /* Pthread mutex Lock & Unlock mechanisms are only used in case of Linux + * since Linux uses six threads for WMM to 3 RX and 3 TX. This is as per the + * original design of Wifi. The same threads are used for WMMPS recv. + * In case of Win CE for WMMPS we create a single thread that does wmmps recv. + * For WMM the threads are created dynamically based on the no of streams. + */ +#ifndef WIN32 + pthread_mutex_lock(&wmm_thr[usedThread].thr_flag_mutex); +#endif /*!WIN32 */ + + wmm_thr[usedThread].thr_flag = wmmps_info.streamid; + +#ifndef WIN32 + pthread_mutex_unlock(&wmm_thr[usedThread].thr_flag_mutex); +#endif /*!WIN32 */ + + (*state)++; + + return 0; +} + +/* WfaStaResetAll: This function resets the whole communication with +** the console (in the event of a wrong message received for the test case) +** resulting into resending of all the packets from the scratch, there is an +** upper bound for the resets a max of three*/ +void WfaStaResetAll() +{ + int r; + PRINTF("Entering Reset\n"); + num_retry++; + if(num_retry > MAXRETRY) + { + create_apts_msg(APTS_RESET_STOP, psTxMsg,wmmps_info.my_sta_id); + wfaTGSetPrio(psSockfd, TG_WMM_AC_BE); + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + mpx("STA msg",psTxMsg,64); + printf("Too many retries\n"); + exit(-8); + } + if(!reset_recd) + { + create_apts_msg(APTS_RESET, psTxMsg,wmmps_info.my_sta_id); + wfaTGSetPrio(psSockfd, TG_WMM_AC_BE); + psTxMsg[1] = TOS_BE; + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + mpx("STA msg",psTxMsg,64); + } + else + { + create_apts_msg(APTS_RESET_RESP, psTxMsg,wmmps_info.my_sta_id); + wfaTGSetPrio(psSockfd, TG_WMM_AC_BE); + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + mpx("STA msg",psTxMsg,64); + reset_recd=0; + } + + resetsnd=1; + resetrcv=1; +} + +/* WfaRcvVO: A function expected to receive a AC_VO packet from +** the console, if it does not reeive a valid VO, it prints out +** an error message*/ +int WfaRcvVO(unsigned int *rmsg,int length,int *state) +{ + int r; + + if ((r=receiver(rmsg,length,TOS_VO,APTS_DEFAULT))>=0) + (*state)++; + else + { + PRINTF("\nBAD REC in VO%d\n",r); + //WfaStaResetAll(); + } + return 0; +} + +/* WfaRcvVI: A function expected to receive a AC_VI packet from +** the console, if does not reeive a valid VI it prints out +** an error message. +*/ + +int WfaRcvVI(unsigned int *rmsg,int length,int *state) +{ + int r; + + if ((r=receiver(rmsg,length,TOS_VI,APTS_DEFAULT))>=0) + (*state)++; + else + PRINTF("\nBAD REC in VI%d\n",r); + + return 0; +} + +/* WfaRcvBE: A function expected to receive a AC_BE packet from +** the console, if does not reeive a valid BE it prints out +** an error message +*/ + +int WfaRcvBE(unsigned int *rmsg,int length,int *state) +{ + int r; + if ((r=receiver(rmsg,length,TOS_BE,APTS_DEFAULT))>=0) + (*state)++; + else + { + PRINTF("\nBAD REC in BE%d\n",r); + } + return 0; +} + +/* WfaRcvBK: A function expected to receive a AC_BK packet from +** the console, if does not reeive a valid BK it prints out +** an error message +*/ + +int WfaRcvBK(unsigned int *rmsg,int length,int *state) +{ + int r; + + if ((r=receiver(rmsg,length,TOS_BK,APTS_DEFAULT))>=0) + (*state)++; + else + PRINTF("\nBAD REC in BK%d\n",r); + + return 0; +} + +void BUILD_APTS_MSG(int msg, unsigned long *txbuf) +{ + struct apts_msg *t; + + t = &apts_msgs[msg]; + txbuf[0] = wmmps_info.msgno++; + txbuf[1] = 0; + txbuf[2] = 0; + txbuf[3] = 0; + txbuf[4] = 0; + txbuf[5] = 0; + txbuf[6] = t->param0; + txbuf[7] = t->param1; + txbuf[8] = t->param2; + txbuf[9] = t->param3; + txbuf[10] = t->cmd; + strcpy((char *)&txbuf[11], t->name); +} + +void send_txmsg(int new_prio_class) +{ + int r; + int new_dscp = 0; + + if(new_prio_class > -1) + new_dscp = wfaTGSetPrio(psSockfd, new_prio_class); + + psTxMsg[0] = wmmps_info.msgno++; + psTxMsg[1] = new_dscp; + psTxMsg[2] = wmmps_info.my_group_cookie; + psTxMsg[3] = wmmps_info.my_cookie; + psTxMsg[4] = wmmps_info.my_sta_id; + + if(psTxMsg[10] == APTS_DEFAULT) + { + psTxMsg[13] = (wmmps_info.msgno%10) + 0x20202030; + } + + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, 200+(wmmps_info.msgno%200), (struct sockaddr *) &wmmps_info.psToAddr); + wmmps_info.nsent++; +} + +/* + * This needs to adopt to the specific platform you port to. + */ +void wfaSetDUTPwrMgmt(int mode) +{ + static int curr_mode; + + if(curr_mode == mode) + { + return; + } + wl_set (g_wl_handle,WLC_SET_PM,&mode,sizeof(int)); + + curr_mode = mode; +} + +int wfaWmmPowerSaveProcess(int sockfd) +{ + int rbytes = 0; + int sta_test; + struct sockaddr from; + int len; + StationRecvProcStatetbl_t *rcvstatarray; + StationRecvProcStatetbl_t func; + int *rcv_state; + len=sizeof(from); + rbytes = WmmpsTrafficRecv(sockfd,(char *)psRxMsg, (struct sockaddr *)&from); + if(rbytes < 0) + { + p_error("receive error"); + return rbytes; + } + sta_test = wmmps_info.sta_test; + if(sta_test != L_1) + mpx("RX msg",psRxMsg,64); + if(psRxMsg[10] == APTS_STOP) + PRINTF("\r\n stop recd\n"); + if(psRxMsg[10] == APTS_RESET) + { + reset_recd=1; + //wmmps_info.ps_thread = 1; + WfaStaResetAll(); + return 0; + } + //If reset signal is there for the receiving thread and station has sent the + //reset message (i.e. !reset_recd) then ignore all the messages till an + //APTS_RESET_RESP has been received. + + if(resetrcv) + { + wmmps_info.rcv_state = 0; + if((!reset_recd)&&(psRxMsg[10] != APTS_RESET_RESP)) + return 0; + else + { + resetrcv = 0; + reset_recd = 0; + } + } + sta_test = wmmps_info.sta_test; + wmmps_info.my_cookie = psRxMsg[0]; + rcv_state = &(wmmps_info.rcv_state); + rcvstatarray = stationRecvProcStatetbl[sta_test]; + func = rcvstatarray[*(rcv_state)]; + func.statefunc(psRxMsg,rbytes,rcv_state); + return TRUE; +} + +void wmmps_wait_state_proc() +{ + int ttypes[4], i, rbytes; + + for(i = 0; i<4; i++) + { + ttypes[i] = 0xFF; + } + + switch(wmmps_info.wait_state) + { + case WFA_WAIT_NEXT_CODEC: + ttypes[0] = -1; + wmmps_info.wait_state = WFA_WAIT_NEXT_CODEC; + break; + + case WFA_WAIT_FOR_AP_RESPONSE: + wmmps_info.wait_state = WFA_WAIT_NEXT_CODEC; + break; + + case WFA_WAIT_STAUT_00: + rbytes = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, 200+(wmmps_info.msgno%200), (struct sockaddr *)&wmmps_info.psToAddr); + wmmps_info.nextsleep = 1000000; /* one second */ + break; + + case WFA_WAIT_STAUT_02: + ttypes[0] = TOS_VO; + wmmps_info.nextsleep = 1000000; // 1 sec + return; + break; + + case WFA_WAIT_STAUT_04: + ttypes[0] = TOS_BE; + ttypes[1] = TOS_VO; + break; + + case WFA_WAIT_STAUT_0E: + ttypes[0] = TOS_VO; + ttypes[1] = TOS_VO; + break; + + case WFA_WAIT_STAUT_VOLOAD: + ttypes[0] = TOS_VO; + break; + + case WFA_WAIT_STAUT_SEQ: + if( wmmps_info.nsent < 0 || wmmps_info.nsent > sizeof(ac_seq[wmmps_info.sta_test]) ) + wmmps_info.nsent = 0; + + if(( wmmps_info.sta_test == A_Y && wmmps_info.nsent == 3) + || (wmmps_info.sta_test == A_U && wmmps_info.nsent == 1) + || (wmmps_info.sta_test == A_U && wmmps_info.nsent == 3) + || (wmmps_info.sta_test == A_U && wmmps_info.nsent == 5)) + { + wfaSetDUTPwrMgmt(PS_OFF); + wmmps_info.nextsleep = 100000; // 100 ms + } + + if((wmmps_info.sta_test == A_Y && wmmps_info.nsent == 4) + || (wmmps_info.sta_test == A_U && wmmps_info.nsent == 2) + || (wmmps_info.sta_test == A_U && wmmps_info.nsent == 4)) + { + wfaSetDUTPwrMgmt(PS_ON); + wmmps_info.nextsleep = 100000; // 100 ms + } + + ttypes[0] = ac_seq[wmmps_info.sta_test][wmmps_info.nsent]; + printf("ttypes 0x%x\n", ttypes[0]); + + // do we need sample time for one sec? + wmmps_info.nextsleep = 1000000; + break; + + default: + printf("unknown wait state\n"); + } + + i=0; + while(ttypes[i] != 0xFF) + send_txmsg(ttypes[i++]); +} +#endif /* WFA_WMM_PS_EXT */ +#endif /* WFA_WMM_EXT */
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_wmmps_linux.c b/src/tools/Wifi_ASD_test/lib/wfa_wmmps_linux.c new file mode 100755 index 0000000..b810e07 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_wmmps_linux.c
@@ -0,0 +1,398 @@ +/* +* Windows port of asd command line utility +* +* Copyright 2002, Broadcom Corporation +* All Rights Reserved. +* +* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; +* the contents of this file may not be disclosed to third parties, copied or +* duplicated in any form, in whole or in part, without the prior written +* permission of Broadcom Corporation. +* +*/ + +#include <netdb.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <pthread.h> + +#include "wfa_sock.h" +#include "wfa_types.h" +#include "wfa_tg.h" +#include "wfa_ca.h" +#include "wfa_wmmps.h" +#include "wfa_miscs.h" +#include "wfa_main.h" +#include "wfa_debug.h" +#include "wfa_tlv.h" + +extern int psSockfd; +extern int msgsize; +extern int resetsnd; +extern int gtgWmmPS; +extern int num_stops; +extern int num_hello; +extern tgWMM_t wmm_thr[]; +extern wfaWmmPS_t wmmps_info; +extern unsigned int psTxMsg[512]; +tgThrData_t tdata[WFA_THREADS_NUM]; + +extern void tmout_stop_send(int num); +extern void wfaSetDUTPwrMgmt(int mode); +extern void wfaSetThreadPrio(int tid, int class); +extern void mpx(char *m, void *buf_v, int len); +extern int wfaTGSetPrio(int sockfd, int tgClass); +extern tgStream_t *findStreamProfile(int id); +extern StationProcStatetbl_t stationProcStatetbl[LAST_TEST+1][11]; +extern int receiver(unsigned int *rmsg,int length,int tos,unsigned int type); + +/* WfaRcvVOCyclic: This is meant for the L1 test case. The function +** receives the VO packets from the console */ +int WfaRcvVOCyclic(unsigned int *rmsg,int length,int *state) +{ + int r; + tgWMM_t *my_wmm = &wmm_thr[wmmps_info.ps_thread]; + + if(rmsg[10] != APTS_STOP) + { + if ((r=receiver(rmsg,length,TOS_VO,APTS_DEFAULT))>=0); + else + PRINTF("\nBAD REC in VO%d\n",r); + } + else + { + pthread_mutex_lock(&my_wmm->thr_stop_mutex); + while(!my_wmm->stop_flag) + { + pthread_cond_wait(&my_wmm->thr_stop_cond, &my_wmm->thr_stop_mutex); + } + pthread_mutex_unlock(&my_wmm->thr_stop_mutex); + my_wmm->stop_flag = 0; + gtgWmmPS = 0; + asd_closeSocket(psSockfd); + psSockfd = -1; + signal(SIGALRM, SIG_IGN); + wfaSetDUTPwrMgmt(PS_OFF); + uapsd_sleep(1); + } + + return 0; +} +/* WfaRcvStop: This function receives the stop message from the +** console, it waits for the sending thread to have sent the stop before +** quitting*/ +int WfaRcvStop(unsigned int *rmsg,int length,int *state) +{ + tgWMM_t *my_wmm = &wmm_thr[wmmps_info.ps_thread]; + + my_wmm->stop_flag = 0; + PRINTF("\r\nEnterring Wfarcvstop\n"); + if(rmsg[10] != APTS_STOP) + { + //PRINTF("\nBAD REC in rcvstop%d\n",r); + //WfaStaResetAll(); + } + else + { + pthread_mutex_lock(&my_wmm->thr_stop_mutex); + while(!my_wmm->stop_flag) + { + printf("\r\n stuck\n"); + pthread_cond_wait(&my_wmm->thr_stop_cond, &my_wmm->thr_stop_mutex); + } + num_stops=0; + pthread_mutex_unlock(&my_wmm->thr_stop_mutex); + my_wmm->stop_flag = 0; + gtgWmmPS = 0; + asd_closeSocket(psSockfd); + psSockfd = -1; + signal(SIGALRM, SIG_IGN); + wfaSetDUTPwrMgmt(PS_OFF); + uapsd_sleep(1); + } + return 0; +} + + +/* +* wfaStaSndHello(): This function sends a Hello packet +* and sleeps for sleep_period, the idea is +* to keep sending hello packets till the console +* responds, the function keeps a check on the MAX +* Hellos and if number of Hellos exceed that it quits +*/ +int WfaStaSndHello(char psave,int sleep_period,int *state) +{ + int r; + tgWMM_t *my_wmm = &wmm_thr[wmmps_info.ps_thread]; + if(!(num_hello++)) + create_apts_msg(APTS_HELLO, psTxMsg,0); + + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + uapsd_sleep(sleep_period); + pthread_mutex_lock(&my_wmm->thr_flag_mutex); + if(my_wmm->thr_flag) + { + (*state)++; + num_hello=0; + my_wmm->thr_flag=0; + } + pthread_mutex_unlock(&my_wmm->thr_flag_mutex); + if(num_hello > MAXHELLO) + { + DPRINT_ERR(WFA_ERR, "Too many Hellos sent\n"); + gtgWmmPS = 0; + num_hello=0; + asd_closeSocket(psSockfd); + psSockfd = -1; + signal(SIGALRM, SIG_IGN); + } + return 0; +} + +/* +* WfaStaWaitStop(): This function sends the stop packet on behalf of the +* station, the idea is to keep sending the Stop +* till a stop is recd from the console,the functions +* quits after stop threshold reaches. +*/ +int WfaStaWaitStop(char psave,int sleep_period,int *state) +{ + int r; + int myid=wmmps_info.ps_thread; + PRINTF("\n Entering Sendwait"); + uapsd_sleep(sleep_period); + if(!num_stops) + { + wfaSetDUTPwrMgmt(psave); + wfaTGSetPrio(psSockfd, TG_WMM_AC_BE); + } + + num_stops++; + create_apts_msg(APTS_STOP, psTxMsg,wmmps_info.my_sta_id); + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + mpx("STA msg",psTxMsg,64); + + wmm_thr[myid].stop_flag = 1; + pthread_mutex_lock(&wmm_thr[myid].thr_stop_mutex); + pthread_cond_signal(&wmm_thr[myid].thr_stop_cond); + pthread_mutex_unlock(&wmm_thr[myid].thr_stop_mutex); + if(num_stops > MAX_STOPS) + { + DPRINT_ERR(WFA_ERR, "Too many stops sent\n"); + gtgWmmPS = 0; + asd_closeSocket(psSockfd); + psSockfd = -1; + signal(SIGALRM, SIG_IGN); + } + wfaSetDUTPwrMgmt(PS_OFF); + return 0; +} + +void * wfa_wmm_thread(void *thr_param) +{ + int myId = ((tgThrData_t *)thr_param)->tid; + tgWMM_t *my_wmm = &wmm_thr[myId]; + tgStream_t *myStream = NULL; + tgThrData_t *tdata =(tgThrData_t *) thr_param; + int myStreamId; + int mySock = -1; + int status, respLen; + tgProfile_t *myProfile; + StationProcStatetbl_t curr_state; + + BYTE respBuf[WFA_BUFF_1K]; + pthread_attr_t tattr; + + pthread_attr_init(&tattr); + pthread_attr_setschedpolicy(&tattr, SCHED_RR); + while(1) + { + pthread_mutex_lock(&my_wmm->thr_flag_mutex); + /* it needs to reset the thr_flag to wait again */ + while(!my_wmm->thr_flag) + { + /* + * in normal situation, the signal indicates the thr_flag changed to + * a valid number (stream id), then it will go out the loop and do + * work. + */ + pthread_cond_wait(&my_wmm->thr_flag_cond, &my_wmm->thr_flag_mutex); + } + sleep(2); + pthread_mutex_unlock(&my_wmm->thr_flag_mutex); + + myStreamId = my_wmm->thr_flag; + my_wmm->thr_flag = 0; + /* use the flag as a stream id to file the profile */ + myStream = findStreamProfile(myStreamId); + myProfile = &myStream->profile; + + if(myProfile == NULL) + { + status = STATUS_INVALID; + wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&status, respBuf); + respLen = WFA_TLV_HDR_LEN+4; + /* + * send it back to control agent. + */ + continue; + } + + switch(myProfile->direction) + { + case DIRECT_SEND: + mySock = wfaCreateUDPSock(myProfile->sipaddr, myProfile->sport); + mySock = wfaConnectUDPPeer(mySock, myProfile->dipaddr, myProfile->dport); + /* + * Set packet/socket priority TOS field + */ + wfaTGSetPrio(mySock, myProfile->trafficClass); + + /* + * set a proper priority + */ + wfaSetThreadPrio(myId, myProfile->trafficClass); +#ifdef DEBUG + printf("wfa_wmm_thread: myProfile->startdelay %i\n", myProfile->startdelay); +#endif /* DEBUG */ + /* if delay is too long, it must be something wrong */ + if(myProfile->startdelay > 0 && myProfile->startdelay < 50) + { + asd_sleep(myProfile->startdelay); + } + + /* + * set timer fire up + */ + signal(SIGALRM, tmout_stop_send); + alarm(myProfile->duration); + + /* Whenever frameRate is 0,sending data at the maximum possible rate */ + if (myProfile->rate != 0) + wfaSendLongFile(mySock, myStreamId, respBuf, &respLen ); + else + wfaImprovePerfSendLongFile(mySock, myStreamId, respBuf, &respLen ); + + memset(respBuf, 0, WFA_BUFF_1K); + if (mySock != -1) { + asd_closeSocket(mySock); + mySock = -1; + } + + /* + * uses thread 0 to pack the items and ships it to CA. + */ + if(myId == 0) { + // wfaSentStatsResp(gxcSockfd, respBuf); + printf("respBuf = %s sent from thr\n", respBuf); + } + break; + + case DIRECT_RECV: +#ifdef WFA_WMM_PS_EXT + if(myProfile->profile == PROF_UAPSD) + { + wmmps_info.sta_test = B_D; + wmmps_info.ps_thread = myId; + wmmps_info.rcv_state = 0; + wmmps_info.tdata = tdata; + wmmps_info.dscp = wfaTGSetPrio(psSockfd, TG_WMM_AC_BE); + tdata->state_num=0; + /* + * default timer value + */ + + while(gtgWmmPS>0) + { + if(resetsnd) + { + tdata->state_num = 0; + resetsnd = 0; + } + + tdata->state = stationProcStatetbl[wmmps_info.sta_test]; + curr_state = tdata->state[tdata->state_num]; + curr_state.statefunc(curr_state.pw_offon,curr_state.sleep_period,&(tdata->state_num)); + } + } + break; +#endif /* WFA_WMM_PS_EXT */ + default: + DPRINT_ERR(WFA_ERR, "Unknown covered case\n"); + } + } +} + +void init_thr_flag() +{ + int cntThr = 0; + pthread_attr_t ptAttr; + int ptPolicy; + + struct sched_param ptSchedParam; + pthread_attr_init(&ptAttr); + + ptSchedParam.sched_priority = 10; + pthread_attr_setschedparam(&ptAttr, &ptSchedParam); + pthread_attr_getschedpolicy(&ptAttr, &ptPolicy); + pthread_attr_setschedpolicy(&ptAttr, SCHED_RR); + pthread_attr_getschedpolicy(&ptAttr, &ptPolicy); + /* + * Create multiple threads for WMM Stream processing. + */ + for(cntThr = 0; cntThr< WFA_THREADS_NUM; cntThr++) + { + tdata[cntThr].tid = cntThr; + pthread_mutex_init(&wmm_thr[cntThr].thr_flag_mutex, NULL); + pthread_cond_init(&wmm_thr[cntThr].thr_flag_cond, NULL); + + wmm_thr[cntThr].thr_id = pthread_create(&wmm_thr[cntThr].thr, + &ptAttr, wfa_wmm_thread, &tdata[cntThr]); + + sleep(1); + wmm_thr[cntThr].thr_flag = 0; + } +} + +/* + * wfaSetThreadPrio(): + * Set thread priorities + * It is an optional experiment if you decide not necessary. + */ +void wfaSetThreadPrio(int tid, int class) +{ + struct sched_param tschedParam; + pthread_attr_t tattr; + pthread_attr_init(&tattr); + pthread_attr_setschedpolicy(&tattr, SCHED_RR); + + switch(class) + { + case TG_WMM_AC_BK: + tschedParam.sched_priority = 70-3; + break; + case TG_WMM_AC_VI: + tschedParam.sched_priority = 70-1; + break; + case TG_WMM_AC_VO: + tschedParam.sched_priority = 70; + break; + case TG_WMM_AC_BE: + tschedParam.sched_priority = 70-2; + default: + /* default */ + ; + } + + pthread_attr_setschedparam(&tattr, &tschedParam); +} + +int WmmpsTrafficRecv(int sock, char *buf, struct sockaddr *from) +{ + int bytesRecvd; + socklen_t addrLen; + bytesRecvd = recvfrom(sock, buf, MAX_UDP_LEN, 0, from, &addrLen); + return bytesRecvd; +}
diff --git a/src/tools/Wifi_ASD_test/lib/wfa_wmmps_win32.c b/src/tools/Wifi_ASD_test/lib/wfa_wmmps_win32.c new file mode 100755 index 0000000..ecc1fc1 --- /dev/null +++ b/src/tools/Wifi_ASD_test/lib/wfa_wmmps_win32.c
@@ -0,0 +1,237 @@ +/* + * Windows port of asd command line utility + * + * Copyright 2002, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied or + * duplicated in any form, in whole or in part, without the prior written + * permission of Broadcom Corporation. + * + */ + +#include "wfa_sock.h" +#include "wfa_types.h" +#include "wfa_tg.h" +#include "wfa_ca.h" +#include "wfa_wmmps.h" +#include "wfa_miscs.h" +#include "wfa_main.h" +#include "wfa_debug.h" + +extern int psSockfd; +extern int msgsize; +extern int resetsnd; +extern int gtgWmmPS; +extern int num_stops; +extern int num_hello; +extern tgWMM_t wmm_thr[]; +tgThrData_t tdata[WFA_THREADS_NUM]; +extern HANDLE thr_flag_cond; +extern HANDLE thr_stop_cond; +extern wfaWmmPS_t wmmps_info; +extern unsigned int psTxMsg[512]; + +extern void wfaSetDUTPwrMgmt(int mode); +extern void mpx(char *m, void *buf_v, int len); +extern int wfaTGSetPrio(int sockfd, int tgClass); +extern StationProcStatetbl_t stationProcStatetbl[LAST_TEST+1][11]; +extern int receiver(unsigned int *rmsg,int length,int tos,unsigned int type); + +/* WfaRcvVOCyclic: This is meant for the L1 test case. The function +** receives the VO packets from the console */ +int WfaRcvVOCyclic(unsigned int *rmsg,int length,int *state) +{ + int r; + tgWMM_t *my_wmm = &wmm_thr[wmmps_info.ps_thread]; + + if(rmsg[10] != APTS_STOP) + { + if ((r=receiver(rmsg,length,TOS_VO,APTS_DEFAULT))>=0); + else + PRINTF("\nBAD REC in VO%d\n",r); + } + else + { + while(!my_wmm->stop_flag) + { + while(WaitForSingleObject(thr_stop_cond, 0)!=WAIT_OBJECT_0); + } + ResetEvent(thr_stop_cond); + my_wmm->stop_flag = 0; + gtgWmmPS = 0; + asd_closeSocket(psSockfd); + psSockfd = -1; + wfaSetDUTPwrMgmt(PS_OFF); + uapsd_sleep(1); + } + return 0; +} + + +/* WfaRcvStop: This function receives the stop message from the +** console, it waits for the sending thread to have sent the stop before +** quitting*/ +int WfaRcvStop(unsigned int *rmsg,int length,int *state) +{ + tgWMM_t *my_wmm = &wmm_thr[wmmps_info.ps_thread]; + my_wmm->stop_flag = 0; + PRINTF("\r\nEnterring Wfarcvstop\n"); + if(rmsg[10] != APTS_STOP) + { + //PRINTF("\nBAD REC in rcvstop%d\n",r); + //WfaStaResetAll(); + } + else + { + while(!my_wmm->stop_flag) + { + while(WaitForSingleObject(thr_stop_cond, 0)!=WAIT_OBJECT_0); + } + num_stops=0; + ResetEvent(thr_stop_cond); + my_wmm->stop_flag = 0; + gtgWmmPS = 0; + asd_closeSocket(psSockfd); + psSockfd = -1; + wfaSetDUTPwrMgmt(PS_OFF); + uapsd_sleep(1); + } + return 0; +} + +/* + * wfaStaSndHello(): This function sends a Hello packet + * and sleeps for sleep_period, the idea is + * to keep sending hello packets till the console + * responds, the function keeps a check on the MAX + * Hellos and if number of Hellos exceed that it quits + */ +int WfaStaSndHello(char psave,int sleep_period,int *state) +{ + int r; + tgWMM_t *my_wmm = &wmm_thr[wmmps_info.ps_thread]; + if(!(num_hello++)) + create_apts_msg(APTS_HELLO, psTxMsg,0); + + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + uapsd_sleep(sleep_period); + if(my_wmm->thr_flag) + { + (*state)++; + num_hello=0; + my_wmm->thr_flag=0; + } + if(num_hello > MAXHELLO) + { + DPRINT_ERR(WFA_ERR, "Too many Hellos sent\n"); + gtgWmmPS = 0; + num_hello=0; + asd_closeSocket(psSockfd); + psSockfd = -1; + } + return 0; +} + +/* + * WfaStaWaitStop(): This function sends the stop packet on behalf of the + * station, the idea is to keep sending the Stop + * till a stop is recd from the console,the functions + * quits after stop threshold reaches. + */ +int WfaStaWaitStop(char psave,int sleep_period,int *state) +{ + int r; + int myid=wmmps_info.ps_thread; + PRINTF("\n Entering Sendwait"); + uapsd_sleep(sleep_period); + if(!num_stops) + { + wfaSetDUTPwrMgmt(psave); + wfaTGSetPrio(psSockfd, TG_WMM_AC_BE); + } + + num_stops++; + create_apts_msg(APTS_STOP, psTxMsg,wmmps_info.my_sta_id); + r = wfaTrafficSendTo(psSockfd, (char *)psTxMsg, msgsize, (struct sockaddr *)&wmmps_info.psToAddr); + mpx("STA msg",psTxMsg,64); + + wmm_thr[myid].stop_flag = 1; + SetEvent(thr_stop_cond); + if(num_stops > MAX_STOPS) + { + DPRINT_ERR(WFA_ERR, "Too many stops sent\n"); + gtgWmmPS = 0; + asd_closeSocket(psSockfd); + psSockfd = -1; + } + wfaSetDUTPwrMgmt(PS_OFF); + return 0; +} + +void Uapsd_Recv_Thread(LPVOID *thr_param) +{ + int myId = ((tgThrData_t *)thr_param)->tid; + tgWMM_t *my_wmm = &wmm_thr[myId]; + tgStream_t *myStream = NULL; + tgThrData_t *tdata =(tgThrData_t *) thr_param; + StationProcStatetbl_t curr_state; + while(!my_wmm->thr_flag) + { + while(WaitForSingleObject(thr_flag_cond, 0)!=WAIT_OBJECT_0); + } + ResetEvent(thr_flag_cond); + my_wmm->thr_flag = 0; + wmmps_info.sta_test = B_D; + wmmps_info.ps_thread = myId; + wmmps_info.rcv_state = 0; + wmmps_info.tdata = tdata; + wmmps_info.dscp = wfaTGSetPrio(psSockfd, TG_WMM_AC_BE); + tdata->state_num=0; + /* + * default timer value + */ + while(gtgWmmPS>0) + { + if(resetsnd) + { + tdata->state_num = 0; + resetsnd = 0; + } + tdata->state = stationProcStatetbl[wmmps_info.sta_test]; + curr_state = tdata->state[tdata->state_num]; + curr_state.statefunc(curr_state.pw_offon,curr_state.sleep_period,&(tdata->state_num)); + } + +} + +void init_wmmps_thr() +{ + int cntThr = 0; + DWORD UAPSDThread; + /*Create the thread event for multiple streams and hold the thread handles in the array*/ + thr_flag_cond = CreateEvent(NULL, FALSE, TRUE, NULL); + thr_stop_cond = CreateEvent(NULL, FALSE, TRUE, NULL); + for(cntThr = 0; cntThr< 1; cntThr++) + { + tdata[cntThr].tid = cntThr; + wmm_thr[cntThr].thr_id = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Uapsd_Recv_Thread, (LPVOID) &tdata[cntThr], 0, &UAPSDThread); + if (wmm_thr[cntThr].thr_id == NULL){ + printf("CreateThread Failed:%d\n",WSAGetLastError()); + } + sleep(1); + wmm_thr[cntThr].thr_flag = 0; + } +} + +int WmmpsTrafficRecv(int sock, char *buf, struct sockaddr *from) +{ + int bytesRecvd; + socklen_t addrLen; + struct sockaddr_in recFrom; + memset(&recFrom, 0, sizeof(recFrom)); + addrLen = sizeof(recFrom); + bytesRecvd = recvfrom(sock, buf, MAX_UDP_LEN, 0, (struct sockaddr *)&recFrom, &addrLen); + return bytesRecvd; +}
diff --git a/src/tools/release/WLAN.usf b/src/tools/release/WLAN.usf new file mode 100644 index 0000000..9b2ef12 --- /dev/null +++ b/src/tools/release/WLAN.usf
@@ -0,0 +1,34 @@ +## +## This is a common config file that is used mainly by modules +## or brand makefiles. The ".usf" suffix stands for "universal +## settings file". The important feature is that this file is +## both legal makefile and shell syntax, and could be parsed as +## a properties file by any language (Perl, Python, Java, ...) +## which understands properties. +## +## Rules: Each line is either an assignment, a comment, or blank. +## Assignments MUST be of the form "foo=bar" (no spaces) and +## comments have a leading "#" character. +## +## It can be included by common templates like WLAN_Common.mk, +## or by brand makefiles, or sourced by build scripts. +## +## $Id: WLAN.usf 429692 2013-10-15 19:51:40Z jqliu $ +## + +# Current list of components +# This list is used in module makefiles to set vpath search +# paths and include paths + +WLAN_COMPONENT_PATHS=src/shared/bcmwifi src/wl/clm src/wl/lwip src/wl/plqmr src/wl/ppr src/wl/rel_mcast src/wl/gas src/wl/encode src/wl/olpc src/wl/keymgmt src/wl/iocv src/wl/dump src/wl/phymods/cmn/hal src/wl/phymods + +# This is a staging area for generated content that need to be shared +# between build step and packaging step. E.g when CLM data files +# need to be packaged, they are first staged to $(WLAN_GEN_BASEDIR) +# and packaged from there. + +WLAN_GEN_BASEDIR=generated + +# This is the conventional Windows mount point for network files. + +WLAN_WINPFX=Z:
diff --git a/src/tools/wlm/Makefile b/src/tools/wlm/Makefile new file mode 100644 index 0000000..d351485 --- /dev/null +++ b/src/tools/wlm/Makefile
@@ -0,0 +1,86 @@ +# +# Makefile for mfgapi_test.cpp +# $Id: Makefile 382637 2013-02-03 04:34:52Z $ +# +# There are total five options for make: +# +# make : This is to make mfgapi_test.exe, wlmSampleTests.exe, and wlm.lib +# make exe : This is to make mfgapi_test.exe and wlmSampleTests.exe +# make lib : This is to make wlm.lib only +# make clean : This is to remove mfgtest_api.exe and wlmSampleTests.exe +# make cleanall : This is to remove mfgtest_api.exe, wlmSampleTests.exe, wlm.lib and all of its object files +# +# + +UNAME = $(shell uname) + +SRCBASE = ../.. +WLM_DIR = wl/exe + +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +TARGET_TEST = mfgapi_test.exe +TARGET_SAMPLE = wlmSampleTests.exe +WLM_LIB = wlm.lib +WLM_DLL = wlm.dll +REL_WLM_DIR = $(WLM_DIR)/obj/wlm/free +WLM_MAKE = GNUmakefile.wlm_dll +C_DEFINES += -mno-cygwin -DWIN32 +else +TARGET_TEST = mfgapi_test +TARGET_SAMPLE = wlmSampleTests +WLM_LIB = wlm.so +REL_WLM_DIR = $(WLM_DIR)/wlm/x86 +WLM_MAKE = GNUmakefile +C_DEFINES += -DLINUX +endif + +SOURCE = mfgapi_test.cpp +SOURCE_SAMPLE = wlmSampleTests.c + +vpath %.h $(SRCBASE)/$(WLM_DIR) + +CC = gcc +CXX = g++ + +C_DEFINES += -Wall -Wextra -Werror +ANSI_C90 = -ansi -pedantic + +INCLUDES = $(SRCBASE)/$(WLM_DIR) $(SRCBASE)/include $(SRCBASE)/common/include +CPPFLAGS = $(patsubst %,-I%,$(subst ;, ,$(INCLUDES))) + +all: lib $(TARGET_SAMPLE) + +test: lib $(TARGET_TEST) + +lib: $(SRCBASE)/$(REL_WLM_DIR)/$(WLM_LIB) + +$(TARGET_TEST): $(SOURCE) wlm.h + @echo "Compiling - $(TARGET_TEST)" + $(CXX) $(C_DEFINES) $(CPPFLAGS) $(SOURCE) $(SRCBASE)/$(REL_WLM_DIR)/$(WLM_LIB) -o $(TARGET_TEST) + +$(SRCBASE)/$(REL_WLM_DIR)/$(WLM_LIB): +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) + $(MAKE) -C $(SRCBASE)/$(WLM_DIR) OTHER_SOURCES="" debug + $(MAKE) -C $(SRCBASE)/$(WLM_DIR) -f $(WLM_MAKE) + cp -f $(SRCBASE)/$(REL_WLM_DIR)/$(WLM_DLL) . +else + $(MAKE) -C $(SRCBASE)/$(WLM_DIR) -f $(WLM_MAKE) wlm + cp -f $(SRCBASE)/$(REL_WLM_DIR)/$(WLM_LIB) . +endif + +$(TARGET_SAMPLE): $(SOURCE_SAMPLE) wlm.h + @echo "Compiling - $(TARGET_SAMPLE)" + $(CC) $(C_DEFINES) $(CPPFLAGS) $(ANSI_C90) $(SOURCE_SAMPLE) $(SRCBASE)/$(REL_WLM_DIR)/$(WLM_LIB) -o $(TARGET_SAMPLE) + +clean: + rm -f $(TARGET_TEST) $(TARGET_SAMPLE) + +cleanall: + rm -f $(TARGET_TEST) $(TARGET_SAMPLE) $(WLM_LIB) +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) + rm -rf $(SRCBASE)/$(REL_WLM_DIR) +else + rm -f $(SRCBASE)/$(REL_WLM_DIR)/*.o $(SRCBASE)/$(REL_WLM_DIR)/$(WLM_LIB) +endif + +.PHONY : all exe lib clean cleanall
diff --git a/src/tools/wlm/wlmSampleTests.c b/src/tools/wlm/wlmSampleTests.c new file mode 100644 index 0000000..e40bdc3 --- /dev/null +++ b/src/tools/wlm/wlmSampleTests.c
@@ -0,0 +1,506 @@ +/* wlmSampleTests.cpp : Sample test program which uses the + * Wireless LAN Manufacturing (WLM) Test Library. + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlmSampleTests.c 241182 2011-02-17 21:50:03Z $ + * + * The sample tests allow users/customers to understand how WLM + * Test Library is used to create manufacturing tests. + * Users/customers may copy and modify the sample tests as + * required to meet their specific manufacturing test requirements. + * + * The sample tests can run in the following configurations: + * direct - on same device as the DUT (default). + * socket - as a client to the server DUT over Ethernet. + * serial - as a client to the server DUT over serial. + * wifi - as a client to the server DUT over 802.11. + * dongle - as a client to the server DUT over serial (to dongle UART). + * See printUsage() (i.e. --help) for details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "wlm.h" + +/* --------------------------------------------------------------- */ +typedef struct +{ + int count; /* number of tests run */ + int passed; /* number of tests passed */ + int failed; /* number of tests failed */ +} TestLog; + +static TestLog testLog; + +#define TEST_INITIALIZE() \ +{ \ + memset(&testLog, 0, sizeof(testLog)); \ +} + +#define TEST(condition, error) \ + testLog.count++; \ + if ((condition)) { \ + testLog.passed++; \ + } \ + else { \ + testLog.failed++; \ + printf("\n*** FAIL *** - %s():%d - %s\n\n", \ + __FUNCTION__, __LINE__, error); \ + } + +#define TEST_FATAL(condition, error) \ + testLog.count++; \ + if ((condition)) { \ + testLog.passed++; \ + } \ + else { \ + testLog.failed++; \ + printf("\n*** FAIL *** - %s():%d - %s\n\n", \ + __FUNCTION__, __LINE__, error); \ + exit(-1); \ + } + +#define TEST_FINALIZE() \ +{ \ + int percent = testLog.count ? \ + testLog.passed * 100 / testLog.count : 0; \ + printf("\n\n"); \ + printf("Test Summary:\n\n"); \ + printf("Tests %d\n", testLog.count); \ + printf("Pass %d\n", testLog.passed); \ + printf("Fail %d\n\n", testLog.failed); \ + printf("%d%%\n\n", percent); \ + printf("-----------------------------------\n\n"); \ +} + +/* --------------------------------------------------------------- */ + +static void delay(unsigned int msec) +{ + clock_t start_tick = clock(); + clock_t end_tick = start_tick + msec * CLOCKS_PER_SEC / 1000; + + while (clock() < end_tick) { + /* do nothing */ + } +} + +static void testDutInit() +{ + TEST(wlmMinPowerConsumption(TRUE), "unable disable sleep mode"); + TEST(wlmCountryCodeSet(WLM_COUNTRY_ALL), "unable to set country code"); + TEST(wlmGlacialTimerSet(99999), "unable to set glacial timer"); + TEST(wlmFastTimerSet(99999), "unable to set fast timer"); + TEST(wlmSlowTimerSet(99999), "unable to set slow timer"); + TEST(wlmScanSuppress(1), "unable to set scansuppress"); +} + +static void testVersion() +{ + char buffer[1024]; + TEST(wlmVersionGet(buffer, 1024), "wlmVersionGet failed"); + printf("version info: %s\n", buffer); +} + +/* Set transmit power and transmit packets expecting ack response. + * Reduce transmit power and repeat. + */ +static void testTransmit() +{ + int i; + int txPower = 17000; /* power in milli-dB */ + + for (i = 0; i < 8; i++) { + int power; + unsigned int txPacketCount = 50; + unsigned int beforeAckCount, afterAckCount, ackCount; + + TEST(wlmTxPowerSet(txPower), "wlmTxPowerSet failed"); + TEST(wlmTxPowerGet(&power), "wlmTxPowerGet failed"); + TEST(power == txPower, "Tx power not set correctly"); + + TEST(wlmTxGetAckedPackets(&beforeAckCount), "wlmTxGetAckedPackets failed"); + + TEST(wlmTxPacketStart(100, txPacketCount, 1024, "00:11:22:33:44:55", TRUE, TRUE), + "wlmTxPacketStart failed"); + + afterAckCount = beforeAckCount; + TEST(wlmTxGetAckedPackets(&afterAckCount), "wlmTxGetAckedPackets failed"); + + /* another pkteng is required to send ACKs else no ACKs will be received + * i.e. 'wl pkteng_start 00:11:22:33;44:55 rxwithack' + */ + ackCount = afterAckCount - beforeAckCount; + printf("Packets tx=%d, ack=%d\n", txPacketCount, ackCount); + TEST(ackCount > 0, "no ACK packets received"); + + /* reduce tx power */ + txPower -= 1000; + } + + TEST(wlmTxPacketStop(), "wlmTxPacketStop failed"); + + /* set tx power back to default */ + TEST(wlmTxPowerSet(-1), "wlmTxPowerSet failed"); +} + +/* Batch the commands to set transmit power and transmit packets, + * reduce transmit power and repeat. + * + * During the batching sequence, only 'set' functions can be invoked. + * 'get' functions are not supported by command batching. + */ +static void testBatchingTransmit(int clientBatching) +{ + int i, count = 8; + int txPower = 17000; /* power in milli-dB */ + unsigned int txPacketCount = 50; + unsigned int beforeAckCount, afterAckCount, ackCount; + + TEST(wlmTxGetAckedPackets(&beforeAckCount), "wlmTxGetAckedPackets failed"); + + /* start command batching */ + TEST(wlmSequenceStart(clientBatching), "wlmSequenceStart failed"); + + for (i = 0; i < count; i++) { + + TEST(wlmTxPowerSet(txPower), "wlmTxPowerSet failed"); + + TEST(wlmTxPacketStart(100, txPacketCount, 1024, "00:11:22:33:44:55", TRUE, TRUE), + "wlmTxPacketStart failed"); + + /* reduce tx power */ + txPower -= 1000; + } + + TEST(wlmTxPacketStop(), "wlmTxPacketStop failed"); + + /* stop command batching */ + TEST(wlmSequenceStop(), "wlmSequenceStop failed"); + + afterAckCount = beforeAckCount; + TEST(wlmTxGetAckedPackets(&afterAckCount), "wlmTxGetAckedPackets failed"); + + /* requires pkteng to send ACKs else no ACKs will be received + * i.e. 'wl pkteng_start 00:11:22:33;44:55 rxwithack' + */ + ackCount = afterAckCount - beforeAckCount; + printf("Packets tx=%d, ack=%d\n", txPacketCount * count, ackCount); + TEST(ackCount > 0, "no ACK packets received"); + + /* set tx power back to default */ + TEST(wlmTxPowerSet(-1), "wlmTxPowerSet failed"); +} + +/* Batch transmit commands on the client */ +static void testClientBatchingTransmit() +{ + testBatchingTransmit(TRUE); +} + +/* Batch transmit commands on the server */ +static void testServerBatchingTransmit() +{ + /* batch commands on server */ + testBatchingTransmit(FALSE); +} + +/* Test receiving of packets by waiting for an expected number + * of packets or a timeout. + */ +static void testReceive() +{ + unsigned int beforeRxPacketCount, afterRxPacketCount, rxPacketCount; + unsigned int rxPacketExpected = 50; + unsigned int maxTimeout = 500; /* milliseconds */ + int rssi = 0; + + TEST(wlmRxGetReceivedPackets(&beforeRxPacketCount), "wlmRxGetReceivedPackets failed"); + TEST(wlmRxPacketStart("00:11:22:33:44:55", FALSE, TRUE, rxPacketExpected, maxTimeout), + "wlmRxPacketStart failed"); + + afterRxPacketCount = beforeRxPacketCount; + TEST(wlmRxGetReceivedPackets(&afterRxPacketCount), "wlmRxGetReceivedPackets failed"); + + /* requires another pkteng to send packets else no packets will be received + * i.e. 'wl pkteng_start 00:11:22:33:44:55 tx 100 1024 0' + */ + rxPacketCount = afterRxPacketCount - beforeRxPacketCount; + printf("Packets rx=%d\n", rxPacketCount); + TEST(rxPacketCount > 0, "no packets received"); + + TEST(wlmRssiGet(&rssi), "wlmRssiGet failed"); + printf("RSSI=%d\n", rssi); + TEST(rssi != 0, "no RSSI"); + + TEST(wlmRxPacketStop(), "wlmRxPacketStop failed"); +} + +/* Test joining a network, get and compare the SSID */ +static int testJoinNetwork(char *ssid, WLM_AUTH_MODE authMode, + WLM_ENCRYPTION encryption, const char *key) +{ + char bssidBuf[256]; + int isAssociated; + char ssidBuf[256]; + + /* make sure not currently associated */ + TEST(wlmDisassociateNetwork(), "wlmDisassociateNetwork failed"); + + TEST(wlmSecuritySet(WLM_TYPE_OPEN, authMode, encryption, key), + "wlmSecuritySet failed"); + TEST(wlmJoinNetwork(ssid, WLM_MODE_BSS), "wlmJoinNetwork failed"); + /* delay to allow network association */ + delay(5000); + TEST(wlmBssidGet(bssidBuf, 256), "wlmBssidGet failed"); + isAssociated = strlen(bssidBuf) == 0 ? FALSE : TRUE; + if (isAssociated) { + TEST(wlmSsidGet(ssidBuf, 256), "wlmSsidGet failed"); + printf("associated to SSID=%s BSSID=%s\n", ssidBuf, bssidBuf); + TEST(strcmp(ssid, ssidBuf) == 0, "SSID does not match"); + } + else { + printf("failed to associate to SSID=%s using key=%s\n", ssid, key ? key : ""); + } + + TEST(wlmDisassociateNetwork(), "wlmDisassociateNetwork failed"); + + return isAssociated; +} + +/* Test joining a network */ +static void testJoinNetworkNone() +{ + /* requires an AP with the SSID, authentication, and encryption + * configured to match these settings + */ + TEST(testJoinNetwork("WLM_NONE", WLM_WPA_AUTH_DISABLED, WLM_ENCRYPT_NONE, 0), + "testJoinNetworkNone failed"); +} + +/* Test joining a WEP network */ +static void testJoinNetworkWep() +{ + /* requires an AP with the SSID, authentication, and encryption + * configured to match these settings + */ + TEST(testJoinNetwork("WLM_WEP", WLM_WPA_AUTH_DISABLED, WLM_ENCRYPT_WEP, + "2222222222444444444466666666668888888888"), + "testJoinNetworkWep failed"); +} + +/* Test joining a WPA TKIP network */ +static void testJoinNetworkWpaTkip() +{ + /* requires an AP with the SSID, authentication, and encryption + * configured to match these settings + */ + TEST(testJoinNetwork("WLM_WPA_TKIP", WLM_WPA_AUTH_PSK, WLM_ENCRYPT_TKIP, + "helloworld"), "testJoinNetworkWpaTkip failed"); +} + +/* Test joining a WPA AES network */ +static void testJoinNetworkWpaAes() +{ + /* requires an AP with the SSID, authentication, and encryption + * configured to match these settings + */ + TEST(testJoinNetwork("WLM_WPA_AES", WLM_WPA_AUTH_PSK, WLM_ENCRYPT_AES, + "helloworld"), "testJoinNetworkWpaAes failed"); +} + +/* Test joining a WPA2 TKIP network */ +static void testJoinNetworkWpa2Tkip() +{ + /* requires an AP with the SSID, authentication, and encryption + * configured to match these settings + */ + TEST(testJoinNetwork("WLM_WPA2_TKIP", WLM_WPA2_AUTH_PSK, WLM_ENCRYPT_TKIP, + "helloworld"), "testJoinNetworkWpa2Tkip failed"); +} + +/* Test joining a WPA2 AES network */ +static void testJoinNetworkWpa2Aes() +{ + /* requires an AP with the SSID, authentication, and encryption + * configured to match these settings + */ + TEST(testJoinNetwork("WLM_WPA2_AES", WLM_WPA2_AUTH_PSK, WLM_ENCRYPT_AES, + "helloworld"), "testJoinNetworkWpa2Aes failed"); +} + +static void printUsage(void) +{ + printf("\nUsage: wlmSampleTests [--socket <IP address> [server port] | " + "--serial <serial port> | --wifi <MAC address> | " + "--dongle <serial port>] [--linux | --linuxdut]]\n\n"); + printf("--socket - Ethernet between client and server (running 'wl_server_socket')\n"); + printf(" IP address - IP address of server (e.g. 10.200.30.10)\n"); + printf(" server port - Server port number (default 8000)\n\n"); + printf("--serial - Serial between client and server (running 'wl_server_serial')\n"); + printf(" serial port - Client serial port (e.g. 1 for COM1)\n\n"); + printf("--wifi - 802.11 between client and server (running 'wl_server_wifi')\n"); + printf(" (external dongle only, NIC not supported)\n"); + printf(" MAC address - MAC address of wifi interface on dongle " + "(e.g. 00:11:22:33:44:55)\n\n"); + printf("--dongle - Serial between client and dongle UART (running 'wl_server_dongle')\n"); + printf(" serial port - Client serial port (e.g. COM1 or /dev/ttyS0)\n\n"); + printf("--linux|linuxdut - Server DUT running Linux\n"); +} + +int main(int argc, char **argv) +{ + WLM_DUT_INTERFACE dutInterface = WLM_DUT_LOCAL; + char *interfaceName = 0; + WLM_DUT_SERVER_PORT dutServerPort = WLM_DEFAULT_DUT_SERVER_PORT; + WLM_DUT_OS dutOs = WLM_DUT_OS_WIN32; + + (void)argc; + + while (*++argv) { + + if (strncmp(*argv, "--help", strlen(*argv)) == 0) { + printUsage(); + exit(0); + } + + if (strncmp(*argv, "--socket", strlen(*argv)) == 0) { + int port; + + dutInterface = WLM_DUT_SOCKET; + if (!*++argv) { + printf("IP address required\n"); + printUsage(); + exit(-1); + } + interfaceName = *argv; + if (*++argv && (sscanf(*argv, "%d", &port) == 1)) { + dutServerPort = (WLM_DUT_SERVER_PORT)port; + } + else { + /* optional parameter */ + --argv; + } + } + + if (strncmp(*argv, "--serial", strlen(*argv)) == 0) { + dutInterface = WLM_DUT_SERIAL; + if (!*++argv) { + printf("serial port required\n"); + printUsage(); + exit(-1); + } + interfaceName = *argv; + } + + if (strncmp(*argv, "--wifi", strlen(*argv)) == 0) { + dutInterface = WLM_DUT_WIFI; + if (!*++argv) { + printf("MAC address required\n"); + printUsage(); + exit(-1); + } + interfaceName = *argv; + } + + if (strncmp(*argv, "--dongle", strlen(*argv)) == 0) { + unsigned int i; + char buffer[256]; + + dutInterface = WLM_DUT_DONGLE; + if (!*++argv) { + printf("COM port required\n"); + printUsage(); + exit(-1); + } + if (!(sscanf(*argv, "COM%u", &i) == 1 || + sscanf(*argv, "/dev/tty%s", buffer) == 1)) { + printf("serial port invalid\n"); + printUsage(); + exit(-1); + } + interfaceName = *argv; + } + + if ((strncmp(*argv, "--linux", strlen(*argv)) == 0) || + strncmp(*argv, "--linuxdut", strlen(*argv)) == 0) { + dutOs = WLM_DUT_OS_LINUX; + } + } + + TEST_INITIALIZE(); + + TEST_FATAL(wlmApiInit(), "wlmApiInit failed"); + + TEST_FATAL(wlmSelectInterface(dutInterface, interfaceName, + dutServerPort, dutOs), "wlmSelectInterface failed"); + + printf("\n"); + switch (dutInterface) { + case WLM_DUT_LOCAL: + printf("Test running against local DUT.\n"); + break; + case WLM_DUT_SOCKET: + printf("Test running over Ethernet to remote DUT IP=%s.\n", interfaceName); + break; + case WLM_DUT_SERIAL: + printf("Test running over serial from port %s\n", interfaceName); + break; + case WLM_DUT_WIFI: + printf("Test running over 802.11 to remote DUT MAC=%s.\n", interfaceName); + break; + case WLM_DUT_DONGLE: + printf("Test running over serial from %s to remote dongle UART\n", + interfaceName); + break; + default: + printf("Invalid interface\n"); + exit(-1); + break; + } + switch (dutOs) { + case WLM_DUT_OS_LINUX: + printf("Test running against Linux DUT.\n"); + break; + case WLM_DUT_OS_WIN32: + printf("Test running against Win32 DUT.\n"); + break; + default: + printf("Invalid DUT OS\n"); + exit(-1); + break; + } + printf("\n"); + + /* packet engine requires MPC to be disabled and WLAN interface up */ + TEST(wlmMinPowerConsumption(FALSE), "wlmMinPowerConsuption failed"); + TEST(wlmEnableAdapterUp(TRUE), "wlmEnableAdapterUp failed"); + /* invoke test cases */ + testDutInit(); + testVersion(); + testTransmit(); + testClientBatchingTransmit(); + testServerBatchingTransmit(); + testReceive(); + testJoinNetworkNone(); + testJoinNetworkWep(); + testJoinNetworkWpaTkip(); + testJoinNetworkWpaAes(); + testJoinNetworkWpa2Tkip(); + testJoinNetworkWpa2Aes(); + + TEST_FATAL(wlmApiCleanup(), "wlmApiCleanup failed"); + + TEST_FINALIZE(); + return 0; +}
diff --git a/src/tools/wlm/wlmSampleTests.sln b/src/tools/wlm/wlmSampleTests.sln new file mode 100644 index 0000000..7f6452f --- /dev/null +++ b/src/tools/wlm/wlmSampleTests.sln
@@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wlmSampleTests", "wlmSampleTests.vcproj", "{47974405-93E8-4133-BE1F-22F6BA3CAA4E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {47974405-93E8-4133-BE1F-22F6BA3CAA4E}.Debug|Win32.ActiveCfg = Debug|Win32 + {47974405-93E8-4133-BE1F-22F6BA3CAA4E}.Debug|Win32.Build.0 = Debug|Win32 + {47974405-93E8-4133-BE1F-22F6BA3CAA4E}.Release|Win32.ActiveCfg = Release|Win32 + {47974405-93E8-4133-BE1F-22F6BA3CAA4E}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal
diff --git a/src/tools/wlm/wlmSampleTests.vcproj b/src/tools/wlm/wlmSampleTests.vcproj new file mode 100755 index 0000000..2fc2468 --- /dev/null +++ b/src/tools/wlm/wlmSampleTests.vcproj
@@ -0,0 +1,207 @@ +<?xml version="1.0" encoding="UTF-8"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="wlmSampleTests" + ProjectGUID="{47974405-93E8-4133-BE1F-22F6BA3CAA4E}" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\wl\exe" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + DisableLanguageExtensions="false" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + CompileAs="1" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="../../wl/exe/obj/wlm/checked/wlm.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + Description="Copy dll to working directory" + CommandLine="copy ..\..\wl\exe\obj\wlm\checked\wlm.dll ." + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\wl\exe" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;" + RuntimeLibrary="2" + DisableLanguageExtensions="false" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CompileAs="1" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="../../wl/exe/obj/wlm/free/wlm.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + Description="Copy dll to working directory" + CommandLine="copy ..\..\wl\exe\obj\wlm\free\wlm.dll ." + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\wlmSampleTests.c" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject>
diff --git a/src/wl/exe/GNUmakefile b/src/wl/exe/GNUmakefile new file mode 100644 index 0000000..66bda37 --- /dev/null +++ b/src/wl/exe/GNUmakefile
@@ -0,0 +1,464 @@ +# +# GNUmakefile for wl/exe +# +# Copyright (c) 2000, Broadcom Corp. +# $Id: GNUmakefile 561503 2015-06-04 23:18:46Z $ + +WLAN_ComponentsInUse := bcmwifi ppr hal +include ../../makefiles/WLAN_Common.mk + +ifndef SRCBASE + SRCBASE := $(WLAN_SrcBaseR) +endif + +UNAME = $(shell uname) + +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) + +#----------------------------------------------------------------- +# Windows build, don't include Makerules due to all: conflict + +include ../../GNUmakefile.inc + +# MfgTest XP and WIN7 WLU DLL builds are built from other standalone Makefiles +# from App and MfgTest teams +# To build XP WLU DLL (output is in obj/*/mfg_dll/{free,checked}/...) +# $(MAKE) -C src/wl/exe -f GNUmakefile.wlu_dll +# To build Win7/Vista WLU DLL (output is in obj/*/mfg_dll/{Release,Debug}/...) +# $(MAKE) -C src/wl/exe/win7 + +else # UNAME + +#----------------------------------------------------------------- +# Linux build +# + +# This should be one of values recognized in src/Makerules +# 2) not windows, need to include first to pick up TARGETENV dependent vars +include $(SRCBASE)/Makerules + +# GNU make function to do compilation and dependency generation +# in one step. +define CompileAndMakedep +$(strip $1 -c -MMD -MF $(@D)/.$(@F).depend -MP $2) +endef + +ifdef CROSS_COMPILE + $(warning CROSS_COMPILE=$(CROSS_COMPILE)) + CC := $(CROSS_COMPILE)gcc + LD := $(CROSS_COMPILE)ld + NM := $(CROSS_COMPILE)nm + AR := $(CROSS_COMPILE)ar + +# LDFLAGS := -static +endif +ifdef ARCH + TARGETARCH := $(ARCH) +endif + +CFLAGS += $(EXTRA_PLATFORM_CFLAGS) + +# Use newer 11ac ratespec for wl command line +CFLAGS += -DD11AC_IOTYPES + +# Use opaque PPR structures +CFLAGS += -DPPR_API + +#ifdef WLCNT + CFLAGS += -DWLCNT +#endif + +#ifdef WIFI_ACT_FRAME + CFLAGS += -DWIFI_ACT_FRAME +#endif + +#ifdef WLEXTLOG + CFLAGS += -DWLEXTLOG +#endif + +ifeq ($(WLTEST),1) + CFLAGS += -DSERDOWNLOAD -DEVENT_LOG_COMPILE +endif + +ifeq ($(OLYMPIC_RWL),1) + CFLAGS += -DOLYMPIC_RWL +endif + +ifneq ($(findstring $(TARGETENV), "linux linuxmips linuxmips_be linuxarm linuxarm_le android android_ndk_r6b freebsd"),) + +#ifdef WLBTAMP + CFLAGS += -DWLBTAMP +#endif + +#ifdef WLP2P + CFLAGS += -DWLP2P +#endif + +#ifdef WLMCHAN + CFLAGS += -DWLMCHAN +#endif + +#ifdef WLTDLS + CFLAGS += -DWLTDLS +#endif + +#ifdef WLNDOE + CFLAGS += -DWLNDOE +#endif + +#ifdef WLP2PO + CFLAGS += -DWLP2PO +#endif + +#ifdef WLANQPO + CFLAGS += -DWLANQPO +#endif + +#ifdef SR_DEBUG + CFLAGS += -DSR_DEBUG +#endif + +#ifdef UC_FATAL + CFLAGS += -DUC_FATAL +#endif + +#ifdef TBTT_OFFSET_STAT + CFLAGS += -DTBTT_OFFSET_STAT +#endif + +#ifdef TRAFFIC_MGMT + CFLAGS += -DTRAFFIC_MGMT +#endif + +# netlink driver interface +ifeq ($(NL80211),1) + CFLAGS += -DNL80211 +endif + +#ifdef WLWNM + CFLAGS += -DWLWNM +#endif + +# extra warnings +ifneq ($(filter mips_be arm_le arm_android arm_android_ndk_r6b,$(TARGETARCH)),) +CFLAGS += -Wextra -Wall +else +CFLAGS += -Wextra -Wall -Werror +endif +CFLAGS += -DWLPFN -DWLPFN_AUTO_CONNECT -DWLOFFLD -DLINUX +ifeq ($(findstring $(TARGETENV), "freebsd"),) +CFLAGS += -DLINUX +endif +CFLAGS += -DWLC_HIGH +CFLAGS += -I$(SRCBASE)/wl/sys -I$(SRCBASE)/wl/phy +CFLAGS += $(WLAN_ComponentIncPathR) + +# Discard any "MMX" or other qualifications on x86 so that +# any TARGETARCH containing x86 is just "x86" +ifeq ($(findstring x86_mmx,$(TARGETARCH)),x86_mmx) + TARGETARCH = x86 +endif + +ASD ?= 0 +ifneq ($(ASD),1) + override ASD:= +endif +ifneq ($(ASD),1) + NOASDDIR = _noasd +endif + +RWL ?= 1 +ifeq ($(RWL),0) + override RWL:= +endif + +RWL_DONGLE ?= 1 +RWL_SOCKET ?= 1 +RWL_WIFI ?= 1 +RWL_SERIAL ?= 1 + +ifneq ($(RWL_DONGLE),0) +RWL_SERVERS += $(SERVER_DONGLE) +endif +ifneq ($(RWL_SOCKET),0) +RWL_SERVERS += $(SERVER_SOCKET) +endif +ifneq ($(RWL_WIFI),0) +RWL_SERVERS += $(SERVER_WIFI) +endif +ifneq ($(RWL_SERIAL),0) +RWL_SERVERS += $(SERVER_SERIAL) +endif +# $(TARGETARCH) is set based on TARGETENV in src/Makerules.* files +ifneq ($(findstring $(TARGETENV), "freebsd"),) +WL_OBJS := wlu.o wlu_common.o wlu_bsd.o wlu_cmd.o wlu_iov.o wlu_rates_matrix.o miniopt.o bcmutils.o bcmwifi_channels.o bcm_app_utils.o wlc_ppr.o +else +WL_OBJS := wlu.o wlu_common.o wlu_linux.o bcmutils.o bcmwifi_channels.o wlu_cmd.o wlu_iov.o wlu_client_shared.o wlu_pipe_linux.o wlu_pipe.o miniopt.o bcm_app_utils.o wlu_rates_matrix.o wlc_ppr.o +endif +SERVER_OBJS := wlu_server_linux.o wlu_pipe_linux.o wlu_pipe.o wlu_server_shared.o shellproc_linux.o +WLM_OBJS := $(WL_OBJS) wlm.o +WLHIGHSTUB_OBJS := wlhighstub.o bcm_rpc_char.o bcm_rpc.o linux_rpc_osl.o +WLHIGHSTUB_OBJS += wlc_low_stubs.o bcm_xdr.o + +# include build settings for nl80211 support +ifeq ($(NL80211),1) +include netlink.inc +endif + +# Prefix obj/<type>/TARGETARCH to produced .obj files +WL_OBJS := $(WL_OBJS:%.o=obj/wl$(NOASDDIR)/$(TARGETARCH)/%.o) +DONGLE_OBJS := $(SERVER_OBJS:%.o=obj/dongle$(NOASDDIR)/$(TARGETARCH)/%.o) +SOCKET_OBJS := $(SERVER_OBJS:%.o=obj/socket$(NOASDDIR)/$(TARGETARCH)/%.o) +WIFI_OBJS := $(SERVER_OBJS:%.o=obj/wifi$(NOASDDIR)/$(TARGETARCH)/%.o) +SERIAL_OBJS := $(SERVER_OBJS:%.o=obj/serial$(NOASDDIR)/$(TARGETARCH)/%.o) +WLM_OBJS := $(WLM_OBJS:%.o=obj/wlm/$(TARGETARCH)/%.o) +WLHIGHSTUB_OBJS := $(WLHIGHSTUB_OBJS:%.o=obj/wlhighstub/$(TARGETARCH)/%.o) + +# Derive a final list of all known objects. +OBJS := $(WL_OBJS) $(DONGLE_OBJS) $(SOCKET_OBJS) $(WIFI_OBJS) $(SERIAL_OBJS) $(WLM_OBJS) $(WLHIGHSTUB_OBJS) + +# Make a list of dependency files, one per object file. +DEPENDS := $(join $(dir $(OBJS)),$(addprefix .,$(addsuffix .depend,$(notdir $(OBJS))))) + +# Include any dependency files which currently exist. +-include $(DEPENDS) + +# TODO: Move final built objects to respective TARGETARCH dirs as well +# Final exe names +ifneq ($(TARGETARCH),x86) + ARCH_SFX = $(TARGETARCH) +endif +WL_EXE := wl$(ARCH_SFX) +SERVER_SOCKET = socket$(NOASDDIR)/$(TARGETARCH)/wl_server_socket$(ARCH_SFX) +SERVER_DONGLE = dongle$(NOASDDIR)/$(TARGETARCH)/wl_server_dongle$(ARCH_SFX) +SERVER_WIFI = wifi$(NOASDDIR)/$(TARGETARCH)/wl_server_wifi$(ARCH_SFX) +SERVER_SERIAL = serial$(NOASDDIR)/$(TARGETARCH)/wl_server_serial$(ARCH_SFX) +WLM_SO := wlm/$(TARGETARCH)/wlm$(ARCH_SFX).so +WLHIGHSTUB := obj/wlhighstub/$(TARGETARCH)/wlhighstub$(ARCH_SFX) + +# ASD specific flags +ifeq ($(ASD),1) + ASD_CFLAGS := -DRWLASD + ASD_CFLAGS += -I../../tools/Wifi_ASD_test/inc +ifneq ($(filter mips_be arm_android arm_android_ndk_r6b x86_android_ndk_r6b,$(TARGETARCH)),) + ASD_LDFLAGS:= -L../../tools/Wifi_ASD_test/lib/$(TARGETARCH) -lwfa +else + ASD_LDFLAGS:= -L../../tools/Wifi_ASD_test/lib/$(TARGETARCH) -lwfa -lpthread +endif +endif # ASD + +INSTALL_DIR ?= apps + +vpath %.c $(SRCBASE)/shared $(SRCBASE)/wl/sys $(SRCBASE)/wl/phy $(WLAN_StdSrcDirsR) $(WLAN_ComponentSrcDirsR) + +all: build_deps + +# Build servers for all but mips_be +ifeq ($(filter mips_be,$(TARGETARCH)),) +all: $(WL_EXE) servers +else +all: $(WL_EXE) +endif + +build_deps: +ifeq ($(ASD),1) + $(MAKE) -C ../../tools/Wifi_ASD_test +endif # ASD + +wlm: $(WLM_SO) + +servers: $(RWL_SERVERS) + +# Handle creation of directories for objects mentioned below. +$(addprefix obj/,$(addsuffix $(NOASDDIR)/$(TARGETARCH),wl dongle socket wifi serial) $(addsuffix /$(TARGETARCH),wlm wlhighstub)): + @mkdir -pv $@ + +# Compilation targets +obj/wl$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/wl$(NOASDDIR)/$(TARGETARCH) +ifneq ($(RWL),) + $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_SOCKET -DRWL_DONGLE -DRWL_WIFI -DRWL_SERIAL -o $@ $<) +else + $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -o $@ $<) +endif + +obj/dongle$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/dongle$(NOASDDIR)/$(TARGETARCH) + $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_DONGLE -o $@ $<) + +obj/socket$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/socket$(NOASDDIR)/$(TARGETARCH) + $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_SOCKET -o $@ $<) + +obj/wifi$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/wifi$(NOASDDIR)/$(TARGETARCH) + $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_WIFI -o $@ $<) + +obj/serial$(NOASDDIR)/$(TARGETARCH)/%.o: %.c | obj/serial$(NOASDDIR)/$(TARGETARCH) + $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_SERIAL -o $@ $<) + +obj/wlm/$(TARGETARCH)/%.o: %.c | obj/wlm/$(TARGETARCH) + $(call CompileAndMakedep,$(CC),$(CFLAGS) $(ASD_CFLAGS) -DRWL_DONGLE -DRWL_SOCKET -DRWL_WIFI -DRWL_SERIAL -DWLMSO -fPIC -o $@ $<) + +obj/wlhighstub/$(TARGETARCH)/%.o: %.c | obj/wlhighstub/$(TARGETARCH) + $(call CompileAndMakedep,$(CC),$(CFLAGS) -o $@ $<) + +$(WLHIGHSTUB): $(WLHIGHSTUB_OBJS) + @mkdir -pv $(@D) + +# Final link targets +$(WL_EXE): $(WL_OBJS) + $(strip $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)) + +# net_priv target is for building the dhd with NET_ADMIN privilege (i.e. to avoid running as root) +# note: The 'setcap' command is availble from the libcap2-bin package +# note: linux kernel < 2.6.33 doesn't support Security File Capabilities by default +net_priv: $(WL_EXE) + sudo setcap CAP_NET_ADMIN=eip $^ + +$(SERVER_DONGLE): $(DONGLE_OBJS) + @mkdir -pv $(@D) + $(strip $(CC) $(LDFLAGS) -o $@ $^ $(ASD_LDFLAGS)) + +$(SERVER_SOCKET): $(SOCKET_OBJS) + @mkdir -pv $(@D) + $(strip $(CC) $(LDFLAGS) -o $@ $^ $(ASD_LDFLAGS)) + +$(SERVER_WIFI): $(WIFI_OBJS) + @mkdir -pv $(@D) + $(strip $(CC) $(LDFLAGS) -o $@ $^ $(ASD_LDFLAGS)) + +$(SERVER_SERIAL): $(SERIAL_OBJS) + @mkdir -pv $(@D) + $(strip $(CC) $(LDFLAGS) -o $@ $^ $(ASD_LDFLAGS)) + +$(WLM_SO): $(WLM_OBJS) + @mkdir -pv $(@D) + $(strip $(CC) $(LDFLAGS) -shared -o $@ $^) + + +wldefs: wlmain.o + $(CC) $(LDFLAGS) -o $@ $< + +.PHONY: all clean wlm release_bins net_priv + +release_bins: + @mkdir -p $(INSTALL_DIR) + install -pv $(WL_EXE) $(INSTALL_DIR) +ifeq ($(filter mips_be,$(TARGETARCH)),) + install -pv $(SERVER_SOCKET) $(INSTALL_DIR) + install -pv $(SERVER_DONGLE) $(INSTALL_DIR) + install -pv $(SERVER_WIFI) $(INSTALL_DIR) + install -pv $(SERVER_SERIAL) $(INSTALL_DIR) +endif +ifeq ($(ASD),1) + $(MAKE) -C ../../tools/Wifi_ASD_test release_bins +endif #ASD + +clean:: + rm -fv $(WL_EXE) $(WL_OBJS) $(SERVER_SOCKET) $(SERVER_DONGLE) $(SERVER_WIFI) $(SERVER_SERIAL) $(SOCKET_OBJS) $(SERIAL_OBJS) $(WIFI_OBJS) $(DONGLE_OBJS) $(WLM_SO) $(WLM_OBJS) $(SERVER_SERIAL) $(DEPENDS) + +endif # TARGETENV linux + +#----------------------------------------------------------------- +# MacOS build +# + +ifeq ($(TARGETENV), macos) + +include $(SRCBASE)/Makerules.env + +.PHONY: all everything clean wl wl_server_socket wl_server_wifi wl_dongle + +PROJTGT := wl +BUILD := xcodebuild +PROJECT := wl.xcodeproj +OBJDIR := $(TARGETENV)/$(MACOS_VER) + +all: wl wl_server_socket + +everything: wl wl_server_socket wl_server_wifi wl_dongle + +clean:: + rm -rf $(OBJDIR) build + +wl wl_server_socket wl_server_wifi: | $(OBJDIR) + +# +# dongle wl is located at ./build/Debug/wl +# +wl_dongle: + $(BUILD) -project $(PROJECT) -target $(PROJTGT) -configuration Debug build + +WL_EXE := $(OBJDIR)/wl +SERVER_SOCKET := $(OBJDIR)/socket/wl_server_socket +SERVER_WIFI := $(OBJDIR)/wifi/wl_server_wifi + +WL_OBJS := $(addprefix $(OBJDIR)/,wlu.o wlu_common.o wlu_macos.o bcmutils.o bcmwifi_channels.o wlu_cmd.o wlu_iov.o miniopt.o bcm_app_utils.o wlu_rates_matrix.o wlc_ppr.o) +SERVER_OBJS := wlu_server_macos.o wlu_pipe_linux.o wlu_pipe.o wlu_server_shared.o shellproc_linux.o +SOCKET_OBJS := $(SERVER_OBJS:%.o=$(OBJDIR)/socket/%.o) +WIFI_OBJS := $(SERVER_OBJS:%.o=$(OBJDIR)/wifi/%.o) + +# Derive a final list of all known objects. +OBJS := $(WL_OBJS) $(SOCKET_OBJS) $(WIFI_OBJS) + +# Create the sub-directories needed to hold object files. +$(sort $(dir $(OBJS))): + @mkdir -pv $@ + +# Make a list of dependency files, one per object file. +DEPENDS := $(join $(dir $(OBJS)),$(addprefix .,$(addsuffix .depend,$(notdir $(OBJS))))) + +# Include any dependency files which currently exist. +-include $(DEPENDS) + +vpath %.c .. $(SRCBASE)/shared $(SRCBASE)/wl/sys $(SRCBASE)/wl/phy $(WLAN_StdSrcDirsR) $(WLAN_ComponentSrcDirsR) + +MACOS_VER ?:= $(shell sw_vers -productVersion) + +ifneq (,$(findstring 10.9,$(MACOS_VER))) + SDKROOT := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk + GCDEFS := $(GCDEFS) -DRDR_5905993 -DWLP2P -DWLMCHAN -DWLAWDL -DWLOFFLD -DPPR_API -I/usr/include -I/Library/Developer/CommandLineTools/usr/include -I$(SDKROOT)/System/Library/Frameworks/Kernel.framework/Versions/A/PrivateHeaders/IOKit/apple80211 -I$(SDKROOT)/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include +else +ifneq (,$(findstring 10.8.3,$(MACOS_VER))) + SDKROOT := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk + GCDEFS := $(GCDEFS) -DRDR_5905993 -DWLP2P -DWLMCHAN -DWLAWDL -DWLOFFLD -DPPR_API -I/usr/include -I/Library/Developer/CommandLineTools/usr/include -I$(SDKROOT)/System/Library/Frameworks/Kernel.framework/Versions/A/PrivateHeaders/IOKit/apple80211 -I$(SDKROOT)/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include +else +ifneq (,$(findstring 10.8,$(MACOS_VER))) + GCDEFS := $(GCDEFS) -DRDR_5905993 -DWLP2P -DWLMCHAN -DWLAWDL -DWLOFFLD -DPPR_API -I/usr/include -I/System/Library/Frameworks/Kernel.framework/Versions/A/PrivateHeaders/IOKit/apple80211 +else +ifneq (,$(findstring 10.7,$(MACOS_VER))) + GCDEFS := $(GCDEFS) -DRDR_5905993 -DWLP2P -DWLMCHAN -DWLOFFLD -DPPR_API +else +ifneq (,$(findstring 10.6,$(MACOS_VER))) + GCDEFS := $(GCDEFS) -DRDR_5905993 -DWLP2P -DWLMCHAN -DWLOFFLD -DPPR_API +endif +endif +endif +endif +endif + +$(OBJDIR)/%.o: %.c | $(OBJDIR) + $(call CompileAndMakedep,$(CC),$(CFLAGS) -o $@ $<) + +wl: $(OBJDIR)/wl +$(OBJDIR)/wl: $(WL_OBJS) +ifneq ($(findstring $(MACOS_VER), 10.8 10.9),) + $(CC) -L/usr/lib $(LDFLAGS) -o $@ $^ +else + $(CC) $(LDFLAGS) -o $@ $^ +endif + +wl_server_socket: $(SERVER_SOCKET) +$(SERVER_SOCKET): $(SOCKET_OBJS) + $(strip $(CC) $(LDFLAGS) -o $@ $^) + +$(OBJDIR)/socket/%.o: %.c | $(OBJDIR)/socket + $(call CompileAndMakedep,$(CC),$(CFLAGS) -DRWL_SOCKET -DREMOTE_WL -o $@ $<) + +wl_server_wifi: $(SERVER_WIFI) +$(SERVER_WIFI): $(WIFI_OBJS) + $(strip $(CC) $(LDFLAGS) -o $@ $^) + +$(OBJDIR)/wifi/%.o: %.c | $(OBJDIR)/wifi + $(call CompileAndMakedep,$(CC),$(CFLAGS) -DRWL_WIFI -DREMOTE_WL -o $@ $<) + +endif # TARGETENV macos + +endif # UNAME
diff --git a/src/wl/exe/shellproc_linux.c b/src/wl/exe/shellproc_linux.c new file mode 100644 index 0000000..d607d90 --- /dev/null +++ b/src/wl/exe/shellproc_linux.c
@@ -0,0 +1,697 @@ +/* + * Remote shell command execution (common for all transports) for linux + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: shellproc_linux.c 377604 2013-01-08 09:10:28Z $ + */ + +/* Linux remote shell command execution + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/wait.h> +#include <signal.h> +#include <fcntl.h> +#include <typedefs.h> +#include <bcmutils.h> +#include <bcmcdc.h> +#include "wlu_remote.h" +#include <sys/poll.h> +#include <malloc.h> +#include <miniopt.h> +#include <sys/utsname.h> +#define ASYNC_RESP 0 +#define MAX_SHELL_ASYNC_RESP 128 /* Support for maximum 5 async process */ +#define MAX_ASYNC_FILE_LENGTH 50 +#define MAX_PID_CMD_LENGTH 20 +#define MAX_PID_RESP_LENTH 50 +#define MAX_SHELL_CMD_LENTH 256 +#define PID_TOKEN_SIZE 50 +#define PID_SEARCH_CMD_SIZE 100 +#define ASYNC_SHELL_CHAR "%" /* Async process identifier from the client */ +#define FILE_PERMISSION 777 + +#define DEFAULT_SHELL_TIMEOUT 0 /* Default TimeOut Value for synchronous shell commands */ +#define SHELL_RETURNVALUE_SIZE 2 /* Size of Return Value of the shell command */ +#define SHELL_ASYNCCMD_ID 1 /* To identify if it is an async command */ +#define REBOOT_MSG "Rebooting AP ...\n" + +/* Function prototypes */ + +static int rwl_get_file_size(char *file_name); +static int remote_shell_async_exec(char *buf_ptr); +static int remote_shell_sync_exec(char *cmd_buf_ptr, void *wl); + + +/* Data structure to hold async shell information */ +typedef struct remote_shell_async { + pid_t PID; + char file_name[MAX_ASYNC_FILE_LENGTH]; +} remote_shell_async_t; + +remote_shell_async_t g_async_resp[MAX_SHELL_ASYNC_RESP]; + +extern int g_shellsync_pid; + +extern unsigned char g_return_stat; +extern void rwl_chld_handler(int num); +extern int set_ctrlc; +extern void handle_ctrlc(int unused); + +/* Global variable to store the timeout value for the shell commands */ +static int g_shellsync_timeout = DEFAULT_SHELL_TIMEOUT; +char globalbuffer[MAX_SHELL_CMD_LENTH]; + +/* Wait for process termination. + * This function returns immediately if the child has + * already exited (zombie process) + */ +static void +sigchld_handler(int s) +{ + UNUSED_PARAMETER(s); + + while (waitpid(-1, NULL, WNOHANG) > 0); +} + +/* Create a main directory \tmp\RWL\ for the shell response files */ +int +rwl_create_dir(void) +{ + if (mkdir(SHELL_RESP_PATH, FILE_PERMISSION) < 0) { + if (errno != EEXIST) + return BCME_ERROR; + } + + return SUCCESS; +} + +/* Main function for shell command execution */ +int +remote_shell_execute(char* buf_ptr, void *wl) +{ + char *async_cmd_flag; + int msg_len; + + /* Check for the "%" token in the buffer from client + * If "%" token is present, execute asynchronous process + * else, execute synchronous shell process + */ + async_cmd_flag = strstr((char*)buf_ptr, ASYNC_SHELL_CHAR); + + if ((async_cmd_flag != NULL) && (!strcmp(async_cmd_flag, ASYNC_SHELL_CHAR))) { + g_shellsync_pid = SHELL_ASYNCCMD_ID; + msg_len = remote_shell_async_exec(buf_ptr); + } + else { + msg_len = remote_shell_sync_exec(buf_ptr, wl); + strcpy(buf_ptr, globalbuffer); + } + return msg_len; +} + +/* Function to get the shell response from the file */ +int +remote_shell_async_get_resp(char* shell_fname, char* buf_ptr, int msg_len) +{ + int sts = 0; + FILE *shell_fpt; + + shell_fpt = fopen(shell_fname, "rb"); + + if (shell_fpt == NULL) { + DPRINT_ERR(ERR, "\nShell Cmd:File open error\n"); + return sts; + } + + /* If there is any response from the shell, Read the file and + * update the buffer for the shell response + * else Just send the return value of the command executed + */ + if (g_shellsync_pid != SHELL_ASYNCCMD_ID) { + if (msg_len) + sts = fread(buf_ptr, sizeof(char), msg_len, shell_fpt); + fscanf(shell_fpt, "%2x", &sts); + } + else + sts = fread(buf_ptr, sizeof(char), MAX_SHELL_CMD_LENTH, shell_fpt); + + fclose(shell_fpt); + + remove(shell_fname); + + DPRINT_DBG(OUTPUT, "\n Resp buff from shell cmdis %s\n", buf_ptr); + + return sts; +} + +/* + * Function to get the shell response length + * by opening the file containing the shell response + * and get the total file size. + * For a given input file name it returns File size. + */ +static int +rwl_get_file_size(char *file_name) +{ + FILE *shell_fpt; + int filesize = 0; + + shell_fpt = fopen(file_name, "rb"); + + if (shell_fpt == NULL) { + DPRINT_DBG(OUTPUT, "\nShell Cmd:File open error\n"); + return filesize; + } + + /* obtain file size */ + if (fseek(shell_fpt, 0, SEEK_END) < 0) + return filesize; + + filesize = ftell(shell_fpt); + fclose(shell_fpt); + + return filesize; +} + +/* + * Function for executing asynchronous shell comamnd + * Stores the results in async temp file and returns the PID + */ +static int +remote_shell_async_exec(char *buf_ptr) +{ + int PID_val = 0, val, msg_len, sts; + FILE *fpt; + int async_count = 0; /* counter needs to be initialized */ + struct sigaction sa; + char pid_search_cmd[MAX_PID_CMD_LENGTH]; + char pid_resp_buf[MAX_PID_RESP_LENTH]; + char temp_async_file_name[MAX_ASYNC_FILE_LENGTH]; + pid_t pid; + char *pid_token, next_pid[PID_TOKEN_SIZE][PID_TOKEN_SIZE]; + struct utsname name; + + /* Call the signal handler for reaping defunct or zombie process */ + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + perror("sigaction:"); + } + + /* Store the async file name if that async process is not killed. + * Async file name: async_temp_0...5 + */ + for (val = 0; val < MAX_SHELL_ASYNC_RESP; val++) { + if (g_async_resp[val].PID > 0) { + async_count++; + } else { + sprintf(g_async_resp[val].file_name, "%s%d", "async_temp_", val); + break; + } + } + sprintf(temp_async_file_name, "%s%s", SHELL_RESP_PATH, + g_async_resp[val].file_name); + + DPRINT_DBG(OUTPUT, "\nasync_count:%d\n", async_count); + if (async_count >= MAX_SHELL_ASYNC_RESP) { + sprintf(buf_ptr, "\n%s\n", "Exceeded max async process forking"); + return BCME_ERROR; + } + + /* Open a child process. The fork will return the PID of the child process + * (i.e) defunct process PID in parent's thread of execution. Zero is returned + * for child's thread of execution. + */ + if ((pid = fork()) == 0) { + /* Redirect the async process output to the async file + * Then after the client executes the kill command for that + * async process, the file will give the status of async process + */ + strtok(buf_ptr, ASYNC_SHELL_CHAR); /* Remove % character from the command buf */ + uname(&name); + /* + * Checking for mips architecture + * different command for mips and x86 + */ + if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) { + strcat(buf_ptr, "&> "); /* buf_ptr is now "ping 127.0.0.1&> " */ + strcat(buf_ptr, temp_async_file_name); /* Add path \tmp\RWL\async_temp_* */ + } + else { + strcat(buf_ptr, " > "); /* buf_ptr is now "ping 127.0.0.1> " */ + strcat(buf_ptr, temp_async_file_name); /* Add path \tmp\RWL\async_temp_* */ + strcat(buf_ptr, " 2>&1 &"); + } + if ((sts = execl(SH_PATH, "sh", "-c", buf_ptr, NULL)) == -1) { + sprintf(buf_ptr, "%s\n", "Not able to execute shell cmd"); + return BCME_ERROR; + } + exit(0); + } /* end of fork */ + + if (pid < 0) { + perror("\nFork error:"); + sprintf(buf_ptr, "%s\n", "Forking async process failed"); + return BCME_ERROR; + } + + /* Find the PID of the running process (for ex: ping) + * pidof -s options returns latest PID of the command. + */ + strtok(buf_ptr, " "); + + uname(&name); + /* Checking for mips architecture */ + if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) + sprintf(pid_search_cmd, "pidof -s %s", buf_ptr); + else + sprintf(pid_search_cmd, "pidof %s", buf_ptr); + + sleep(1); + + /* Execute the command e.g "pidof ping" */ + if ((fpt = popen(pid_search_cmd, "r")) == NULL) { + sprintf(buf_ptr, "%s\n", "Can't return PID"); + return BCME_ERROR; + } + + /* Get the PID and copy the PID in buf_ptr to send to the client */ + fgets(pid_resp_buf, sizeof(pid_resp_buf), fpt); + + /* Checking for mips architecture */ + if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) { + PID_val = atoi(pid_resp_buf); + } + else { + /* code to extract the correct PID */ + pid_token = strtok_r(pid_resp_buf, " ", (char **)next_pid); + /* the pid buffer will terminate with a '\n' */ + while (pid_token != NULL && *pid_token != '\n') { + PID_val = atoi(pid_token); + pid_token = strtok_r(NULL, " ", (char **)next_pid); + } + } + if (PID_val == 0) { + msg_len = rwl_get_file_size(temp_async_file_name); + remote_shell_async_get_resp(temp_async_file_name, buf_ptr, msg_len); + + } else { + g_async_resp[val].PID = PID_val; + /* Update PID value in buffer to send it to client */ + sprintf(buf_ptr, "%d", PID_val); + msg_len = strlen(buf_ptr); + } + + pclose(fpt); + /* In async case, the PID value will be copied to the input buffer only + * and there is no need of getting the response from the file. So return + * value can be -1. + */ + return msg_len; +} + +/* Process for 'kill' command. + * Kill command can also be used from the client to get the + * result of asynchronous command and actually kill the mentioned process + */ +static int +remote_kill_cmd_exec(char *cmd_buf_ptr) +{ + char file_name[MAX_ASYNC_FILE_LENGTH]; + int PID_val = 0, val, msg_len; + FILE *fpt; + char *pid_token, next_pid[PID_TOKEN_SIZE][PID_TOKEN_SIZE]; + + system(cmd_buf_ptr); + + /* Parse the PID val from the kill command. + */ + pid_token = strtok_r(cmd_buf_ptr, " ", (char **)next_pid); + while (pid_token != NULL && *pid_token != '\n') { + /* to extract the PID from the kill command */ + PID_val = atoi(pid_token); + pid_token = strtok_r(NULL, " ", (char **)next_pid); + } + + /* Check for the matching PID from the async structure and + * give the last 256 bytes statistics of the async process + * that was running + */ + for (val = 0; val < MAX_SHELL_ASYNC_RESP; ++val) { + if (g_async_resp[val].PID == PID_val) { + /* We found a match here. Hence get the response now from the + * corresponding async response file + */ + sprintf(file_name, "%s%s", SHELL_RESP_PATH, g_async_resp[val].file_name); + msg_len = rwl_get_file_size(file_name); + if (msg_len > 0) { + if ((fpt = fopen(file_name, "rb")) == NULL) { + DPRINT_DBG(OUTPUT, "\nShell Cmd:File open error\n"); + return BCME_ERROR; + } + + if (fseek(fpt, 0, SEEK_SET) < 0) { + fclose(fpt); + return BCME_ERROR; + } + + if (fread(cmd_buf_ptr, sizeof(char), MAX_SHELL_CMD_LENTH, + fpt) <= 0) { + sprintf(cmd_buf_ptr, "%s\n", "Shell Resp:Reading error"); + fclose(fpt); + return BCME_ERROR; + } + + fclose(fpt); + } + else + sprintf(cmd_buf_ptr, "ed %d: No Response\n", PID_val); + remove(g_async_resp[val].file_name); + + g_async_resp[val].PID = 0; + break; + } + } + return MAX_SHELL_CMD_LENTH; +} + +/* Handle --timeout command line option for linux servers */ +int +shell_timeout_cmd(char *cmd_buf_ptr, char *sync_file_name) +{ + char *token1, *token2, *nexttoken; + FILE* fp; + int msg_len; + + token1 = strtok_r(cmd_buf_ptr, "--timeout ", &nexttoken); + if (token1) + token2 = strtok_r(NULL, token1, &nexttoken); + if (token1 == NULL || atoi(token1) <= 0 || token2 == NULL) { + fp = fopen(sync_file_name, "w+"); + fprintf(fp, "Usage: ./wl --<transport> <ip/mac> sh" + "--timeout <timeout value> <shell command>\n"); + fprintf(fp, "Eg: ./wl --socket 172.22.65.226 sh --timeout 15 ls\n"); + fflush(fp); + msg_len = rwl_get_file_size(sync_file_name); + strcpy(cmd_buf_ptr, sync_file_name); + fclose(fp); + strcpy(globalbuffer, sync_file_name); + printf("Fix timeout problem in socket!!!!!\n"); + return msg_len; + } + else + g_shellsync_timeout = atoi(token1); + return BCME_OK; +} + +/* Handle synchronous shell commands here */ +static int +remote_shell_sync_exec(char *cmd_buf_ptr, void *wl) +{ + char *kill_cmd_token; + char sync_file_name[] = TEMPLATE; + int fd, msg_len; + char cmd[(strlen(cmd_buf_ptr) + 1)]; + int pid, status, pid_final; + char buf[SHELL_RESP_SIZE], cmd_find_lastpid[PID_SEARCH_CMD_SIZE]; + int nbytes = 0; + int child_status; + static int sent_once = 0; + struct utsname name; + FILE *fpt; + + /* Default Size of Return Value of the shell command is 2bytes */ + + kill_cmd_token = strstr(cmd_buf_ptr, "kill"); + + /* Synchronous Kill command processing is handled separately */ + if (kill_cmd_token != NULL) { + msg_len = remote_kill_cmd_exec(cmd_buf_ptr); + remote_tx_response(wl, cmd_buf_ptr, msg_len); + return 0; + } + + + /* Process synchronous command other than kill command */ + if ((fd = mkstemp(sync_file_name)) < 0) { + perror("mkstemp failed"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + sprintf(cmd_buf_ptr, "%s\n", "mkstemp failed"); + return BCME_ERROR; + } + + close(fd); + + strcpy(cmd, cmd_buf_ptr); + /* Synchronous timeout command processing is handled separately */ + if (strstr(cmd_buf_ptr, "--timeout") != NULL) { + if ((msg_len = shell_timeout_cmd (cmd, sync_file_name) > 0)) { + /* Signal end of command output */ + g_rem_ptr->msg.len = 0; + g_rem_ptr->msg.cmd = g_return_stat; + remote_tx_response(wl, NULL, 0); + return msg_len; + } else { + /* Parse out --timeout <val> since command is successful + * point buffer to the shell command + */ + strcpy(cmd, cmd_buf_ptr); + strtok_r(cmd, " ", &cmd_buf_ptr); + strcpy(cmd, cmd_buf_ptr); + strtok_r(cmd, " ", &cmd_buf_ptr); + } + } + + /* Schedule an ALARM in case of timeout value of SHELL_TIMEOUT seconds */ + /* Defalut time out only in case of Non socket transport */ + alarm(g_shellsync_timeout); + /* registering the relevant signals to handle end of child process, + * the ctrl+c event on the server side and the kill command on the + * server process + */ + signal(SIGCHLD, rwl_chld_handler); + signal(SIGINT, handle_ctrlc); + signal(SIGTERM, handle_ctrlc); + + /* Set g_sig_chld before forking */ + g_sig_chld = 1; + + if (strcmp("reboot", cmd_buf_ptr) == 0) { /* reboot command */ + memset(buf, 0, sizeof(buf)); + strncpy(buf, REBOOT_MSG, sizeof(REBOOT_MSG)); + remote_tx_response(wl, buf, 0); + + /* Signal end of command output */ + g_rem_ptr->msg.len = 0; + g_rem_ptr->msg.cmd = 0; + remote_tx_response(wl, NULL, 0); + sleep(1); + + /* Clean up the temp file */ + remove(sync_file_name); + } + + if ((pid = fork()) == 0) { + close(STDOUT_FILENO); + fd = open(sync_file_name, O_WRONLY|O_SYNC); + /* Redirect stdin to dev/null. This handles un usual commands like + * sh cat from the client side + */ + close(STDIN_FILENO); + open("/dev/null", O_RDONLY); + close(STDERR_FILENO); + fcntl(fd, F_DUPFD, STDERR_FILENO); + if ((status = execl(SH_PATH, "sh", "-c", cmd_buf_ptr, NULL)) == -1) { + perror("Exec error"); + + } + } /* end of fork */ + + g_shellsync_pid = pid; + /* The g_return_stat is being set for short commands */ + waitpid(g_shellsync_pid, &child_status, WNOHANG); + if (WIFEXITED(child_status)) + g_return_stat = WEXITSTATUS(child_status); + else + g_return_stat = 1; + + /* Read file in the interim from a temp file and send back the results */ + fd = open(sync_file_name, O_RDONLY|O_SYNC); + + while (1) { + /* read file in the interim and send back the results */ + nbytes = read(fd, buf, SHELL_RESP_SIZE); + g_rem_ptr->msg.len = nbytes; + if (nbytes > 0) { + remote_tx_response(wl, buf, 0); +#ifdef RWL_SERIAL + /* usleep introduced for flooding of data over serial port */ + usleep(1); +#endif + } + if (get_ctrlc_header(wl) >= 0) { + if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) { + uname(&name); + /* Checking for mips architecture + * The mips machine responds differently to + * execl command. so the pid is incremented + * to kill the right command. + */ + if (strncmp(name.machine, "mips", sizeof(name.machine)) == 0) + pid++; + if (strncmp(name.machine, "armv5tel", sizeof(name.machine)) == 0) { + snprintf(cmd_find_lastpid, sizeof(cmd_find_lastpid), + "ps | awk \'PRINT $1\' | tail -n 1"); + if ((fpt = popen(cmd_find_lastpid, "r")) == NULL) { + sprintf(buf, "%s\n", "Can't return PID"); + return BCME_ERROR; + } + fgets(cmd_find_lastpid, sizeof(cmd_find_lastpid), fpt); + pid_final = atoi(cmd_find_lastpid); + while (pid <= pid_final) { + kill(pid, SIGKILL); + pid++; + } + pclose(fpt); + } + else { + kill(pid, SIGKILL); + } + break; + } + } + if (get_ctrlc_header(wl) >= 0) { + if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) { + uname(&name); + /* Checking for mips architecture + * The mips machine responds differently to + * execl command. so the pid is incremented + * to kill the right command. + */ + if (strncmp(name.machine, "mips", sizeof(name.machine)) == 0) { + pid++; + kill(pid, SIGKILL); + } + /* Checking for arm architecture + * The multiple commands would not work + * for ctrl+C. So we kill the processes + * spawned after the parent. This method has + * its own limitations but the busybox in pxa + * doesnot have many options to implement it better + */ + else { + if (strncmp(name.machine, "armv5tel", + sizeof(name.machine)) == 0) { + /* The command below is used to get the + * PIDs and they are killed + */ + snprintf(cmd_find_lastpid, + sizeof(cmd_find_lastpid), + "ps | awk \'PRINT $1\' | tail -n 1"); + if ((fpt = popen(cmd_find_lastpid, "r")) == NULL) { + sprintf(buf, "%s\n", "Can't return PID"); + return BCME_ERROR; + } + fgets(cmd_find_lastpid, sizeof(cmd_find_lastpid), + fpt); + pid_final = atoi(cmd_find_lastpid); + while (pid <= pid_final) { + kill(pid, SIGKILL); + pid++; + } + pclose(fpt); + } + /* In the case of x86, on receiving ctrl+C + * the child PIDs are obtained by searching + * the parent PID to obtain the PIDs of the + * and kill them + */ + else { + while (pid != 0) { + /* The commad below is used to get the + * child PIDs by using their parent PID + */ + snprintf(cmd_find_lastpid, + sizeof(cmd_find_lastpid), + "ps al | awk \"{ if (\\$4 == %d)" + " {print \\$3}}\"| head -n 1", + g_shellsync_pid); + if ((fpt = popen(cmd_find_lastpid, "r")) + == NULL) { + sprintf(buf, "%s\n", + "Can't return PID"); + return BCME_ERROR; + } + fgets(cmd_find_lastpid, + sizeof(cmd_find_lastpid), + fpt); + pid = atoi(cmd_find_lastpid); + if (pid == 0) + kill(g_shellsync_pid, SIGKILL); + else + kill(pid, SIGKILL); + pclose(fpt); + } + } + } + break; + } + } + if (set_ctrlc == 1) { + g_rem_ptr->msg.len = 0; + g_rem_ptr->msg.cmd = g_return_stat; + remote_tx_response(wl, NULL, g_return_stat); + unlink(sync_file_name); + kill(0, SIGKILL); + } + /* It is possible that the child would have exited + * However we did not get a chance to read the file + * In this case go once again and check the file + */ + if (!sent_once && !g_sig_chld) { + sent_once = 1; + continue; + } + + if (!(g_sig_chld || nbytes)) + break; + } + wait(NULL); + close(fd); + + /* Signal end of command output */ + g_rem_ptr->msg.len = 0; + g_rem_ptr->msg.cmd = g_return_stat; + + remote_tx_response(wl, NULL, g_return_stat); + /* Cancel the time out alarm if any */ + alarm(0); + sent_once = 0; + /* Clean up the temp file */ + unlink(sync_file_name); + g_shellsync_timeout = DEFAULT_SHELL_TIMEOUT; + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + + return BCME_OK; +}
diff --git a/src/wl/exe/uamp.mk b/src/wl/exe/uamp.mk new file mode 100644 index 0000000..78ba224 --- /dev/null +++ b/src/wl/exe/uamp.mk
@@ -0,0 +1,62 @@ +# +# GNUmakefile for wl/exe +# +# Copyright (c) 2000, Broadcom Corp. +# $Id: uamp.mk 403251 2013-05-20 05:15:55Z $ + +ifndef SRCBASE + SRCBASE = ../.. +endif + +UNAME = $(shell uname) + + +#----------------------------------------------------------------- +# Linux build +# + +# This should be one of values recognized in src/Makerules +# 2) not windows, need to include first to pick up TARGETENV dependent vars +include $(SRCBASE)/Makerules + +# Discard any "MMX" or other qualifications on x86 so that +# any TARGETARCH containing x86 is just "x86" +ifeq ($(findstring x86,$(TARGETARCH)),x86) + TARGETARCH = x86 +endif + +# $(TARGETARCH) is set based on TARGETENV in src/Makerules.* files +UAMP_OBJS := uamp_linux.o + +# Prefix obj/<type>/TARGETARCH to produced .obj files +UAMP_OBJS := $(UAMP_OBJS:%.o=obj/uamp/$(TARGETARCH)/%.o) + +# TODO: Move final built objects to respective TARGETARCH dirs as well +# Final exe names +ARCH_SFX := $(if $(findstring x86,$(TARGETARCH)),,$(TARGETARCH)) +UAMP_EXE := uamp$(ARCH_SFX) + +# extra warnings +CFLAGS += -Wextra $(CUSTOM_FLAGS) + +CFLAGS += -DLINUX -DWLBTAMP + +LDFLAGS += -pthread -lrt + +vpath %.c $(SRCBASE)/wl/sys $(WLAN_StdSrcDirsA) $(WLAN_ComponentSrcDirs) + +.PHONY: all +all: $(UAMP_EXE) + +# Compilation targets +obj/uamp/$(TARGETARCH)/%.o: %.c + @mkdir -pv $(@D) + $(CC) -c $(CFLAGS) -o $@ $^ + +# Final link targets +$(UAMP_EXE): $(UAMP_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + +.PHONY: clean +clean: + rm -fv $(UAMP_EXE) $(UAMP_OBJS)
diff --git a/src/wl/exe/wlm.c b/src/wl/exe/wlm.c new file mode 100644 index 0000000..013f8af --- /dev/null +++ b/src/wl/exe/wlm.c
@@ -0,0 +1,2266 @@ +/* + * Wlm (Wireless LAN Manufacturing) test library. + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlm.c 425281 2013-09-23 17:40:45Z $ + */ + +#if defined(WIN32) +#include <windows.h> +#endif +#include <stdio.h> +#include <stdlib.h> + +#include <bcmcdc.h> // cdc_ioctl_t used in wlu_remote.h +#if defined(WIN32) +#include <bcmstdlib.h> +#endif +#include <bcmendian.h> +#include <bcmutils.h> // ARRAYSIZE, bcmerrorstr() +#include <bcmsrom_fmt.h> // SROM4_WORDS +#include <bcmsrom_tbl.h> // pavars_t +#include <wlioctl.h> +#if defined(WIN32) +#include <epictrl.h> // ADAPTER +#endif +#include <proto/ethernet.h> // ETHER_ADDR_LEN + +#include <sys/socket.h> +#include <proto/bcmip.h> // ipv4_addr +#include <arpa/inet.h> // struct sockaddr_in +#include <string.h> +#include <signal.h> + +#include "wlu_remote.h" // wl remote type defines (ex: NO_REMOTE) +#include "wlu_pipe.h" // rwl_open_pipe() +#include "wlu.h" // wl_ether_atoe() +#include "wlm.h" +#include "wlc_ppr.h" + +/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */ +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) +#define htodenum(i) (i) +#define dtohenum(i) (i) + +#if defined(WIN32) +static HANDLE irh; +int adapter; +#else +static void * irh; +#define HANDLE void * +#endif + +#define MAX_INTERFACE_NAME_LENGTH 128 +static char interfaceName[MAX_INTERFACE_NAME_LENGTH + 1] = {0}; +static WLM_BAND curBand = WLM_BAND_AUTO; +static int ioctl_version; + +extern int wl_os_type_get_rwl(void); +extern void wl_os_type_set_rwl(int os_type); +extern int wl_ir_init_rwl(HANDLE *irh); +extern int wl_ir_init_adapter_rwl(HANDLE *irh, int adapter); +extern void wl_close_rwl(int remote_type, HANDLE irh); +extern int rwl_init_socket(void); + +extern int wlu_get(void *wl, int cmd, void *buf, int len); +extern int wlu_set(void *wl, int cmd, void *buf, int len); + +extern int wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len); +extern int wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen); +extern int wlu_iovar_getint(void *wl, const char *iovar, int *pval); +extern int wlu_iovar_setint(void *wl, const char *iovar, int val); + +extern int wlu_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr); +extern int wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len); +extern int wlu_var_getbuf_med(void *wl, const char *iovar, void *param, int parmlen, void **bufptr); +extern int wlu_var_setbuf_med(void *wl, const char *iovar, void *param, int param_len); +extern int wlu_var_getbuf_sm(void *wl, const char *iovar, void *param, int parmlen, void **bufptr); +extern int wlu_var_setbuf_sm(void *wl, const char *iovar, void *param, int param_len); + +extern int wl_seq_batch_in_client(bool enable); +extern int wl_seq_start(void *wl, cmd_t *cmd, char **argv); +extern int wl_seq_stop(void *wl, cmd_t *cmd, char **argv); + +static int wlmPhyTypeGet(void); + +static const char * +wlmLastError(void) +{ + static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; + static char errorString[256]; + int bcmerror; + + if (wlu_iovar_getint(irh, "bcmerror", &bcmerror)) + return "Failed to retrieve error"; + + if (bcmerror > 0 || bcmerror < BCME_LAST) { + sprintf(errorString, "Undefined error (%d)", bcmerror); + } else { + sprintf(errorString, "%s (%d)", bcmerrorstrtable[-bcmerror], bcmerror); + } + + return errorString; +} + +int wlmWLMVersionGet(const char **buffer) +{ + *buffer = WLM_VERSION_STR; + return TRUE; +} + +int wlmApiInit(void) +{ + curBand = WLM_BAND_AUTO; + return TRUE; +} + +int wlmApiCleanup(void) +{ + wl_close_rwl(rwl_get_remote_type(), irh); + irh = 0; + return TRUE; +} + +int wlmSelectInterface(WLM_DUT_INTERFACE ifType, char *ifName, + WLM_DUT_SERVER_PORT dutServerPort, WLM_DUT_OS dutOs) +{ + int val; + + /* close previous handle */ + if (irh != NULL) { + wlmApiCleanup(); + } + + switch (ifType) { + case WLM_DUT_LOCAL: + rwl_set_remote_type(NO_REMOTE); + break; + case WLM_DUT_SERIAL: + rwl_set_remote_type(REMOTE_SERIAL); + break; + case WLM_DUT_SOCKET: + rwl_set_remote_type(REMOTE_SOCKET); + break; + case WLM_DUT_WIFI: + rwl_set_remote_type(REMOTE_WIFI); + break; + case WLM_DUT_DONGLE: + rwl_set_remote_type(REMOTE_DONGLE); + break; + default: + /* ERROR! Unknown interface! */ + return FALSE; + } + + if (ifName) { + strncpy(interfaceName, ifName, MAX_INTERFACE_NAME_LENGTH); + interfaceName[MAX_INTERFACE_NAME_LENGTH] = 0; + } + + switch (dutOs) { + case WLM_DUT_OS_LINUX: + wl_os_type_set_rwl(LINUX_OS); + break; + case WLM_DUT_OS_WIN32: + wl_os_type_set_rwl(WIN32_OS); + break; + default: + /* ERROR! Unknown OS! */ + return FALSE; + } + + switch (rwl_get_remote_type()) { + struct ipv4_addr temp; + case REMOTE_SOCKET: + if (!wl_atoip(interfaceName, &temp)) { + printf("wlmSelectInterface: IP address invalid\n"); + return FALSE; + } + rwl_set_server_ip(interfaceName); + rwl_set_server_port(dutServerPort); + rwl_init_socket(); + break; + case REMOTE_SERIAL: + rwl_set_serial_port_name(interfaceName); /* x (port number) or /dev/ttySx */ + if ((irh = rwl_open_pipe(rwl_get_remote_type(), + rwl_get_serial_port_name(), 0, 0)) == NULL) { + printf("wlmSelectInterface: rwl_open_pipe failed\n"); + return FALSE; + } + break; + case REMOTE_DONGLE: + rwl_set_serial_port_name(interfaceName); /* COMx or /dev/ttySx */ + if ((irh = rwl_open_pipe(rwl_get_remote_type(), "\0", 0, 0)) == NULL) { + printf("wlmSelectInterface: rwl_open_pipe failed\n"); + return FALSE; + } + break; + case REMOTE_WIFI: + if (!wl_ether_atoe(interfaceName, + (struct ether_addr *)rwl_get_wifi_mac())) { + printf("wlmSelectInterface: ethernet MAC address invalid\n"); + return FALSE; + } + /* intentionally no break here to pass through to NO_REMOTE case */ + case NO_REMOTE: +#if defined(WIN32) + adapter = atoi(interfaceName); + if (adapter == 0) + adapter = -1; + + if (wl_ir_init_adapter_rwl(&irh, adapter) != 0) { + printf("wlmSelectInterface: Adapter %d init failed\n", adapter); + return FALSE; + } +#else + if (wl_ir_init_rwl(&irh) != 0) { + printf("wlmSelectInterface: initialize failed\n"); + return FALSE; + } +#endif + break; + default: + /* ERROR! Invalid interface! + * NOTE: API should not allow code to come here. + */ + return FALSE; + } + + /* Query the IOCTL API version */ + if (wlu_get(irh, WLC_GET_VERSION, &val, sizeof(int)) < 0) { + printf("wlmSelectInterface: IOCTL Version query failed\n"); + return FALSE; + } + + ioctl_version = dtoh32(val); + if (ioctl_version != WLC_IOCTL_VERSION && + ioctl_version != 1) { + printf("wlmSelectInterface: Version mismatch, please upgrade." + "Got %d, expected %d or 1\n", + ioctl_version, WLC_IOCTL_VERSION); + return FALSE; + } + + + return TRUE; +} + +int wlmVersionGet(char *buf, int len) +{ + if (buf == 0) { + printf("wlmVersionGet: buffer invalid\n"); + return FALSE; + } + + memset(buf, 0, sizeof(buf)); + + /* query for 'ver' to get version info */ + if (wlu_iovar_get(irh, "ver", buf, (len < WLC_IOCTL_SMLEN) ? len : WLC_IOCTL_SMLEN)) { + printf("wlmVersionGet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmEnableAdapterUp(int enable) +{ + /* Enable/disable adapter */ + if (enable) + { + if (wlu_set(irh, WLC_UP, NULL, 0)) { + printf("wlmEnableAdapterUp: %s\n", wlmLastError()); + return FALSE; + } + } + else { + if (wlu_set(irh, WLC_DOWN, NULL, 0)) { + printf("wlmEnableAdapterUp: %s\n", wlmLastError()); + return FALSE; + } + } + + return TRUE; +} + +int wlmIsAdapterUp(int *up) +{ + /* Get 'isup' - check if adapter is up */ + up = dtoh32(up); + if (wlu_get(irh, WLC_GET_UP, up, sizeof(int))) { + printf("wlmIsAdapterUp: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmMinPowerConsumption(int enable) +{ + if (wlu_iovar_setint(irh, "mpc", enable)) { + printf("wlmMinPowerConsumption: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmMimoPreambleGet(int* type) +{ + if (wlu_iovar_getint(irh, "mimo_preamble", type)) { + printf("wlmMimoPreambleGet(): %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmMimoPreambleSet(int type) +{ + if (wlu_iovar_setint(irh, "mimo_preamble", type)) { + printf("wlmMimoPreambleSet(): %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmChannelSet(int channel) +{ + + /* Check band lock first before set channel */ + if ((channel <= 14) && (curBand != WLM_BAND_2G)) { + curBand = WLM_BAND_2G; + } else if ((channel > 14) && (curBand != WLM_BAND_5G)) { + curBand = WLM_BAND_5G; + } + + /* Set 'channel' */ + channel = htod32(channel); + if (wlu_set(irh, WLC_SET_CHANNEL, &channel, sizeof(channel))) { + printf("wlmChannelSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRateSet(WLM_RATE rate) +{ + char aname[] = "a_rate"; + char bgname[] = "bg_rate"; + char *name; + + switch (curBand) { + case WLM_BAND_AUTO : + printf("wlmRateSet: must set channel or band lock first \n"); + return FALSE; + case WLM_BAND_DUAL : + printf("wlmRateSet: must set channel or band lock first\n"); + return FALSE; + case WLM_BAND_5G : + name = (char *)aname; + break; + case WLM_BAND_2G : + name = (char *)bgname; + break; + default : + return FALSE; + } + + rate = htod32(rate); + if (wlu_iovar_setint(irh, name, rate)) { + printf("wlmRateSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmLegacyRateSet(WLM_RATE rate) +{ + uint32 nrate = 0; + + if (ioctl_version == 1) { + nrate |= (rate & OLD_NRATE_RATE_MASK); + nrate |= (OLD_NRATE_STF_SISO << OLD_NRATE_STF_SHIFT) & OLD_NRATE_STF_MASK; + } else { + nrate = WL_RSPEC_ENCODE_RATE; /* 11abg */ + nrate |= (rate & WL_RSPEC_RATE_MASK); + } + + if (wlu_iovar_setint(irh, "nrate", (int)nrate)) { + printf("wlmMcsRateSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmMcsRateSet(WLM_MCS_RATE mcs_rate, WLM_STF_MODE stf_mode) +{ + uint32 nrate = 0; + uint stf; + + if (mcs_rate > 32) { + printf("wlmMcsRateSet: MCS %d out of range\n", mcs_rate); + return FALSE; + } + + if (ioctl_version == 1) { + nrate |= mcs_rate; + nrate |= OLD_NRATE_MCS_INUSE; + + if (!stf_mode) { + stf = 0; + if (mcs_rate <= HIGHEST_SINGLE_STREAM_MCS || + mcs_rate == 32) + stf = OLD_NRATE_STF_SISO; /* SISO */ + else + stf = OLD_NRATE_STF_SDM; /* SDM */ + } else + stf = stf_mode; + + nrate |= (stf << OLD_NRATE_STF_SHIFT) & OLD_NRATE_STF_MASK; + } else { + nrate = WL_RSPEC_ENCODE_HT; /* 11n HT */ + nrate |= mcs_rate; + + /* decode WLM stf value into tx expansion and STBC */ + if (stf_mode == WLM_STF_MODE_CDD) { + nrate |= (1 << WL_RSPEC_TXEXP_SHIFT); + } else if (stf_mode == WLM_STF_MODE_STBC) { + nrate |= WL_RSPEC_STBC; + } + } + + if (wlu_iovar_setint(irh, "nrate", (int)nrate)) { + printf("wlmMcsRateSet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmPreambleSet(WLM_PREAMBLE preamble) +{ + preamble = htod32(preamble); + + if (wlu_set(irh, WLC_SET_PLCPHDR, &preamble, sizeof(preamble))) { + printf("wlmPreambleSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmBandSet(WLM_BAND band) +{ + band = htod32(band); + + if (wlu_set(irh, WLC_SET_BAND, (void *)&band, sizeof(band))) { + printf("wlmBandSet: %s\n", wlmLastError()); + return FALSE; + } + + curBand = band; + + return TRUE; +} + +int wlmGetBandList(WLM_BAND * bands) +{ + unsigned int list[3]; + unsigned int i; + + if (wlu_get(irh, WLC_GET_BANDLIST, list, sizeof(list))) { + printf("wlmGetBandList: %s\n", wlmLastError()); + return FALSE; + } + + list[0] = dtoh32(list[0]); + list[1] = dtoh32(list[1]); + list[2] = dtoh32(list[2]); + + /* list[0] is count, followed by 'count' bands */ + + if (list[0] > 2) + list[0] = 2; + + for (i = 1, *bands = (WLM_BAND)0; i <= list[0]; i++) + *bands |= list[i]; + + return TRUE; +} + +int wlmGmodeSet(WLM_GMODE gmode) +{ + /* Set 'gmode' - select mode in 2.4G band */ + gmode = htod32(gmode); + + if (wlu_set(irh, WLC_SET_GMODE, (void *)&gmode, sizeof(gmode))) { + printf("wlmGmodeSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRxAntSet(int antenna) +{ + /* Set 'antdiv' - select receive antenna */ + antenna = htod32(antenna); + + if (wlu_set(irh, WLC_SET_ANTDIV, &antenna, sizeof(antenna))) { + printf("wlmRxAntSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmTxAntSet(int antenna) +{ + /* Set 'txant' - select transmit antenna */ + antenna = htod32(antenna); + + if (wlu_set(irh, WLC_SET_TXANT, &antenna, sizeof(antenna))) { + printf("wlmTxAntSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmEstimatedPowerGet(int *estPower, int chain) +{ + int mimo; + int is2g; + + size_t pprsize = ppr_ser_size_by_bw(ppr_get_max_bw()); + /* Allocate memory for structure and 2 serialisation buffer */ + tx_pwr_rpt_t *ppr_wl = (tx_pwr_rpt_t *)malloc(sizeof(tx_pwr_rpt_t) + pprsize*2); + uint8 *ppr_ser; + if (ppr_wl == NULL) + return FALSE; + + ppr_ser = ppr_wl->pprdata; + memset(ppr_wl, 0, sizeof(tx_pwr_rpt_t) + pprsize*2); + ppr_wl->board_limit_len = pprsize; + ppr_wl->target_len = pprsize; + ppr_wl->version = TX_POWER_T_VERSION; + /* init allocated mem for serialisation */ + ppr_init_ser_mem_by_bw(ppr_ser, ppr_get_max_bw(), ppr_wl->board_limit_len); + ppr_ser += ppr_wl->board_limit_len; + ppr_init_ser_mem_by_bw(ppr_ser, ppr_get_max_bw(), ppr_wl->target_len); + + + if (wlu_get(irh, WLC_CURRENT_PWR, ppr_wl, sizeof(tx_pwr_rpt_t) + pprsize*2) < 0) { + printf("wlmEstimatedPowerGet: %s\n", wlmLastError()); + free(ppr_wl); + return FALSE; + } + ppr_wl->flags = dtoh32(ppr_wl->flags); + ppr_wl->chanspec = dtohchanspec(ppr_wl->chanspec); + mimo = (ppr_wl->flags & WL_TX_POWER_F_MIMO); + + /* value returned is in units of quarter dBm, need to multiply by 250 to get milli-dBm */ + if (mimo) { + *estPower = ppr_wl->est_Pout[chain] * 250; + } else { + *estPower = ppr_wl->est_Pout[0] * 250; + } + + if (ioctl_version == 1) { + is2g = LCHSPEC_IS2G(ppr_wl->chanspec); + } else { + is2g = CHSPEC_IS2G(ppr_wl->chanspec); + } + + if (!mimo && is2g) { + *estPower = ppr_wl->est_Pout_cck * 250; + } + + free(ppr_wl); + return TRUE; +} + +int wlmTxPowerGet(int *power) +{ + int val; + + if ((wlu_iovar_getint(irh, "qtxpower", &val)) < 0) { + printf("wlmTxPowerGet: %s\n", wlmLastError()); + return FALSE; + } + + val &= ~WL_TXPWR_OVERRIDE; + + /* value returned is in units of quarter dBm, need to multiply by 250 to get milli-dBm */ + *power = val * 250; + return TRUE; +} + +int wlmTxPowerSet(int powerValue) +{ + int newValue = 0; + + if (powerValue == -1) { + newValue = 127; /* Max val of 127 qdbm */ + } else { + /* expected to be in units of quarter dBm */ + newValue = powerValue / 250; + newValue |= WL_TXPWR_OVERRIDE; + } + + if (wlu_iovar_setint(irh, "qtxpower", newValue)) { + printf("wlmTxPowerSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +static int wlmPhyTypeGet(void) +{ + + int phytype = PHY_TYPE_NULL; + + if (wlu_get(irh, WLC_GET_PHYTYPE, &phytype, sizeof(int)) < 0) { + printf("wlmPhyTypeGet: %s\n", wlmLastError()); + return FALSE; + } + + return phytype; +} + +int wlmPaParametersGet(WLM_BANDRANGE bandrange, + unsigned int *a1, unsigned int *b0, unsigned int *b1) +{ + uint16 inpa[WL_PHY_PAVARS_LEN]; + void *ptr = NULL; + uint16 *outpa; + int i = 0; + int phytype = PHY_TYPE_NULL; + + *a1 = 0; + *b0 = 0; + *b1 = 0; + + /* Do not rely on user to have knowledge of phytype */ + phytype = wlmPhyTypeGet(); + if (phytype != PHY_TYPE_NULL) { + inpa[i++] = phytype; + inpa[i++] = bandrange; + inpa[i++] = 0; /* Fix me: default with chain 0 for all SISO system */ + } else { + printf("wlmPaParametersGet: unknow Phy type\n"); + return FALSE; + } + + if (wlu_var_getbuf_sm(irh, "pavars", inpa, WL_PHY_PAVARS_LEN * sizeof(uint16), &ptr)) { + printf("wlmPaParametersGet: %s\n", wlmLastError()); + return FALSE; + } + + outpa = (uint16 *)ptr; + *b0 = outpa[i++]; + *b1 = outpa[i++]; + *a1 = outpa[i++]; + + return TRUE; +} + +int wlmPaParametersSet(WLM_BANDRANGE bandrange, + unsigned int a1, unsigned int b0, unsigned int b1) +{ + uint16 inpa[WL_PHY_PAVARS_LEN]; + int i = 0; + int phytype = PHY_TYPE_NULL; + + /* Do not rely on user to have knowledge of phy type */ + phytype = wlmPhyTypeGet(); + if (phytype != PHY_TYPE_NULL) { + inpa[i++] = phytype; + inpa[i++] = bandrange; + inpa[i++] = 0; /* Fix me: default with chain 0 for all SISO system */ + } else { + printf("wlmPaParametersSet: unknow Phy type\n"); + return FALSE; + } + + inpa[i++] = b0; + inpa[i++] = b1; + inpa[i++] = a1; + + if (wlu_var_setbuf_sm(irh, "pavars", inpa, WL_PHY_PAVARS_LEN * sizeof(uint16))) { + printf("wlmPaParametersSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + + +int wlmMIMOPaParametersGet(WLM_BANDRANGE bandrange, int chain, + unsigned int *a1, unsigned int *b0, unsigned int *b1) +{ + uint16 inpa[WL_PHY_PAVARS_LEN]; + void *ptr = NULL; + uint16 *outpa; + int i = 0; + int phytype = PHY_TYPE_NULL; + + /* Do not rely on user to have knowledge of phytype */ + phytype = wlmPhyTypeGet(); + if (phytype != PHY_TYPE_NULL) { + inpa[i++] = phytype; + inpa[i++] = bandrange; + inpa[i++] = chain; + } else { + printf("wlmMIMOPaParametersGet: unknow Phy type\n"); + return FALSE; + } + + if (wlu_var_getbuf_sm(irh, "pavars", inpa, WL_PHY_PAVARS_LEN * sizeof(uint16), &ptr)) { + printf("wlmMIMOPaParametersGet: %s\n", wlmLastError()); + return FALSE; + } + + outpa = (uint16 *)ptr; + *a1 = outpa[i++]; + *b0 = outpa[i++]; + *b1 = outpa[i++]; + + return TRUE; +} + +int wlmMIMOPaParametersSet(WLM_BANDRANGE bandrange, int chain, + unsigned int a1, unsigned int b0, unsigned int b1) +{ + uint16 inpa[WL_PHY_PAVARS_LEN]; + int i = 0; + int phytype = PHY_TYPE_NULL; + + /* Do not rely on user to have knowledge of phy type */ + phytype = wlmPhyTypeGet(); + if (phytype != PHY_TYPE_NULL) { + inpa[i++] = phytype; + inpa[i++] = bandrange; + inpa[i++] = chain; + } else { + printf("wlmMIMOPaParametersSet: unknow Phy type\n"); + return FALSE; + } + + inpa[i++] = a1; + inpa[i++] = b0; + inpa[i++] = b1; + + if (wlu_var_setbuf_sm(irh, "pavars", inpa, WL_PHY_PAVARS_LEN * sizeof(uint16))) { + printf("wlmMIMOPaParametersSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmMacAddrGet(char *macAddr, int length) +{ + struct ether_addr ea = {{0, 0, 0, 0, 0, 0}}; + + /* query for 'cur_etheraddr' to get MAC address */ + if (wlu_iovar_get(irh, "cur_etheraddr", &ea, ETHER_ADDR_LEN) < 0) { + printf("wlmMacAddrGet: %s\n", wlmLastError()); + return FALSE; + } + + strncpy(macAddr, wl_ether_etoa(&ea), length); + + return TRUE; +} + +int wlmMacAddrSet(const char* macAddr) +{ + struct ether_addr ea; + + if (!wl_ether_atoe(macAddr, &ea)) { + printf("wlmMacAddrSet: MAC address invalid: %s\n", macAddr); + return FALSE; + } + + /* Set 'cur_etheraddr' to set MAC address */ + if (wlu_iovar_set(irh, "cur_etheraddr", (void *)&ea, ETHER_ADDR_LEN)) { + printf("wlmMacAddrSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmEnableCarrierTone(int enable, int channel) +{ + int val = channel; + + if (!enable) { + val = 0; + } + else { + wlmEnableAdapterUp(1); + if (wlu_set(irh, WLC_OUT, NULL, 0) < 0) { + printf("wlmEnableCarrierTone: %s\n", wlmLastError()); + return FALSE; + } + } + val = htod32(val); + if (wlu_set(irh, WLC_FREQ_ACCURACY, &val, sizeof(int)) < 0) { + printf("wlmEnableCarrierTone: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmEnableEVMTest(int enable, WLM_RATE rate, int channel) +{ + int val[3] = {0}; + val[1] = WLM_RATE_1M; /* default value */ + if (enable) { + val[0] = htod32(channel); + val[1] = htod32(rate); + wlmEnableAdapterUp(1); + if (wlu_set(irh, WLC_OUT, NULL, 0) < 0) { + printf("wlmEnableEVMTest: %s\n", wlmLastError()); + return FALSE; + } + } + if (wlu_set(irh, WLC_EVM, val, sizeof(val)) < 0) { + printf("wlmEnableEVMTest: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmTxPacketStart(unsigned int interPacketDelay, + unsigned int numPackets, unsigned int packetLength, + const char* destMac, int withAck, int syncMode) +{ + wl_pkteng_t pkteng; + + if (!wl_ether_atoe(destMac, (struct ether_addr *)&pkteng.dest)) { + printf("wlmTxPacketStart: destMac invalid\n"); + return FALSE; + } + + pkteng.flags = withAck ? WL_PKTENG_PER_TX_WITH_ACK_START : WL_PKTENG_PER_TX_START; + + if (syncMode) + pkteng.flags |= WL_PKTENG_SYNCHRONOUS; + else + pkteng.flags &= ~WL_PKTENG_SYNCHRONOUS; + + pkteng.delay = interPacketDelay; + pkteng.length = packetLength; + pkteng.nframes = numPackets; + + pkteng.seqno = 0; /* not used */ + pkteng.src = ether_null; /* implies current ether addr */ + + if (wlu_var_setbuf(irh, "pkteng", &pkteng, sizeof(pkteng))) { + printf("wlmTxPacketStart: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmTxPacketStop(void) +{ + wl_pkteng_t pkteng; + + memset(&pkteng, 0, sizeof(pkteng)); + pkteng.flags = WL_PKTENG_PER_TX_STOP; + + if (wlu_var_setbuf(irh, "pkteng", &pkteng, sizeof(pkteng)) < 0) { + printf("wlmTxPacketStop: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRxPacketStart(const char* srcMac, int withAck, + int syncMode, unsigned int numPackets, unsigned int timeout) +{ + wl_pkteng_t pkteng; + + if (!wl_ether_atoe(srcMac, (struct ether_addr *)&pkteng.dest)) { + printf("wlmRxPacketStart: srcMac invalid\n"); + return FALSE; + } + + pkteng.flags = withAck ? WL_PKTENG_PER_RX_WITH_ACK_START : WL_PKTENG_PER_RX_START; + + if (syncMode) { + pkteng.flags |= WL_PKTENG_SYNCHRONOUS; + pkteng.nframes = numPackets; + pkteng.delay = timeout; + } + else { + pkteng.flags &= ~WL_PKTENG_SYNCHRONOUS; + pkteng.length = 0; + } + + if (wlu_var_setbuf(irh, "pkteng", &pkteng, sizeof(pkteng))) { + printf("wlmRxPacketStart: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRxPacketStop(void) +{ + wl_pkteng_t pkteng; + + memset(&pkteng, 0, sizeof(pkteng)); + pkteng.flags = WL_PKTENG_PER_RX_STOP; + + if (wlu_var_setbuf(irh, "pkteng", &pkteng, sizeof(pkteng)) < 0) { + printf("wlmRxPacketStop: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmTxGetAckedPackets(unsigned int *count) +{ + wl_cnt_t *cnt; + + if (wlu_var_getbuf(irh, "counters", NULL, 0, (void **)&cnt)) { + printf("wlmTxGetAckedPackets: %s\n", wlmLastError()); + return FALSE; + } + + *count = dtoh32(cnt->rxackucast); + + return TRUE; +} + +int wlmRxGetReceivedPackets(unsigned int *count) +{ + wl_cnt_t *cnt; + + if (wlu_var_getbuf_med(irh, "counters", NULL, 0, (void **)&cnt)) { + printf("wlmRxGetReceivedPackets: %s\n", wlmLastError()); + return FALSE; + } + + cnt->version = dtoh16(cnt->version); + cnt->length = dtoh16(cnt->version); + + /* current wl_cnt_t version is 7 */ + if (cnt->version == WL_CNT_T_VERSION) { + *count = dtoh32(cnt->pktengrxducast); + } else { + *count = dtoh32(cnt->rxdfrmucastmbss); + } + + return TRUE; +} + +int wlmRssiGet(int *rssi) +{ + wl_pkteng_stats_t *cnt; + + if (wlu_var_getbuf(irh, "pkteng_stats", NULL, 0, (void **)&cnt)) { + printf("wlmRssiGet: %s\n", wlmLastError()); + return FALSE; + } + + *rssi = dtoh32(cnt->rssi); + + return TRUE; +} + + + +int wlmSequenceStart(int clientBatching) +{ + if (wl_seq_batch_in_client((bool)clientBatching)) { + printf("wlmSequenceStart: %s\n", wlmLastError()); + return FALSE; + } + + if (wl_seq_start(irh, 0, 0)) { + printf("wlmSequenceStart: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmSequenceStop(void) +{ + if (wl_seq_stop(irh, 0, 0)) { + printf("wlmSequenceStop: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmSequenceDelay(int msec) +{ + if (wlu_iovar_setint(irh, "seq_delay", msec)) { + printf("wlmSequenceDelay: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmSequenceErrorIndex(int *index) +{ + if (wlu_iovar_getint(irh, "seq_error_index", index)) { + printf("wlmSequenceErrorIndex: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmDeviceImageWrite(const char* byteStream, int length, WLM_IMAGE_TYPE imageType) +{ + srom_rw_t *srt; + char buffer[WLC_IOCTL_MAXLEN] = {0}; + + char *bufp; + char *cisp, *cisdata; + cis_rw_t cish; + + if (byteStream == NULL) { + printf("wlmDeviceImageWrite: Buffer is invalid!\n"); + return FALSE; + } + if (length > SROM_MAX+1) { + printf("wlmDeviceImageWrite: Data length should be less than %d bytes\n", SROM_MAX); + return FALSE; + } + + switch (imageType) { + case WLM_TYPE_SROM: + srt = (srom_rw_t *)buffer; + memcpy(srt->buf, byteStream, length); + + if (length == SROM4_WORDS * 2) { + if ((srt->buf[SROM4_SIGN] != SROM4_SIGNATURE) && + (srt->buf[SROM8_SIGN] != SROM4_SIGNATURE)) { + printf("wlmDeviceImageWrite: Data lacks a REV4 signature!\n"); + return FALSE; + } + } else if ((length != SROM_WORDS * 2) && (length != SROM_MAX)) { + printf("wlmDeviceImageWrite: Data length is invalid!\n"); + return FALSE; + } + + srt->nbytes = length; + if (wlu_set(irh, WLC_SET_SROM, buffer, length + 8)) { + printf("wlmDeviceImageWrite: %s\n", wlmLastError()); + return FALSE; + } + + + break; + case WLM_TYPE_OTP: + bufp = buffer; + strcpy(bufp, "ciswrite"); + bufp += strlen("ciswrite") + 1; + cisp = bufp; + cisdata = cisp + sizeof(cish); + cish.source = htod32(0); + memcpy(cisdata, byteStream, length); + + cish.byteoff = htod32(0); + cish.nbytes = htod32(length); + memcpy(cisp, (char*)&cish, sizeof(cish)); + + if (wl_set(irh, WLC_SET_VAR, buffer, (cisp - buffer) + sizeof(cish) + length) < 0) { + printf("wlmDeviceImageWrite: %s\n", wlmLastError()); + return FALSE; + } + break; + case WLM_TYPE_AUTO: + if (!wlmDeviceImageWrite(byteStream, length, WLM_TYPE_SROM) && + !wlmDeviceImageWrite(byteStream, length, WLM_TYPE_OTP)) { + printf("wlmDeviceImageWrite: %s\n", wlmLastError()); + return FALSE; + } + break; + default: + printf("wlmDeviceImageWrite: Invalid image type!\n"); + return FALSE; + } + return TRUE; +} + +int wlmDeviceImageRead(char* byteStream, unsigned int len, WLM_IMAGE_TYPE imageType) +{ + srom_rw_t *srt; + cis_rw_t *cish; + char buf[WLC_IOCTL_MAXLEN] = {0}; + unsigned int numRead = 0; + + if (byteStream == NULL) { + printf("wlmDeviceImageRead: Buffer is invalid!\n"); + return FALSE; + } + + if (len > SROM_MAX) { + printf("wlmDeviceImageRead: byteStream should be less than %d bytes!\n", SROM_MAX); + return FALSE; + } + + if (len & 1) { + printf("wlmDeviceImageRead: Invalid byte count %d, must be even\n", len); + return FALSE; + } + + switch (imageType) { + case WLM_TYPE_SROM: + if (len < 2*SROM4_WORDS) { + printf("wlmDeviceImageRead: Buffer not large enough!\n"); + return FALSE; + } + + srt = (srom_rw_t *)buf; + srt->byteoff = 0; + srt->nbytes = htod32(2 * SROM4_WORDS); + /* strlen("cisdump ") = 9 */ + if (wlu_get(irh, WLC_GET_SROM, buf, 9 + (len < SROM_MAX ? len : SROM_MAX)) < 0) { + printf("wlmDeviceImageRead: %s\n", wlmLastError()); + return FALSE; + } + memcpy(byteStream, buf + 8, srt->nbytes); + numRead = srt->nbytes; + break; + case WLM_TYPE_OTP: + strcpy(buf, "cisdump"); + /* strlen("cisdump ") = 9 */ + if (wl_get(irh, WLC_GET_VAR, buf, 9 + (len < SROM_MAX ? len : SROM_MAX)) < 0) { + printf("wlmDeviceImageRead: %s\n", wlmLastError()); + return FALSE; + } + + cish = (cis_rw_t *)buf; + cish->source = dtoh32(cish->source); + cish->byteoff = dtoh32(cish->byteoff); + cish->nbytes = dtoh32(cish->nbytes); + + if (len < cish->nbytes) { + printf("wlmDeviceImageRead: Buffer not large enough!\n"); + return FALSE; + } + memcpy(byteStream, buf + sizeof(cis_rw_t), cish->nbytes); + numRead = cish->nbytes; + break; + case WLM_TYPE_AUTO: + numRead = wlmDeviceImageRead(byteStream, len, WLM_TYPE_SROM); + if (!numRead) { + numRead = wlmDeviceImageRead(byteStream, len, WLM_TYPE_OTP); + printf("wlmDeviceImageRead: %s\n", wlmLastError()); + return FALSE; + } + break; + default: + printf("wlmDeviceImageRead: Invalid image type!\n"); + return FALSE; + } + return numRead; +} + +int wlmSecuritySet(WLM_AUTH_TYPE authType, WLM_AUTH_MODE authMode, + WLM_ENCRYPTION encryption, const char *key) +{ + int length = 0; + int wpa_auth; + int sup_wpa; + int primary_key = 0; + wl_wsec_key_t wepKey[4]; + wsec_pmk_t psk; + int wsec; + + if (encryption != WLM_ENCRYPT_NONE && key == 0) { + printf("wlmSecuritySet: invalid key\n"); + return FALSE; + } + + if (key) { + length = strlen(key); + } + + switch (encryption) { + + case WLM_ENCRYPT_NONE: + wpa_auth = WPA_AUTH_DISABLED; + sup_wpa = 0; + break; + + case WLM_ENCRYPT_WEP: { + int i; + int len = length / 4; + + wpa_auth = WPA_AUTH_DISABLED; + sup_wpa = 0; + + if (!(length == 40 || length == 104 || length == 128 || length == 256)) { + printf("wlmSecuritySet: invalid WEP key length %d" + " - expect 40, 104, 128, or 256" + " (i.e. 10, 26, 32, or 64 for each of 4 keys)\n", length); + return FALSE; + } + + /* convert hex key string to 4 binary keys */ + for (i = 0; i < 4; i++) { + wl_wsec_key_t *k = &wepKey[i]; + const char *data = &key[i * len]; + unsigned int j; + + memset(k, 0, sizeof(*k)); + k->index = i; + k->len = len / 2; + + for (j = 0; j < k->len; j++) { + char hex[] = "XX"; + char *end = NULL; + strncpy(hex, &data[j * 2], 2); + k->data[j] = (char)strtoul(hex, &end, 16); + if (*end != 0) { + printf("wlmSecuritySet: invalid WEP key" + " - expect hex values\n"); + return FALSE; + } + } + + switch (k->len) { + case 5: + k->algo = CRYPTO_ALGO_WEP1; + break; + case 13: + k->algo = CRYPTO_ALGO_WEP128; + break; + case 16: + k->algo = CRYPTO_ALGO_AES_CCM; + break; + case 32: + k->algo = CRYPTO_ALGO_TKIP; + break; + default: + /* invalid */ + return FALSE; + } + + k->flags |= WL_PRIMARY_KEY; + } + + break; + } + + case WLM_ENCRYPT_TKIP: + case WLM_ENCRYPT_AES: { + + if (authMode != WLM_WPA_AUTH_PSK && authMode != WLM_WPA2_AUTH_PSK) { + printf("wlmSecuritySet: authentication mode must be WPA PSK or WPA2 PSK\n"); + return FALSE; + } + + wpa_auth = authMode; + sup_wpa = 1; + + if (length < WSEC_MIN_PSK_LEN || length > WSEC_MAX_PSK_LEN) { + printf("wlmSecuritySet: passphrase must be between %d and %d characters\n", + WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN); + return FALSE; + } + + psk.key_len = length; + psk.flags = WSEC_PASSPHRASE; + memcpy(psk.key, key, length); + + break; + } + + case WLM_ENCRYPT_WSEC: + case WLM_ENCRYPT_FIPS: + default: + printf("wlmSecuritySet: encryption not supported\n"); + return FALSE; + } + + if (wlu_iovar_setint(irh, "auth", authType)) { + printf("wlmSecuritySet: %s\n", wlmLastError()); + return FALSE; + } + + if (wlu_iovar_setint(irh, "wpa_auth", wpa_auth)) { + printf("wlmSecuritySet: %s\n", wlmLastError()); + return FALSE; + } + + if (wlu_iovar_setint(irh, "sup_wpa", sup_wpa)) { + printf("wlmSecuritySet: %s\n", wlmLastError()); + return FALSE; + } + + if (encryption == WLM_ENCRYPT_WEP) { + int i; + for (i = 0; i < 4; i++) { + wl_wsec_key_t *k = &wepKey[i]; + k->index = htod32(k->index); + k->len = htod32(k->len); + k->algo = htod32(k->algo); + k->flags = htod32(k->flags); + + if (wlu_set(irh, WLC_SET_KEY, k, sizeof(*k))) { + printf("wlmSecuritySet: %s\n", wlmLastError()); + return FALSE; + } + } + + primary_key = htod32(primary_key); + if (wlu_set(irh, WLC_SET_KEY_PRIMARY, &primary_key, sizeof(primary_key)) < 0) { + printf("wlmSecuritySet: %s\n", wlmLastError()); + return FALSE; + } + } + else if (encryption == WLM_ENCRYPT_TKIP || encryption == WLM_ENCRYPT_AES) { + psk.key_len = htod16(psk.key_len); + psk.flags = htod16(psk.flags); + + if (wlu_set(irh, WLC_SET_WSEC_PMK, &psk, sizeof(psk))) { + printf("wlmSecuritySet: %s\n", wlmLastError()); + return FALSE; + } + } + + wsec = htod32(encryption); + if (wlu_set(irh, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0) { + printf("wlmSecuritySet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmJoinNetwork(const char* ssid, WLM_JOIN_MODE mode) +{ + wlc_ssid_t wlcSsid; + int infra = htod32(mode); + if (wlu_set(irh, WLC_SET_INFRA, &infra, sizeof(int)) < 0) { + printf("wlmJoinNetwork: %s\n", wlmLastError()); + return FALSE; + } + + wlcSsid.SSID_len = htod32(strlen(ssid)); + memcpy(wlcSsid.SSID, ssid, wlcSsid.SSID_len); + + if (wlu_set(irh, WLC_SET_SSID, &wlcSsid, sizeof(wlc_ssid_t)) < 0) { + printf("wlmJoinNetwork: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmDisassociateNetwork(void) +{ + if (wlu_set(irh, WLC_DISASSOC, NULL, 0) < 0) { + printf("wlmDisassociateNetwork: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmSsidGet(char *ssid, int length) +{ + wlc_ssid_t wlc_ssid; + + if (length < SSID_FMT_BUF_LEN) { + printf("wlmSsidGet: Ssid buffer too short - %d bytes at least\n", + SSID_FMT_BUF_LEN); + return FALSE; + } + + /* query for 'ssid' */ + if (wlu_get(irh, WLC_GET_SSID, &wlc_ssid, sizeof(wlc_ssid_t))) { + printf("wlmSsidGet: %s\n", wlmLastError()); + return FALSE; + } + + wl_format_ssid(ssid, wlc_ssid.SSID, dtoh32(wlc_ssid.SSID_len)); + + return TRUE; +} + +int wlmBssidGet(char *bssid, int length) +{ + struct ether_addr ea; + + if (length != ETHER_ADDR_LEN) { + printf("wlmBssiGet: bssid requires %d bytes", ETHER_ADDR_LEN); + return FALSE; + } + + if (wlu_get(irh, WLC_GET_BSSID, &ea, ETHER_ADDR_LEN) == 0) { + /* associated - format and return bssid */ + strncpy(bssid, wl_ether_etoa(&ea), length); + } + else { + /* not associated - return empty string */ + memset(bssid, 0, length); + } + + return TRUE; +} + + +int wlmGlacialTimerSet(int val) +{ + if (wlu_iovar_setint(irh, "glacial_timer", val)) { + printf("wlmGlacialTimerSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmFastTimerSet(int val) +{ + if (wlu_iovar_setint(irh, "fast_timer", val)) { + printf("wlmFastTimerSet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmSlowTimerSet(int val) +{ + if (wlu_iovar_setint(irh, "slow_timer", val)) { + printf("wlmGlacialTimerSet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + + +int wlmScanSuppress(int on) +{ + int val; + if (on) + val = 1; + else + val = 0; + + if (wlu_set(irh, WLC_SET_SCANSUPPRESS, &val, sizeof(int))) { + printf("wlmSetScansuppress: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmCountryCodeSet(const char * country_name) +{ + wl_country_t cspec; + int err; + + memset(&cspec, 0, sizeof(cspec)); + cspec.rev = -1; + + /* arg matched a country name */ + memcpy(cspec.country_abbrev, country_name, WLC_CNTRY_BUF_SZ); + err = 0; + + /* first try the country iovar */ + if (cspec.rev == -1 && cspec.ccode[0] == '\0') + err = wlu_iovar_set(irh, "country", &cspec, WLC_CNTRY_BUF_SZ); + else + err = wlu_iovar_set(irh, "country", &cspec, sizeof(cspec)); + + if (err == 0) + return TRUE; + return FALSE; +} + +int wlmFullCal(void) +{ + if (wlu_var_setbuf(irh, "lpphy_fullcal", NULL, 0)) { + printf("wlmLPPY_FULLCAL: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmIoctlGet(int cmd, void *buf, int len) +{ + if (wlu_get(irh, cmd, buf, len)) { + printf("wlmIoctlGet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmIoctlSet(int cmd, void *buf, int len) +{ + if (wlu_set(irh, cmd, buf, len)) { + printf("wlmIoctlSet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmIovarGet(const char *iovar, void *buf, int len) +{ + if (wlu_iovar_get(irh, iovar, buf, len)) { + printf("wlmIovarGet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmIovarSet(const char *iovar, void *buf, int len) +{ + if (wlu_iovar_set(irh, iovar, buf, len)) { + printf("wlmIovarSet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmIovarIntegerGet(const char *iovar, int *val) +{ + if (wlu_iovar_getint(irh, iovar, val)) { + printf("wlmIovarIntegerGet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmIovarIntegerSet(const char *iovar, int val) +{ + if (wlu_iovar_setint(irh, iovar, val)) { + printf("wlmIovarIntegerSet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmIovarBufferGet(const char *iovar, void *param, int param_len, void **bufptr) +{ + if (wlu_var_getbuf(irh, iovar, param, param_len, bufptr)) { + printf("wlmIovarBufferGet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmIovarBufferSet(const char *iovar, void *param, int param_len) +{ + if (wlu_var_setbuf(irh, iovar, param, param_len)) { + printf("wlmIovarBufferSet: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmCga5gOffsetsSet(char* values, int len) +{ + if (len != CGA_5G_OFFSETS_LEN) { + printf("wlmCga5gOffsetsSet() requires a %d-value array as a parameter\n", + CGA_5G_OFFSETS_LEN); + return FALSE; + } + + if ((wlu_var_setbuf(irh, "sslpnphy_cga_5g", values, + CGA_5G_OFFSETS_LEN * sizeof(int8))) < 0) { + printf("wlmCga5gOffsetsSet(): Error setting offset values (%s)\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmCga5gOffsetsGet(char* buf, int len) +{ + if (len != CGA_5G_OFFSETS_LEN) { + printf("wlmCga5gOffsetsGet() requires a %d-value array as a parameter\n", + CGA_5G_OFFSETS_LEN); + return FALSE; + } + + if ((wlu_iovar_get(irh, "sslpnphy_cga_5g", buf, CGA_5G_OFFSETS_LEN * sizeof(int8))) < 0) { + printf("wlmCga5gOffsetsGet(): Error setting offset values (%s)\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmCga2gOffsetsSet(char* values, int len) +{ + if (len != CGA_2G_OFFSETS_LEN) { + printf("wlmCga2gOffsetsSet(): requires a %d-value array as a parameter\n", + CGA_2G_OFFSETS_LEN); + return FALSE; + } + + if ((wlu_var_setbuf(irh, "sslpnphy_cga_2g", values, + CGA_2G_OFFSETS_LEN * sizeof(int8))) < 0) { + printf("wlmCga2gOffsetsSet(): Error setting offset values (%s)\n", wlmLastError()); + return FALSE; + } + + return TRUE; + +} + +int wlmCga2gOffsetsGet(char* buf, int len) +{ + if (len != CGA_2G_OFFSETS_LEN) { + printf("wlmCga2gOffsetsGet(): requires a %d-value array as a parameter\n", + CGA_2G_OFFSETS_LEN); + return FALSE; + } + + if ((wlu_iovar_get(irh, "sslpnphy_cga_2g", buf, CGA_2G_OFFSETS_LEN * sizeof(int8))) < 0) { + printf("wlmCga2gOffsetsGet(): Error setting offset values (%s)\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + + +int wlmRadioOn(void) +{ + int val; + + /* val = WL_RADIO_SW_DISABLE << 16; */ + val = (1<<0) << 16; + + if (wlu_set(irh, WLC_SET_RADIO, &val, sizeof(int)) < 0) { + printf("wlmRadioOn: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRadioOff(void) +{ + int val; + + /* val = WL_RADIO_SW_DISABLE << 16 | WL_RADIO_SW_DISABLE; */ + val = (1<<0) << 16 | (1<<0); + + if (wlu_set(irh, WLC_SET_RADIO, &val, sizeof(int)) < 0) { + printf("wlmRadioOff: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmPMmode(int val) +{ + if (val < 0 || val > 2) { + printf("wlmPMmode: setting for PM mode out of range [0,2].\n"); + /* 0: CAM constant awake mode */ + /* 1: PS (Power save) mode */ + /* 2: Fast PS mode */ + } + + if (wlu_set(irh, WLC_SET_PM, &val, sizeof(int)) < 0) { + printf("wlmPMmode: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRoamingOn(void) +{ + if (wlu_iovar_setint(irh, "roam_off", 0) < 0) { + printf("wlmRoamingOn: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRoamingOff(void) +{ + if (wlu_iovar_setint(irh, "roam_off", 1) < 0) { + printf("wlmRoamingOff: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRoamTriggerLevelGet(int *val, WLM_BAND band) +{ + struct { + int val; + int band; + } x; + + x.band = htod32(band); + x.val = -1; + + if (wlu_get(irh, WLC_GET_ROAM_TRIGGER, &x, sizeof(x)) < 0) { + printf("wlmRoamTriggerLevelGet: %s\n", wlmLastError()); + return FALSE; + } + + *val = htod32(x.val); + + return TRUE; +} + +int wlmRoamTriggerLevelSet(int val, WLM_BAND band) +{ + struct { + int val; + int band; + } x; + + x.band = htod32(band); + x.val = htod32(val); + + if (wlu_set(irh, WLC_SET_ROAM_TRIGGER, &x, sizeof(x)) < 0) { + printf("wlmRoamTriggerLevelSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmFrameBurstOn(void) +{ + int val = 1; + + if (wlu_set(irh, WLC_SET_FAKEFRAG, &val, sizeof(int)) < 0) { + printf("wlmFrameBurstOn: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmFrameBurstOff(void) +{ + int val = 0; + + if (wlu_set(irh, WLC_SET_FAKEFRAG, &val, sizeof(int)) < 0) { + printf("wlmFrameBurstOff: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + + +int wlmBeaconIntervalSet(int val) +{ + val = htod32(val); + if (wlu_set(irh, WLC_SET_BCNPRD, &val, sizeof(int)) < 0) { + printf("wlmBeaconIntervalSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmAMPDUModeSet(int val) +{ + val = htod32(val); + if (wlu_iovar_setint(irh, "ampdu", val) < 0) { + printf("wlmAMPDUModeSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmMIMOBandwidthCapabilitySet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "mimo_bw_cap", val) < 0) { + printf("wlmMIMOBandwidthCapabilitySet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmInterferenceSet(int val) +{ + val = htod32(val); + + if (val < 0 || val > 4) { + printf("wlmInterferenceSet: interference setting out of range [0, 4]\n"); + return FALSE; + } + + if (wlu_set(irh, WLC_SET_INTERFERENCE_MODE, &val, sizeof(int)) < 0) { + printf("wlmInterferenceSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmInterferenceOverrideSet(int val) +{ + val = htod32(val); + + if (val < 0 || val > 4) { + printf("wlmInterferenceOverrideSet: interference setting out of range [0, 4]\n"); + return FALSE; + } + + if (wlu_set(irh, WLC_SET_INTERFERENCE_OVERRIDE_MODE, &val, sizeof(int)) < 0) { + printf("wlmInterferenceOverrideSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmTransmitBandwidthSet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "mimo_txbw", val) < 0) { + printf("wlmTransmitBadnwidthSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmShortGuardIntervalSet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "sgi_tx", val) < 0) { + printf("wlmShortGuardIntervalSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmObssCoexSet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "obss_coex", val) < 0) { + printf("wlmObssCoexSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmPHYPeriodicalCalSet(void) +{ + if (wlu_iovar_setint(irh, "phy_percal", 0) < 0) { + printf("wlmPHYPeriodicalCalSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmPHYForceCalSet(void) +{ + if (wlu_iovar_setint(irh, "phy_forcecal", 0) < 0) { + printf("wlmPHYForceCalSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmPHYScramblerUpdateDisable(void) +{ + if (wlu_iovar_setint(irh, "phy_scraminit", 0x7f) < 0) { + printf("wlmPHYScramblerUpdateDisable: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmPHYScramblerUpdateEnable(void) +{ + if (wlu_iovar_setint(irh, "phy_scraminit", -1) < 0) { + printf("wlmPHYScramblerUpdateEnable: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmPHYWatchdogSet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "phy_watchdog", val) < 0) { + printf("wlmPHYWatchdogSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmTemperatureSensorDisable(void) +{ + int val = 1; /* 0 = temp sensor enabled; 1 = temp sensor disabled */ + if (wlu_iovar_setint(irh, "tempsense_disable", val) < 0) { + printf("wlmTempSensorDisable %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmTemperatureSensorEnable(void) +{ + int val = 0; /* 0 = temp sensor enabled; 1 = temp sensor disabled */ + if (wlu_iovar_setint(irh, "tempsense_disable", val) < 0) { + printf("wlmTempSensorEnable %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmTransmitCoreSet(int val) +{ val = htod32(val); + + if (wlu_iovar_setint(irh, "txcore", val) < 0) { + printf("wlmTransmitCoreSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmPhyTempSenseGet(int *val) +{ + if (wlu_iovar_getint(irh, "phy_tempsense", val) < 0) { + printf("wlmPhyTempSense: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmOtpFabidGet(int *val) +{ + if (wlu_iovar_getint(irh, "otp_fabid", val)) { + printf("wlmOtpFabid: %s\n", wlmLastError()); + return FALSE; + } + return TRUE; +} + +int wlmChannelSpecSet(int channel, int bandwidth, int sideband) +{ + chanspec_t chanspec = 0; + + if (channel > 224) { + printf("wlmChannelSpecSet: %d is invalid channel\n", channel); + return FALSE; + } else + chanspec |= channel; + + if ((bandwidth != 20) && (bandwidth != 40)) { + printf("wlChannelSpecSet: %d is invalid channel bandwidth.\n", bandwidth); + return FALSE; + } + + if ((sideband != -1) && (sideband != 1) && (sideband != 0)) { + printf("wlmChannelSpecSet: %d is invalid channel sideband.\n", sideband); + return FALSE; + } + + if (ioctl_version == 1) { + if (channel > 14) + chanspec |= WL_LCHANSPEC_BAND_5G; + else + chanspec |= WL_LCHANSPEC_BAND_2G; + + if (bandwidth == 20) + chanspec |= WL_LCHANSPEC_BW_20; + else + chanspec |= WL_LCHANSPEC_BW_40; + + if (sideband == -1) + chanspec |= WL_LCHANSPEC_CTL_SB_LOWER; + else if (sideband == 1) + chanspec |= WL_LCHANSPEC_CTL_SB_UPPER; + else + chanspec |= WL_LCHANSPEC_CTL_SB_NONE; + } else { + if (channel > 14) + chanspec |= WL_CHANSPEC_BAND_5G; + else + chanspec |= WL_CHANSPEC_BAND_2G; + + if (bandwidth == 20) + chanspec |= WL_CHANSPEC_BW_20; + else + chanspec |= WL_CHANSPEC_BW_40; + + if (sideband == -1) + chanspec |= WL_CHANSPEC_CTL_SB_LOWER; + else if (sideband == 1) + chanspec |= WL_CHANSPEC_CTL_SB_UPPER; + } + + if (wlu_iovar_setint(irh, "chanspec", (int) chanspec) < 0) { + printf("wlmChannelSpecSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRtsThresholdOverride(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "rtsthresh", val) < 0) { + printf("wlmRtsThresholdOverride: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + + +int wlmSTBCTxSet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "stbc_tx", val) < 0) { + printf("wlmSTBCTxSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + + +int wlmSTBCRxSet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "stbc_rx", val) < 0) { + printf("wlmSTBCRxSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + + +int wlmTxChainSet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "txchain", val) < 0) { + printf("wlmTxChainSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRxChainSet(int val) +{ + val = htod32(val); + + if (wlu_iovar_setint(irh, "rxchain", val) < 0) { + printf("wlmRxChainSet: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +} + +int wlmRxIQEstGet(float *val, int sampleCount, int ant) +{ + uint32 rxiq; + int sample_count = sampleCount; /* [0, 16], default: maximum 15 sample counts */ + int antenna = ant ; /* [0, 3], default: antenna 0 */ + int err; + uint8 resolution = 1; /* resolution default to 0.25dB */ + float x, y; + + /* default: resolution 1 (coarse), samples = 1024 (2^10) and antenna 3 */ + + rxiq = (10 << 8) | 3; + if ((sample_count < 0) || (sample_count > 16)) { + printf("wlmRxIQGet: SampleCount out of range of [0, 15].\n"); + return FALSE; + } else { + rxiq = (((sample_count & 0xff) << 8) | (rxiq & 0xff)); + } + + if ((antenna < 0) || (antenna > 3)) { + printf("wlmRxIQGet: Antenna out of range of [0, 3].\n"); + return FALSE; + } else { + rxiq = ((rxiq & 0xff00) | (antenna & 0xff)); + } + + if ((err = wlu_iovar_setint(irh, "phy_rxiqest", (int) rxiq)) < 0) { + printf("wlmRxIQGet: %s\n", wlmLastError()); + return FALSE; + } + + if ((err = wlu_iovar_getint(irh, "phy_rxiqest", (int*)&rxiq)) < 0) { + printf("wlmRxIQGet: %s\n", wlmLastError()); + return FALSE; + } + + if (resolution == 1) { + /* fine resolutin power reporting (0.25dB resolution) */ + if (rxiq >> 20) { + } else if (rxiq >> 10) { + } else { + /* 1-chain specific */ + int16 tmp; + tmp = (rxiq & 0x3ff); + tmp = ((int16)(tmp << 6)) >> 6; /* sing extension */ + if (tmp < 0) { + tmp = -1 * tmp; + } + + x = (float)(tmp >> 2); + y = (float)(tmp & 0x3); + + *val = (x + y * 25 /100) * (-1); + } + } + return TRUE; +} + +int wlmPHYTxPowerIndexGet(unsigned int *val, const char *chipid) +{ + uint32 power_index = (uint32)-1; + uint32 txpwridx[4] = {0}; + int chip = atoi(chipid); + + switch (chip) { + case 4329: + case 43291: + if (wlu_iovar_getint(irh, "sslpnphy_txpwrindex", (int *)&power_index) < 0) { + printf("wlmPHYTxPowerIndexGet: %s\n", wlmLastError()); + return FALSE; + } + *val = power_index; + break; + case 4325: + if (wlu_iovar_getint(irh, "lppphy_txpwrindex", + (int *)&power_index) < 0) { + printf("wlmPHYTxPowerIndexGet: %s\n", wlmLastError()); + return FALSE; + } + *val = power_index; + break; + default: + if (wlu_iovar_getint(irh, "phy_txpwrindex", (int *)&txpwridx[0]) < 0) { + printf("wlmPHYTxPowerIndexGet: %s\n", wlmLastError()); + return FALSE; + } + txpwridx[0] = dtoh32(txpwridx[0]); + *val = txpwridx[0]; + break; + } + + return TRUE; +} + +int wlmPHYTxPowerIndexSet(unsigned int val, const char *chipid) +{ + uint32 power_index; + uint32 txpwridx[4] = {0}; + int chip = atoi(chipid); + + power_index = dtoh32(val); + switch (chip) { + case 4329: + case 43291: + if (wlu_iovar_setint(irh, "sslpnphy_txpwrindex", power_index) < 0) { + printf("wlmPHYTxPowerIndexSet: %s\n", wlmLastError()); + return FALSE; + } + break; + case 4325: + if (wlu_iovar_setint(irh, "lppphy_txpwrindex", power_index) < 0) { + printf("wlmPHYTxPowerIndexSet: %s\n", wlmLastError()); + return FALSE; + } + break; + default: + txpwridx[0] = (int8) (power_index & 0xff); + txpwridx[1] = (int8) ((power_index >> 8) & 0xff); + txpwridx[2] = (int8) ((power_index >> 16) & 0xff); + txpwridx[3] = (int8) ((power_index >> 24) & 0xff); + + if (wlu_var_setbuf(irh, "phy_txpwrindex", txpwridx, 4*sizeof(uint32)) < 0) { + printf("wlmPHYTxPowerIndexSet: %s\n", wlmLastError()); + return FALSE; + } + break; + } + + return TRUE; +} + +int wlmRIFSEnable(int enable) +{ + int val, rifs; + + val = rifs = htod32(enable); + if (rifs != 0 && rifs != 1) { + printf("wlmRIFSEnable: Usage: input must be 0 or 1\n"); + return FALSE; + } + + if (wlu_set(irh, WLC_SET_FAKEFRAG, &val, sizeof(int)) < 0) { + printf("wlmRIFSEnable: %s\n", wlmLastError()); + return FALSE; + } + + if (wlu_iovar_setint(irh, "rifs", (int)rifs) < 0) { + printf("wlmRIFSEnable: %s\n", wlmLastError()); + return FALSE; + } + + return TRUE; +}
diff --git a/src/wl/exe/wlm.h b/src/wl/exe/wlm.h new file mode 100644 index 0000000..9f3458b --- /dev/null +++ b/src/wl/exe/wlm.h
@@ -0,0 +1,1116 @@ +/* + * Common (OS-independent) portion of + * WLM (Wireless LAN Manufacturing) test library. + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlm.h 281542 2011-09-02 17:31:19Z $ + */ + +#ifndef _wlm_h +#define _wlm_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** +\mainpage mfgtest_api.h + +Overview: + +The MFG API DLL allows a user to talk to a DUT by providing functions +that abstract out the lower level details of the driver. + +The goal of this API is to make testing easier by providing enough +functionality for the user to perform various tasks without +requiring the user to know anything about the driver internals and, +in addition, any differences there may be between drivers. + +*/ + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define WLM_MAX_FILENAME_LEN 256 + +#if defined(WIN32) +#define WLM_FUNCTION __declspec(dllexport) +#else +#define WLM_FUNCTION +#endif /* WIN32 */ + +/* Supported DUT interfaces. */ +/* Values are used to select the interface used to talk to the DUT. */ +enum { + WLM_DUT_LOCAL = 0, /* client and DUT on same device */ + WLM_DUT_SERIAL = 1, /* client to DUT via serial */ + WLM_DUT_SOCKET = 2, /* client to DUT via Ethernet */ + WLM_DUT_WIFI = 3, /* client to DUT via WLAN */ + WLM_DUT_DONGLE = 4 /* client to DUT dongle via serial */ +}; +typedef int WLM_DUT_INTERFACE; + +/* Supported server ports. */ +/* Values are used to configure server port (for WLM_DUT_SOCKET only). */ +enum { + WLM_DEFAULT_DUT_SERVER_PORT = 8000 /* default */ +}; +typedef int WLM_DUT_SERVER_PORT; + +/* Supported DUT OS. */ +/* Values are used to select the OS of the DUT. */ +enum { + WLM_DUT_OS_LINUX = 1, /* Linux DUT */ + WLM_DUT_OS_WIN32 = 2 /* Win32 DUT */ +}; +typedef int WLM_DUT_OS; + +/* Supported join modes. */ +/* Values are used to select the mode used to join a network. */ +enum { + WLM_MODE_IBSS = 0, /* IBSS Mode. (Adhoc) */ + WLM_MODE_BSS = 1, /* BSS Mode. */ + WLM_MODE_AUTO = 2 /* Auto. */ +}; +typedef int WLM_JOIN_MODE; + +/* Supported bands. */ +/* Values are used to select the band used for testing. */ +enum { + WLM_BAND_AUTO = 0, /* auto select */ + WLM_BAND_5G = 1, /* 5G Band. */ + WLM_BAND_2G = 2, /* 2G Band. */ + WLM_BAND_DUAL = WLM_BAND_2G | WLM_BAND_5G /* Dual Band. */ +}; +typedef int WLM_BAND; + +/* Supported gmode. */ +/* Values are used to select gmode used for testing. */ +enum { + WLM_GMODE_LEGACYB = 0, + WLM_GMODE_AUTO = 1, + WLM_GMODE_GONLY = 2, + WLM_GMODE_BDEFERED = 3, + WLM_GMODE_PERFORMANCE = 4, + WLM_GMODE_LRS = 5 +}; +typedef int WLM_GMODE; + +/* Supported legacy rates. */ +/* Values are used to select the rate used for testing. */ +enum { + WLM_RATE_AUTO = 0, + WLM_RATE_1M = 2, + WLM_RATE_2M = 4, + WLM_RATE_5M5 = 11, + WLM_RATE_6M = 12, + WLM_RATE_9M = 18, + WLM_RATE_11M = 22, + WLM_RATE_12M = 24, + WLM_RATE_18M = 36, + WLM_RATE_24M = 48, + WLM_RATE_36M = 72, + WLM_RATE_48M = 96, + WLM_RATE_54M = 108 +}; +typedef int WLM_RATE; + +/* Supported MCS rates */ +enum { + WLM_MCS_RATE_0 = 0, + WLM_MCS_RATE_1 = 1, + WLM_MCS_RATE_2 = 2, + WLM_MCS_RATE_3 = 3, + WLM_MCS_RATE_4 = 4, + WLM_MCS_RATE_5 = 5, + WLM_MCS_RATE_6 = 6, + WLM_MCS_RATE_7 = 7, + WLM_MCS_RATE_8 = 8, + WLM_MCS_RATE_9 = 9, + WLM_MCS_RATE_10 = 10, + WLM_MCS_RATE_11 = 11, + WLM_MCS_RATE_12 = 12, + WLM_MCS_RATE_13 = 13, + WLM_MCS_RATE_14 = 14, + WLM_MCS_RATE_15 = 15, + WLM_MCS_RATE_16 = 16, + WLM_MCS_RATE_17 = 17, + WLM_MCS_RATE_18 = 18, + WLM_MCS_RATE_19 = 19, + WLM_MCS_RATE_20 = 20, + WLM_MCS_RATE_21 = 21, + WLM_MCS_RATE_22 = 22, + WLM_MCS_RATE_23 = 23, + WLM_MCS_RATE_24 = 24, + WLM_MCS_RATE_25 = 25, + WLM_MCS_RATE_26 = 26, + WLM_MCS_RATE_27 = 27, + WLM_MCS_RATE_28 = 28, + WLM_MCS_RATE_29 = 29, + WLM_MCS_RATE_30 = 30, + WLM_MCS_RATE_31 = 31, + WLM_MCS_RATE_32 = 32 +}; + +typedef int WLM_MCS_RATE; + +/* Supported STF mode */ +enum { + WLM_STF_MODE_SISO = 0, /* stf mode SISO */ + WLM_STF_MODE_CDD = 1, /* stf mode CDD */ + WLM_STF_MODE_STBC = 2, /* stf mode STBC */ + WLM_STF_MODE_SDM = 3 /* stf mode SDM */ +}; +typedef int WLM_STF_MODE; + + +/* Supported PLCP preambles. */ +/* Values are used to select the preamble used for testing. */ +enum { + WLM_PREAMBLE_AUTO = -1, + WLM_PREAMBLE_SHORT = 0, + WLM_PREAMBLE_LONG = 1 +}; +typedef int WLM_PREAMBLE; + +/* Supported MIMO preamble types */ +enum { + WLM_MIMO_MIXEDMODE = 0, + WLM_MIMO_GREENFIELD = 1 +}; +typedef int WLM_MIMO_PREAMBLE; + +enum { + WLM_CHAN_FREEQ_RANGE_2G = 0, + WLM_CHAN_FREEQ_RANGE_5GL, + WLM_CHAN_FREEQ_RANGE_5GM, + WLM_CHAN_FREEQ_RANGE_5GH +}; +typedef int WLM_BANDRANGE; + +/* Supported image formats modes. */ +/* Values are used to select the type of image to read/write. */ +enum { + WLM_TYPE_AUTO = 0, /* Auto mode. */ + WLM_TYPE_SROM = 1, /* SROM. */ + WLM_TYPE_OTP = 2 /* OTP. */ +}; +typedef int WLM_IMAGE_TYPE; + +/* Supported authentication type. */ +/* Values are used to select the authentication type used to join a network. */ +enum { + WLM_TYPE_OPEN = 0, /* Open */ + WLM_TYPE_SHARED = 1 /* Shared */ +}; +typedef int WLM_AUTH_TYPE; + +/* Supported authentication mode. */ +/* Values are used to select the authentication mode used to join a network. */ +enum { + WLM_WPA_AUTH_DISABLED = 0x0000, /* Legacy (i.e., non-WPA) */ + WLM_WPA_AUTH_NONE = 0x0001, /* none (IBSS) */ + WLM_WPA_AUTH_PSK = 0x0004, /* Pre-shared key */ + WLM_WPA2_AUTH_PSK = 0x0080 /* Pre-shared key */ +}; +typedef int WLM_AUTH_MODE; + +/* WLAN Security Encryption. */ +/* Values are used to select the type of encryption used for testing. */ +enum { + WLM_ENCRYPT_NONE = 0, /* No encryption. */ + WLM_ENCRYPT_WEP = 1, /* WEP encryption. */ + WLM_ENCRYPT_TKIP = 2, /* TKIP encryption. */ + WLM_ENCRYPT_AES = 4, /* AES encryption. */ + WLM_ENCRYPT_WSEC = 8, /* Software WSEC encryption. */ + WLM_ENCRYPT_FIPS = 0x80 /* FIPS encryption. */ +}; +typedef int WLM_ENCRYPTION; + +/* Country abbreviative code */ +#define WLM_COUNTRY_ALL "ALL" /* Default country code */ +#define WLM_COUNTRY_JAPAN "JP" /* Japan country code */ +#define WLM_COUNTRY_KOREA "KR" /* Korea country code */ + +/* number of 5G channel offsets */ +#define CGA_5G_OFFSETS_LEN 24 + +/* number of 2G channel offsets */ +#define CGA_2G_OFFSETS_LEN 14 + +/* Initialization related functions */ + + +#define WLM_VERSION_STR "wlm version: 10.02.0 (support 4325, 4329, 4330 and 43236)" + +/* Get the WLM version. + * param[out] buffer version string for current wlm (dll, lib and dylib) + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmWLMVersionGet(const char **buffer); + +/* Performs any initialization required internally by the DLL. + * NOTE: This method needs to be called before any other API function. + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmApiInit(void); + +/* Performs any cleanup required internally by the DLL. + * NOTE: This method needs to be called by the user at the end of the application. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmApiCleanup(void); + +/* Selects the interface to use for talking to the DUT + * + * param[in] ifType The desired interface. + * param[in] ifName Expected value depends on ifType: + * For ifType = WLM_DUT_DONGLE, ifName is the COM port to use (ex: "COM1"). + * For ifType = WLM_DUT_SOCKET, ifName is the IP address to use + * (ex: "192.168.1.1" or "localhost"). + * param[in] dutServerPort Server port of DUT (used only for WLM_DUT_SOCKET). + * param[in] dutOs Operating system of DUT. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSelectInterface(WLM_DUT_INTERFACE ifType, char *ifName, + WLM_DUT_SERVER_PORT dutServerPort, WLM_DUT_OS dutOs); + +/* Gets the WLAN driver version. + * + * param[in] buffer Buffer for the version string. + * param[in] length Maximum length of buffer. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmVersionGet(char *buffer, int length); + +/* Enables or disables wireless adapter. + * + * param[in] enable Set to true to bring adapter up, false to bring down. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmEnableAdapterUp(int enable); + +/* Check if adapter is currently up. + * + * param[in] up Return the up/down state of adapter. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmIsAdapterUp(int *up); + +/* Enables or disables Minimum Power Consumption (MPC). + * MPC will automatically turn off the radio if not associated to a network. + * + * param[in] enable Set to true to enable MPC, false to disable MPC. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmMinPowerConsumption(int enable); + +/* Sets the operating channel of the DUT. + * + * param[in] channel Desired channel. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmChannelSet(int channel); + +/* Sets the operating legacy rate (bg_rate or a_rate) for the DUT. + * + * param[in] rate Desired rate. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRateSet(WLM_RATE rate); + +/* Sets the operating legacy rate (nrate) of the DUT. + * + * param[in] rate Desired rate. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmLegacyRateSet(WLM_RATE rate); + + +/* Sets the operating mcs rate and STF of the DUT + * param[in] Desired mcs rate [0, 7] for SISO (single-in-single-out) device. + * param[in] Stf mode, 0=SISO, 1= CDD, 2=STBC, 3=SDM + * return - True for sucess, false for failure. +*/ +WLM_FUNCTION +int wlmMcsRateSet(WLM_MCS_RATE mcs_rate, WLM_STF_MODE stf_mode); + +/* Sets the PLCP preamble. + * + * param[in] preamble Desired preamble. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPreambleSet(WLM_PREAMBLE preamble); + +/* Set the band. + * + * param[in] The Desired band. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmBandSet(WLM_BAND band); + +/* Get available bands. + * + * param[in] Available bands returned in the form of WLM_BANDs added. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmGetBandList(WLM_BAND * bands); + +/* Set gmode. + * + * param[in] The desired gmode. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmGmodeSet(WLM_GMODE gmode); + +/* Sets the receive antenna. + * + * param[in] antenna Desired antenna. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRxAntSet(int antenna); + +/* Sets the transmit antenna. + * + * param[in] antenna Desired antenna. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTxAntSet(int antenna); + +/* Retrieves the current estimated power in milli-dBm. + * + * param[out] estPower Power value returned. + * param[in] chain For MIMO device, specifies which chain to retrieve power value from. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmEstimatedPowerGet(int *estPower, int chain); + +/* Retrieves the current TX power in milli-dB. + * + * param[in] power Power value returned. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTxPowerGet(int *power); + +/* Sets the current TX power. + * + * param[in] powerValue Desired power value. Expected to be in milli-dB. Use -1 to restore default. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTxPowerSet(int powerValue); + +/* Retrieves the tx power control parameters for SISO system. + * + * param[in] bandrange. The desired band range for getting PA parameters. + * param[out] b0 PA parameter returned. + * param[out] b1 PA parameter returned. + * param[out] a1 PA parameter returned. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPaParametersGet(WLM_BANDRANGE bandrange, + unsigned int *a1, unsigned int *b0, unsigned int *b1); + +/* Sets tx power control parameters for SISO system. + * + * param[in] bandrange. The desired band range for getting PA parameters. + * param[in] b0 PA parameter. + * param[in] b1 PA parameter. + * param[in] a1 PA parameter. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPaParametersSet(WLM_BANDRANGE bandrange, + unsigned int a1, unsigned int b0, unsigned int b1); + +/* Retrieves the tx power control parameters for MIMO system. + * + * param[in] bandrange The desired band range for getting PA parameters. + * param[in] chain. The desired tx chain for getting PA parameters + * param[out] b0 PA parameter returned. + * param[out] b1 PA parameter returned. + * param[out] a1 PA parameter returned. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmMIMOPaParametersGet(WLM_BANDRANGE bandrange, int chain, + unsigned int *a1, unsigned int *b0, unsigned int *b1); + +/* Sets tx power control parameters for MIMO system. + * + * param[in] bandrange. The desired band range for getting PA parameters. + * param[in] chain. The desired tx chain for getting PA parameters. + * param[in] b0 PA parameter. + * param[in] b1 PA parameter. + * param[in] a1 PA parameter. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmMIMOPaParametersSet(WLM_BANDRANGE bandrange, int chain, + unsigned int a1, unsigned int b0, unsigned int b1); + +/* Retrieves the current MAC address of the device. + * + * param[in] macAddr MAC address returned. + * param[in] length Length of macAddr buffer. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmMacAddrGet(char *macAddr, int length); + +/* Sets the MAC address of the device. + * + * param[in] macAddr The desired MAC address. Expected format is "XX:XX:XX:XX:XX:XX". + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmMacAddrSet(const char* macAddr); + +/* Enables or disables output of a carrier tone. + * + * param[in] enable Set to true to enable carrier tone, false to disable. + * param[in] channel Desired channel. Ignored if <i>enable</i> is false. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmEnableCarrierTone(int enable, int channel); + +/* Enables or disables an EVM test. + * + * param[in] enable Set to true to enable EVM test, false to disable. + * param[in] channel Desired channel. Ignored if <i>enable</i> is false. + * param[in] rate Desired rate. Ignored if <i>enable</i> is false. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmEnableEVMTest(int enable, WLM_RATE rate, int channel); + +/* RX/TX related functions */ + +/* Starts sending packets with supplied parameters. + * + * param[in] shortPreamble Set to true to use a short preamble, false for a long preamble. + * param[in] interPacketDelay Delay between each packet. + * param[in] numPackets The number of packets transmitted. + * param[in] packetLength Length of packet transmitted. + * param[in] destMac The MAC address of the destination. + * param[in] withAck Ack response expected for transmitted packet. + * param[in] syncMode Enable synchronous mode to transmit packets before returning. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTxPacketStart(unsigned int interPacketDelay, + unsigned int numPackets, unsigned int packetLength, + const char* destMac, int withAck, int syncMode); + +/* Stops sending packets. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTxPacketStop(void); + +/* Starts receiving packets with supplied parameters. + * + * param[in] srcMac The MAC address of the packet source.. + * param[in] withAck Ack response expected for received packet. + * param[in] syncMode Enable synchronous mode to receive packets before returning or timeout. + * param[in] numPackets Number of receive packets before returning (sync mode only). + * param[in] timeout Maximum timeout in msec (sync mode only). + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRxPacketStart(const char* srcMac, int withAck, + int syncMode, unsigned int numPackets, unsigned int timeout); + +/* Stops receiving packets. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRxPacketStop(void); + +/* Returns number of packets that were ACKed successfully. + * + * param[in] count Packet count returned. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTxGetAckedPackets(unsigned int *count); + +/* Returns number of packets received successfully. + * + * param[in] count Packet count returned. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRxGetReceivedPackets(unsigned int *count); + +/* Returns Receive Signal Strength Indicator (RSSI). + * + * param[in] rssi RSSI returned. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRssiGet(int *rssi); + +/* Sequence related functions */ + +/* Initiates a command batch sequence. + * Any commands issued after calling this function will be queued + * instead of being executed. Call sequenceStop() to run queued commands. + * + * param[in] clientBatching Set to true to batch on client, false to batch on server/DUT. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSequenceStart(int clientBatching); + +/* Signals the end of a command batch sequence. + * Requires a previous call to sequenceStart(). Any commands + * issued after previously calling sequenceStart() will be run. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSequenceStop(void); + +/* Sets a delay between commands, in ms. + * Requires a previous call to sequenceStart(). Once sequenceStart() is called, + * calling sequenceDelay() after a command will insert a delay after the + * previous command is complete. + * + * param[in] msec Amount of time to wait after previous command has complete. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSequenceDelay(int msec); + +/* If a command sequence fails at a particular command, the remaining + * commands will be aborted. Calling this function, will return the index + * of which command failed. NOTE: Index starts at 1. + * + * param[in] index Failed command index returned. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSequenceErrorIndex(int *index); + +/* Image access (SROM/OTP) functions: */ + +/* Programs the device with a supplied image. Used to program the SROM/OTP. + * + * param[in] byteStream A stream of bytes loaded from an image file. + * param[in] length The number of bytes to write. + * param[in] imageType Use this to force a specific image type (ex: SROM, OTP, etc). + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmDeviceImageWrite(const char* byteStream, int length, WLM_IMAGE_TYPE imageType); + +/* Dumps the image from the device. Used to read the SROM/OTP. + * + * param[out] byteStream A user supplied buffer. + * param[in] length The size of the buffer supplied by byteStream. + * param[in] imageType Use this to force a specific image type (ex: SROM, OTP, etc). + * + * return - Size of image in bytes. -1 if size of image is larger than supplied buffer. + */ +WLM_FUNCTION +int wlmDeviceImageRead(char* byteStream, unsigned int length, WLM_IMAGE_TYPE imageType); + +/* Network related functions */ + +/* Set the current wireless security. + * + * param[in] authType Desired authentication type. + * param[in] authMode Desired authentication mode. + * param[in] encryption The desired encryption method. + * param[in] key The encryption key string (null terminated). + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSecuritySet(WLM_AUTH_TYPE authType, WLM_AUTH_MODE authMode, + WLM_ENCRYPTION encryption, const char *key); + +/* Joins a network. + * + * param[in] ssid The SSID of the network to join. + * param[in] mode The mode used for the join. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmJoinNetwork(const char* ssid, WLM_JOIN_MODE mode); + +/* Disassociates from a currently joined network. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmDisassociateNetwork(void); + +/* Retrieves the current SSID of the AP. + * + * param[in] ssid SSID returned. SSID may be returned if not associated + * (i.e. attempting to associate, roaming). + * param[in] length Length of ssid buffer. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSsidGet(char *ssid, int length); + +/* Retrieves the current BSSID of the AP. + * + * param[in] bssid BSSID returned. If the device is not associated, empty string returned. + * param[in] length Length of bssid buffer. + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmBssidGet(char *ssid, int length); + +/* Set/Get the MIMO Preamble mode + * Valid options are: + * WLC_N_PREAMBLE_MIXEDMODE 0 + * WLC_N_PREAMBLE_GF 1 + */ + +WLM_FUNCTION +int wlmMimoPreambleSet(int type); + +WLM_FUNCTION +int wlmMimoPreambleGet(int* type); + +/* Set/Get the CGA coefficients in the 2.4G/5G band + * requires an array of 24 uint8s to be set + * and a specified length of 24 to get + * All of these CGA value query functions only applies to 4329 solution + */ + +WLM_FUNCTION +int wlmCga5gOffsetsSet(char* values, int len); + +WLM_FUNCTION +int wlmCga5gOffsetsGet(char* buffer, int len); + +WLM_FUNCTION +int wlmCga2gOffsetsSet(char* values, int len); + +WLM_FUNCTION +int wlmCga2gOffsetsGet(char* buffer, int len); + +/* Set Glacial Timer + * param[in] timer duration in msec + * + * return - True for success, false for failure. +*/ +WLM_FUNCTION +int wlmGlacialTimerSet(int val); + +/* Set Fast Timer + * param[in] timer duration in msec + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmFastTimerSet(int val); + +/* Set Slow Timer + * param[in] timer duration in msec + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSlowTimerSet(int val); + +/* Enable/Disable Scansuppress + * param[in] set to TRUE enables scansuppress, set to false disable scansuppress + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmScanSuppress(int val); + +/* Set Country Code + * param[in] country code abbrv. Default use WLM_COUNTRY_CODE_ABBRV_ALL + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmCountryCodeSet(const char *country_name); + +/* Set fullcal + * Trigger lpphy fullcal + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmFullCal(void); + +/* Get Receiver IQ Estimation + * param[out] estimated rxiq power in dBm at 0.25dBm resolution + * param[in] sampel count, 0 to 15 + * param[in] antenna, 0 to 3 + * return - True for success, false for failure. +*/ +WLM_FUNCTION +int wlmRxIQEstGet(float *val, int sampleCount, int ant); + +/* Get PHY txpwrindex + * param[out] txpwrindex + * param[in] chip id: 4325, 4329, 43291, 4330, 4336 and 43236 + */ +WLM_FUNCTION +int wlmPHYTxPowerIndexGet(unsigned int *val, const char *chipid); + +/* Set PHY txpwrindex + * param[in] txpwrindex + * param[in] chip id: 4325, 4329, 43291, 4330, 4336 and 43236 + */ +WLM_FUNCTION +int wlmPHYTxPowerIndexSet(unsigned int val, const char *chipid); + +/* Enable/Disable RIFS + * param[in] Set RIFS mode. 1 = enable ; 0 = disable + */ +WLM_FUNCTION +int wlmRIFSEnable(int enable); + +/* Get/Set IOCTL + * param[in] cmd IOCTL command. + * param[in] buf Get data returned or set data input. + * param[in] len Length of buf. + * return - True for success, false for failure. + */ +WLM_FUNCTION int wlmIoctlGet(int cmd, void *buf, int len); +WLM_FUNCTION int wlmIoctlSet(int cmd, void *buf, int len); + +/* Get/Set IOVAR + * param[in] iovar IOVAR command. + * param[in] buf Get data returned or set data input. + * param[in] len Length of buf. + * return - True for success, false for failure. + */ +WLM_FUNCTION int wlmIovarGet(const char *iovar, void *buf, int len); +WLM_FUNCTION int wlmIovarSet(const char *iovar, void *buf, int len); + +/* Get/Set IOVAR integer. + * param[in] iovar IOVAR integer command. + * param[out/in] val Get integer returned or set integer input. + * return - True for success, false for failure. + */ +WLM_FUNCTION int wlmIovarIntegerGet(const char *iovar, int *val); +WLM_FUNCTION int wlmIovarIntegerSet(const char *iovar, int val); + +/* Get/Set IOVAR using internal buffer. + * param[in] iovar IOVAR command. + * param[in] param Input parameters. + * param[in] param_len Length of parameters. + * param[out] bufptr Buffer returning get data. + * return - True for success, false for failure. + */ +WLM_FUNCTION int wlmIovarBufferGet(const char *iovar, void *param, int param_len, void **bufptr); +WLM_FUNCTION int wlmIovarBufferSet(const char *iovar, void *param, int param_len); + + + +/* Enables radio + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRadioOn(void); + +/* Disable radio . + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRadioOff(void); + +/* Set Power Saving Mode + * param[in] 0 = CAM, 1 =Power Save, 2 = Fast PS Mode + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPMmode(int val); + +/* Enable roaming + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRoamingOff(void); + +/* Disable roaming + * + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRoamingOn(void); + +/* Get roaming trigger level + * param[out] roaming trigger level in dBm returned + * param[in] frequency band + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRoamTriggerLevelGet(int *val, WLM_BAND band); + +/* Set roaming trigger level + * param[in] roaming trigger level in dBm + * param[in] frequence band + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRoamTriggerLevelSet(int val, WLM_BAND band); + +/* Set framburst mode on + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmFrameBurstOn(void); + +/* Set framburst mode off + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmFrameBurstOff(void); + +/* Set beacon interval + * param[in] beacon interval in ms + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmBeaconIntervalSet(int val); + +/* Set AMPDU mode on/off + * param[in] on = 1, off = 0 + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmAMPDUModeSet(int val); + +/* Set MIMO bandwidth capability + * param[in] mimo bandwidth capability. 0 = 20Mhz, 1 =40Mhz + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmMIMOBandwidthCapabilitySet(int val); + +/* Set interference on/off + * param[in] on = 1, 0ff = 0 + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmInterferenceSet(int val); + +/* Set interferenceoverride on/off + * param[in] on = 1, 0ff = 0 + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmInterferenceOverrideSet(int val); + +/* Set MIMO transmit banddwith + * param[in] auto = -1, 2 = 20Mhz, 3 = 20Mhz upper , 4 =40 Mhz, 5 =40dup (mcs32 only) + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTransmitBandwidthSet(int val); + +/* Set MIMO short guard intervaltransmit banddwith + * param[in] auto = -1, 1 = on, 0 = off + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmShortGuardIntervalSet(int val); + +/* Set MIMO OBSS coex set + * param[in] auto = -1, 1 = on, 0 = off + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmObssCoexSet(int val); + +/* Set PHY Periodical call + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPHYPeriodicalCalSet(void); + +/* Set PHY Force call + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPHYForceCalSet(void); + +/* Disable scrambler update + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPHYScramblerUpdateDisable(void); + +/* Enable scrambler update + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPHYScramblerUpdateEnable(void); + +/* Turn PHY watchdog on/off + * param[in] on = 1, off = 0 + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPHYWatchdogSet(int val); + +/* Disable temperature sensore + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTemperatureSensorDisable(void); + +/* Enable temperature sensore + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTemperatureSensorEnable(void); + +/* Set transmit core + * param[in] + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTransmitCoreSet(int val); + +/* Get temperation sensor read + * param[out] chip core temperature in F + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmPhyTempSenseGet(int *val); + +/* Get chip OTP Fab ID + * param[out] chip fab id + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmOtpFabidGet(int *val); + +/* Set mimo channnel specifications + * param[in] channel + * param[in] bandwidth 20 = 20Mhz, 40 = 40Mhz + * param[in] sideband 1 = upper, -1 = lower, 0 = none + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmChannelSpecSet(int channel, int bandwidth, int sideband); + +/* Set rts threshold + * param[in] rts threshold value + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRtsThresholdOverride(int val); + +/* Turn STBC Tx mode on/off + * param[in] on = 1, off = 0 + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSTBCTxSet(int val); + +/* Turn STBC Rx mode on/off + * param[in] on = 1, off = 0 + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmSTBCRxSet(int val); + +/* MIMO single stream tx chain selection + * param[in] chain 1 = 1, chain 2 = 2 + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmTxChainSet(int val); + +/* MIMO single stream rx chain selection + * param[in] chain 1 = 1, chain 2 = 2 + * return - True for success, false for failure. + */ +WLM_FUNCTION +int wlmRxChainSet(int val); + +#ifdef __cplusplus +} +#endif + +#endif /* _wlm_h */
diff --git a/src/wl/exe/wlu.c b/src/wl/exe/wlu.c new file mode 100644 index 0000000..b2583e4 --- /dev/null +++ b/src/wl/exe/wlu.c
@@ -0,0 +1,36330 @@ +/* + * Common code for wl command-line swiss-army-knife utility + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu.c 647609 2016-07-06 21:27:18Z $ + */ + + +#ifdef WIN32 +#include <windows.h> +#endif + +#include <wlioctl.h> + +#define CLMDOWNLOAD + + +/* Because IL_BIGENDIAN was removed there are few warnings that need + * to be fixed. Windows was not compiled earlier with IL_BIGENDIAN. + * Hence these warnings were not seen earlier. + * For now ignore the following warnings + */ +#ifdef WIN32 +#pragma warning(push) +#pragma warning(disable : 4244) +#pragma warning(disable : 4761) +#endif + +#include <typedefs.h> +#include <epivers.h> +#include <proto/ethernet.h> +#include <proto/802.11.h> +#include <proto/802.1d.h> +#include <proto/802.11e.h> +#include <proto/wpa.h> +#include <proto/bcmip.h> +#include <proto/wps.h> + +#include <bcmwifi_rates.h> +#include "wlu_rates_matrix.h" + +#ifdef BCMCCX +#include <proto/802.11_ccx.h> +#endif +#ifdef WLBTAMP +#include <proto/bt_amp_hci.h> +#endif +#include <sdiovar.h> +#include <bcmutils.h> +#include <bcmendian.h> +#include <bcmwifi_channels.h> +#include <bcmsrom_fmt.h> +#include <bcmsrom_tbl.h> +#include "wlu_common.h" +#include "wlu.h" +#include <bcmcdc.h> +#if defined(WLPFN) +#ifndef TARGETENV_android +#include <unistd.h> +#endif +#include <signal.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <net/if.h> +#include <linux/if_packet.h> +#endif /* WLPFN */ + +#ifdef WLEXTLOG +#include <wlc_extlog_idstr.h> +#endif + +#include <inttypes.h> +#include <miniopt.h> +#include <errno.h> + +#if defined CLMDOWNLOAD +#include <sys/stat.h> +#include <trxhdr.h> +#include <stdio.h> +#include <errno.h> + +#ifndef WIN32 +#include <fcntl.h> +#endif /* WIN32 */ +#endif + + +#if LCNCONF || SSLPNCONF +#define MAX_CHUNK_LEN 1456 /* 8 * 7 * 26 */ +#else +#define MAX_CHUNK_LEN 1408 /* 8 * 8 * 22 */ +#endif + +#include <bcm_mpool_pub.h> +#include <proto/bcmipv6.h> + +#ifdef EVENT_LOG_COMPILE +#define EVENT_LOG_DUMPER +#include <event_log.h> +#endif + +/* For backwards compatibility, the absense of the define 'NO_FILESYSTEM_SUPPORT' + * implies that a filesystem is supported. + */ +#if !defined(BWL_NO_FILESYSTEM_SUPPORT) +#define BWL_FILESYSTEM_SUPPORT +#endif + +cmd_func_t wl_int; + + +static cmd_func_t wl_print_deprecate; +static cmd_func_t wl_void, wl_rssi, wl_rssi_event, wl_phy_rssi_ant, wl_gmode; +static cmd_func_t wlu_dump, wlu_mempool, wlu_srdump, wlu_srwrite, wlu_srvar, wl_nvsource; +static cmd_func_t wlu_ciswrite, wlu_cisupdate, wlu_cisdump, wlu_offloads_stats; +static cmd_func_t wl_rate, wl_rate_mrate, wl_phy_rate, wl_bss_max; +static cmd_func_t wl_channel, wl_chanspec, wl_chanim_state, wl_chanim_mode, wl_rclass; +static cmd_func_t wl_radio, wl_version, wl_list, wl_band, wl_bandlist, wl_phylist; +static cmd_func_t wl_join, wl_tssi, wl_txpwr, wl_atten, wl_evm, wl_country; +static cmd_func_t wl_out, wl_txpwr1, wl_country_ie_override; +static cmd_func_t wl_maclist, wl_get_pktcnt, wl_upgrade; +static cmd_func_t wl_maclist_1, wl_default_rateset; +static cmd_func_t wl_rateset, wl_interfere, wl_interfere_override; +static cmd_func_t wl_radar_args, wl_radar_thrs, wl_dfs_status; +static cmd_func_t wl_get_txpwr_limit, wl_get_current_power, wl_get_instant_power; +static cmd_func_t wl_get_current_txppr, wl_get_txpwr_target_max; +static cmd_func_t wl_var_get, wl_var_getint, wl_var_getinthex, wl_var_getandprintstr; +static cmd_func_t wl_var_setint, wl_addwep, wl_rmwep; +static cmd_func_t wl_nvdump, wl_nvget, wl_nvset, wl_sta_info, wl_chan_info; +static cmd_func_t wl_wme_ac_req, wl_add_ie, wl_del_ie, _wl_list_ie; +static cmd_func_t wl_wme_apsd_sta, wl_wme_dp, wl_lifetime; +static cmd_func_t wl_rand, wl_otpw, wl_otpraw, wl_counters, wl_delta_stats; +static cmd_func_t wl_assoc_info, wl_wme_counters, wl_devpath; +static cmd_func_t wl_management_info; +static cmd_func_t wl_eventbitvec, wl_diag, wl_var_void; +static cmd_func_t wl_auto_channel_sel; +static cmd_func_t wl_bsscfg_int, wl_bsscfg_enable; +static cmd_func_t wl_msglevel, wl_plcphdr, wl_reg, wl_macreg, wl_band_elm; +static cmd_func_t wl_phymsglevel; +static cmd_func_t wl_rateparam, wl_wepstatus, wl_status, wl_spect; +static cmd_func_t wl_sup_rateset, wl_scan, wl_send_csa, wl_iscan, wl_escan; +static cmd_func_t wl_roamparms; +/* WLOTA_EN START */ +static cmd_func_t wl_ota_loadtest, wl_otatest_status, wl_load_cmd_stream; +static cmd_func_t wl_ota_teststop; +/* WLOTA_EN END */ +#ifdef EXTENDED_SCAN +static cmd_func_t wl_extdscan; +#endif +static cmd_func_t wl_dump_chanlist, wl_primary_key, wl_measure_req, wl_send_quiet; +static cmd_func_t wl_dump_chanspecs, wl_dump_chanspecs_defset, wl_cur_mcsset; +static cmd_func_t wl_wsec, wl_keys, wl_wsec_test; +static cmd_func_t wl_channels_in_country; +static cmd_func_t wl_wpa_auth, wl_tsc, wl_deauth_rc, wl_ssid, wl_bssid, wl_smfstats; +static cmd_func_t wl_wds_wpa_role_old, wl_wds_wpa_role, wl_set_pmk; +static cmd_func_t wl_rm_request, wl_rm_report; +static cmd_func_t wl_join_pref, wl_assoc_pref; +static cmd_func_t wl_dump_networks, wl_mac, wl_revinfo, wl_iov_mac, wl_iov_pktqlog_params; +static cmd_func_t wl_cac, wl_tslist, wl_tspec, wl_tslist_ea, wl_tspec_ea, wl_cac_delts_ea; +static cmd_func_t wl_varstr, wl_var_setintandprintstr; +static cmd_func_t wl_rifs; +static cmd_func_t wl_rifs_advert; +static cmd_func_t wl_test_tssi, wl_test_tssi_offs, wl_phy_rssiant, wl_rxiq; +static cmd_func_t wl_obss_scan, wl_obss_coex_action; +static cmd_func_t wl_dump_lq; +static cmd_func_t wl_monitor_lq; +static cmd_func_t wl_test_idletssi; + +#ifdef WLPFN +static cmd_func_t wl_pfn_set; +static cmd_func_t wl_pfn_add; +static cmd_func_t wl_pfn_add_bssid; +static cmd_func_t wl_pfn_cfg; +static cmd_func_t wl_pfn; +static cmd_func_t wl_pfnbest; +static cmd_func_t wl_pfn_suspend; +static cmd_func_t wl_pfnlbest; +static cmd_func_t wl_pfn_mem; +static cmd_func_t wl_pfn_event_check; +static cmd_func_t wl_escan_event_check; +static cmd_func_t wl_escanresults; +static cmd_func_t wl_event_filter; +#endif /* WLPFN */ + +#ifdef WLP2PO +static cmd_func_t wl_p2po_listen; +static cmd_func_t wl_p2po_addsvc; +static cmd_func_t wl_p2po_delsvc; +static cmd_func_t wl_p2po_sd_reqresp; +static cmd_func_t wl_p2po_listen_channel; +static cmd_func_t wl_p2po_stop; +static cmd_func_t wl_p2po_results; + +#endif /* WLP2PO */ + +#ifdef WLANQPO +static cmd_func_t wl_anqpo_set; +static cmd_func_t wl_anqpo_stop_query; +static cmd_func_t wl_anqpo_start_query; +static cmd_func_t wl_anqpo_ignore_ssid_list; +static cmd_func_t wl_anqpo_ignore_bssid_list; +static cmd_func_t wl_anqpo_results; +#endif /* WLANQPO */ +static cmd_func_t wl_hs20_ie; + +static cmd_func_t wl_wowl_pattern, wl_wowl_wakeind, wl_wowl_pkt, wl_wowl_status; +static cmd_func_t wl_wowl_wake_reason, wl_wowl_extended_magic; +static cmd_func_t wl_reassoc; + +static cmd_func_t wl_sd_reg, wl_sd_msglevel, wl_sd_blocksize, wl_sd_mode; + +static cmd_func_t wl_overlay; +static cmd_func_t wl_pmkid_info; + +#ifdef BCMCCX +static cmd_func_t wl_leap; +#endif + +static void wl_rate_histo_print(wl_mac_ratehisto_res_t *rate_histo_res); +static cmd_func_t wl_rate_histo; +static cmd_func_t wl_mac_rate_histo; +static cmd_func_t wl_sample_collect; +static cmd_func_t wlu_reg3args; + +static cmd_func_t wl_tpc_lm; +static cmd_func_t wlu_reg2args; +static cmd_func_t wme_tx_params; +static cmd_func_t wme_maxbw_params; +static cmd_func_t wl_ampdu_tid, wl_ampdu_activate_test; +static cmd_func_t wl_ampdu_retry_limit_tid; +static cmd_func_t wl_ampdu_rr_retry_limit_tid; +static cmd_func_t wl_ampdu_send_addba; +static cmd_func_t wl_ampdu_send_delba; + +static cmd_func_t wl_dpt_deny; +static cmd_func_t wl_dpt_endpoint; +static cmd_func_t wl_dpt_pmk; +static cmd_func_t wl_dpt_fname; +static cmd_func_t wl_dpt_list; +#ifdef WLTDLS +static cmd_func_t wl_tdls_endpoint; +static cmd_func_t wl_tdls_wfd_ie; +#endif /* WLTDLS */ +#ifdef WLBTAMP +static cmd_func_t wl_HCI_cmd; +static cmd_func_t wl_HCI_ACL_data; +static cmd_func_t wl_get_btamp_log; +#endif +static cmd_func_t wl_actframe; + +static cmd_func_t wl_gpioout; + +static cmd_func_t wl_bw_cap; +static cmd_func_t wl_nrate, wl_antsel, wl_txcore; +static cmd_func_t wl_txcore_pwr_offset; +#ifdef PLC +static cmd_func_t wl_plc; +#endif /* PLC */ +static cmd_func_t wl_txfifo_sz; +static cmd_func_t wl_pkteng, wl_pkteng_stats; + +static cmd_func_t wl_offload_cmpnt; +static cmd_func_t wl_hostip, wl_arp_stats, wl_toe_stats, wl_nshostip; +static cmd_func_t wl_mcast_ackmac, wl_mcast_ackreq, wl_mcast_status; +static cmd_func_t wl_mcast_actf_time, wl_mcast_rssi_thresh, wl_mcast_stats; +static cmd_func_t wl_mcast_rssi_delta, wl_mcast_vsie, wl_mcast_ar_timeout; +#ifdef WLOFFLD +static cmd_func_t wl_ol_notify_bcn_ie; +#endif + +#if defined(WLNDOE) || defined(WLOFFLD) +static cmd_func_t wl_hostipv6; +#endif +#ifdef WLNDOE +static cmd_func_t wl_ndstatus, wl_hostipv6, wl_solicitipv6, wl_remoteipv6; +#endif +static cmd_func_t wl_phy_papdepstbl; + +int wl_seq_batch_in_client(bool enable); +cmd_func_t wl_seq_start; +cmd_func_t wl_seq_stop; + +static cmd_func_t wl_phy_txiqcc, wl_phy_txlocc; +static cmd_func_t wl_rssi_cal_freq_grp_2g; +static cmd_func_t wl_phy_rssi_gain_delta_2g, wl_phy_rssi_gain_delta_5g; +static cmd_func_t wl_phy_rssi_gain_delta_2g_sub; +static cmd_func_t wl_phy_rxgainerr_2g, wl_phy_rxgainerr_5g; +static cmd_func_t wl_phytable, wl_phy_pavars, wl_phy_povars; +static cmd_func_t wl_phy_fem, wl_phy_maxpower, wl_antgain, wl_phy_txpwrindex; +static cmd_func_t wl_keep_alive; +static cmd_func_t wl_mkeep_alive; +static cmd_func_t wl_srchmem; +static cmd_func_t wl_phy_rpcalvars; + +static cmd_func_t wl_pkt_filter_add; +static cmd_func_t wl_pkt_filter_enable; +static cmd_func_t wl_pkt_filter_list; +static cmd_func_t wl_pkt_filter_stats; + +#ifdef TRAFFIC_MGMT +static cmd_func_t wl_trf_mgmt_config; +static cmd_func_t wl_trf_mgmt_filters_add; +static cmd_func_t wl_trf_mgmt_filters_addex; +static cmd_func_t wl_trf_mgmt_filters_remove; +static cmd_func_t wl_trf_mgmt_filters_removeex; +static cmd_func_t wl_trf_mgmt_filters_list; +static cmd_func_t wl_trf_mgmt_filters_clear; +static cmd_func_t wl_trf_mgmt_bandwidth; +static cmd_func_t wl_trf_mgmt_flags; +static cmd_func_t wl_trf_mgmt_stats; +static cmd_func_t wl_trf_mgmt_stats_clear; +static cmd_func_t wl_trf_mgmt_shaping_info; +#endif /* TRAFFIC_MGMT */ + +#ifdef CLMDOWNLOAD +static cmd_func_t wl_clmload; +#endif /* CLMDOWNLOAD */ +static cmd_func_t wl_ledbh; + +#ifdef RWL_WIFI +/* Function added to support RWL_WIFI Transport */ +static cmd_func_t wl_wifiserver; +#endif + +static cmd_func_t wl_led_blink_sync; +static cmd_func_t wl_cca_get_stats; +static cmd_func_t wl_itfr_get_stats; +static cmd_func_t wl_rrm; +static cmd_func_t wl_rrm_nbr_req; +static cmd_func_t wl_rrm_bcn_req; +static cmd_func_t wl_rrm_chload_req; +static cmd_func_t wl_rrm_noise_req; +static cmd_func_t wl_rrm_frame_req; +static cmd_func_t wl_rrm_stat_req; +static cmd_func_t wl_rrm_lm_req; +static cmd_func_t wl_rrm_nbr_list; +static cmd_func_t wl_rrm_nbr_del_nbr; +static cmd_func_t wl_rrm_nbr_add_nbr; +static cmd_func_t wl_wnm; +static cmd_func_t wl_wnm_bsstq; +static cmd_func_t wl_tclas_add; +static cmd_func_t wl_tclas_del; +static cmd_func_t wl_tclas_list; +#ifdef WLWNM +static cmd_func_t wl_wnm_tfsreq_add; +static cmd_func_t wl_wnm_dms_set; +static cmd_func_t wl_wnm_dms_status; +static cmd_func_t wl_wnm_dms_term; +static cmd_func_t wl_wnm_service_term; +static cmd_func_t wl_wnm_timbc_offset; +static cmd_func_t wl_wnm_timbc_set; +static cmd_func_t wl_wnm_timbc_status; +static cmd_func_t wl_wnm_maxidle; +static cmd_func_t wl_wnm_bsstrans_req; +static cmd_func_t wl_wnm_keepalives_max_idle; +#endif /* WLWNM */ +static cmd_func_t wl_chanim_acs_record; +static cmd_func_t wl_chanim_stats; +static cmd_func_t wl_txdelay_params; +static cmd_func_t wl_intfer_params; + + +#ifdef WLP2P +static cmd_func_t wl_p2p_state; +static cmd_func_t wl_p2p_scan; +static cmd_func_t wl_p2p_ifadd; +static cmd_func_t wl_p2p_ifdel; +static cmd_func_t wl_p2p_ifupd; +static cmd_func_t wl_p2p_if; +static cmd_func_t wl_p2p_ops; +static cmd_func_t wl_p2p_noa; +#endif + +static cmd_func_t wl_rpmt; +static cmd_func_t wl_spatial_policy, wl_ratetbl_ppr; +static cmd_func_t wl_sarlimit; +static cmd_func_t wl_bmon_bssid; + +static cmd_func_t wl_ie; +static cmd_func_t wl_wnm_url; + + + +#ifdef SR_DEBUG +static cmd_func_t wl_dump_pmu; +static cmd_func_t wl_pmu_keep_on; +#endif /* SR_DEBUG */ + +#ifdef TBTT_OFFSET_STAT +static cmd_func_t wl_tbtt_offset_stat; +#endif /* TBTT_OFFSET_STAT */ + +static cmd_func_t wl_staprio; +static cmd_func_t wl_stamon_sta_config; +static cmd_func_t wl_monitor_promisc_level; +static cmd_func_t wl_bcnlenhist; +static cmd_func_t wl_aibss_bcn_force_config; + +#if defined(DWDS) +static cmd_func_t wl_dwds_config; +#endif + +static cmd_func_t wl_bss_peer_info; +static cmd_func_t wl_aibss_txfail_config; + +static void wl_txppr_print(ppr_t *ppr, int cck, uint flags); +static void wl_txppr_print_bw(ppr_t *ppr, int cck, uint flags, wl_tx_bw_t bw); +static int8 wl_ppr_get_pwr(ppr_t* pprptr, reg_rate_index_t rate_idx, wl_tx_bw_t bw); +static void wl_txpwr_array_row_print(ppr_t* pprptr, int8 channel_bandwidth, + reg_rate_index_t rate_idx); +static void wl_txpwr_array_print(ppr_t* pprptr, int8 channel_bandwidth, bool verbose, bool is5G); +static void wl_txpwr_ppr_print(ppr_t* pprptr, int vb, ppr_rate_type_t type, + clm_rate_group_id_t gid, int8 bw, reg_rate_index_t *rate_index, bool is5G); +static void wl_txpwr_print_row(const char *label, uint8 chains, int8 pwr20, + int8 pwr20in40, int8 pwr40, int8 pwr80, int8 pwr20in80, int8 pwr40in80, + int8 unsupported_rate, int8 channel_bandwidth, bool verbose); +static int wl_array_check_val(int8 *pwr, uint count, int8 val); +static void wl_txpwr_regulatory_array_row_print(int8 *powers, int8 *powers_subchan1, + int8 *powers_subchan2, int8 channel_bandwidth, reg_rate_index_t rate_index); +static void wl_txpwr_regulatory_array_print(int8 *powers, int8 *powers_subchan1, + int8 *powers_subchan2, int8 channel_bandwidth, bool verbose); +static int wl_array_uniform(uint8 *pwr, int start, int count); +static int wl_parse_rateset(void *wl, wl_rateset_args_t* rs, char **argv); +static void wl_print_mcsset(char *mcsset); +static void wl_print_vhtmcsset(uint16 *mcsset); + +static void dump_networks(char *buf); +void dump_bss_info(wl_bss_info_t *bi); +static void wl_dump_wpa_rsn_ies(uint8* cp, uint len); +static void wl_rsn_ie_dump(bcm_tlv_t *ie); +static cmd_func_t wl_power_sel_params; + +static cmd_func_t wl_phy_force_vsdb_chans; + +int wlu_get(void *wl, int cmd, void *buf, int len); +int wlu_set(void *wl, int cmd, void *buf, int len); + +static int _wl_dump_lq(void *wl); + +/* 802.11i/WPA RSN IE parsing utilities */ +typedef struct { + uint16 version; + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + wpa_suite_auth_key_mgmt_t *akm; + uint8 *capabilities; +} rsn_parse_info_t; + +static int wl_rsn_ie_parse_info(uint8* buf, uint len, rsn_parse_info_t *rsn); +static uint wl_rsn_ie_decode_cntrs(uint cntr_field); + +static int wl_parse_assoc_params(char **argv, wl_assoc_params_t *params, bool *prescanned); +static int wl_join_prescanned(void *wl, wl_join_params_t *join_params, uint *join_params_size); +#define wl_parse_reassoc_params(argv, params) wl_parse_assoc_params(argv, \ + (wl_assoc_params_t *)(params), NULL) + +static int wl_parse_channel_list(char* list_str, uint16* channel_list, int channel_num); +static int wl_parse_chanspec_list(char* list_str, chanspec_t *chanspec_list, int chanspec_num); +static chanspec_t wl_chspec_to_driver(chanspec_t chanspec); +static uint32 wl_chspec32_to_driver(chanspec_t chanspec); +static chanspec_t wl_chspec_from_driver(chanspec_t chanspec); +static chanspec_t wl_chspec32_from_driver(uint32 chanspec); + +#ifdef EXTENDED_SCAN +static int wl_parse_extdchannel_list(char* list_str, + chan_scandata_t* channel_list, int channel_num); +#endif + +static uint16 wl_qdbm_to_mw(uint8 qdbm); +static uint8 wl_mw_to_qdbm(uint16 mw); + +static int wl_cfg_option(char **argv, const char *fn_name, int *bsscfg_idx, int *consumed); +static int get_oui_bytes(uchar *oui_str, uchar *oui); +static int get_ie_data(uchar *data_str, uchar *ie_data, int len); +static void wl_printrate(int val); +static int rate_string2int(char *s); +static char *rate_int2string(char *buf, int val); + +static int wl_get_iscan(void *wl, char *buf, uint buf_len); +int wlu_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr); +int wlu_var_getbuf_sm(void *wl, const char *iovar, void *param, int param_len, void **bufptr); +int wlu_var_getbuf_med(void *wl, const char *iovar, void *param, int param_len, void **bufptr); +int wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len); + + +int wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len); +int wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen); +int wlu_iovar_getint(void *wl, const char *iovar, int *pval); +int wlu_iovar_setint(void *wl, const char *iovar, int val); + +static int wl_bssiovar_mkbuf(const char *iovar, int bssidx, void *param, + int paramlen, void *bufptr, int buflen, int *perr); +int wlu_bssiovar_setbuf(void* wl, const char *iovar, int bssidx, + void *param, int paramlen, void *bufptr, int buflen); +static int wl_bssiovar_getbuf(void* wl, const char *iovar, int bssidx, + void *param, int paramlen, void *bufptr, int buflen); +static int wl_bssiovar_set(void *wl, const char *iovar, int bssidx, void *param, int paramlen); +int wlu_bssiovar_get(void *wl, const char *iovar, int bssidx, void *outbuf, int len); +static int wl_bssiovar_setint(void *wl, const char *iovar, int bssidx, int val); +static int wl_bssiovar_getint(void *wl, const char *iovar, int bssidx, int *pval); + +static int wl_vndr_ie(void *wl, const char *command, uint32 pktflag_ok, char **argv); +static void wl_dump_ie_buf(vndr_ie_buf_t *ie_getbuf); +static int hexstrtobitvec(const char *cp, uchar *bitvec, int veclen); +static void wl_join_pref_print_ie(bcm_tlv_t *ie); +static void wl_join_pref_print_akm(uint8* suite); +static void wl_join_pref_print_cipher_suite(uint8* suite); +static void wl_print_tspec(tspec_arg_t *ts); +static void wl_cac_addts_usage(void); +static void wl_cac_delts_usage(void); + +static cmd_func_t wl_txmcsset; +static cmd_func_t wl_rxmcsset; + +static int wl_mimo_stf(void *wl, cmd_t *cmd, char **argv); + +#ifdef WLEXTLOG +static int wl_extlog(void *wl, cmd_t *cmd, char **argv); +static int wl_extlog_cfg(void *wl, cmd_t *cmd, char **argv); +#endif + +static int wl_assertlog(void *wl, cmd_t *cmd, char **argv); +static int wl_tsf(void *wl, cmd_t *cmd, char **argv); +static int wl_mfp_config(void *wl, cmd_t *cmd, char **argv); +static int wl_mfp_sha256(void *wl, cmd_t *cmd, char **argv); +static int wl_mfp_sa_query(void *wl, cmd_t *cmd, char **argv); +static int wl_mfp_disassoc(void *wl, cmd_t *cmd, char **argv); +static int wl_mfp_deauth(void *wl, cmd_t *cmd, char **argv); +static int wl_mfp_assoc(void *wl, cmd_t *cmd, char **argv); +static int wl_mfp_auth(void *wl, cmd_t *cmd, char **argv); +static int wl_mfp_reassoc(void *wl, cmd_t *cmd, char **argv); + +static cmd_func_t wl_scb_bs_data; + +static int wl_bssload_static(void *wl, cmd_t *cmd, char **argv); + +#ifdef EVENT_LOG_COMPILE +static int wl_event_log_set_init(void *wl, cmd_t *cmd, char **argv); +static int wl_event_log_set_expand(void *wl, cmd_t *cmd, char **argv); +static int wl_event_log_set_shrink(void *wl, cmd_t *cmd, char **argv); +static int wl_event_log_tag_control(void *wl, cmd_t *cmd, char **argv); +#endif + +static int wl_sleep_ret_ext(void *wl, cmd_t *cmd, char **argv); + +static char *ver2str(unsigned int vms, unsigned int vls); + +/* some OSes (FC4) have trouble allocating (kmalloc) 128KB worth of memory, + * hence keeping WL_DUMP_BUF_LEN below that + */ +#if defined(BWL_SMALL_WLU_DUMP_BUF) +#define WL_DUMP_BUF_LEN (4 * 1024) +#else +#define WL_DUMP_BUF_LEN (127 * 1024) +#endif + +#define CMDLINESZ 80 + +#define OUI_STR_SIZE 8 /* OUI string size */ +#define MAX_OUI_SIZE 3 /* MAX OUI size */ +#define MAX_BYTE_CHARS 2 /* MAX num chars */ +#define MAX_DATA_COLS 16 /* MAX data cols */ +#define DIV_QUO(num, div) ((num)/div) /* Return the quotient of division to avoid floats */ +#define DIV_REM(num, div) (((num%div) * 100)/div) /* Return the remainder of division */ + +#define RADIO_CORE_SYN (0x0 << 12) +#define RADIO_CORE_TX0 (0x2 << 12) +#define RADIO_CORE_TX1 (0x3 << 12) +#define RADIO_CORE_RX0 (0x6 << 12) +#define RADIO_CORE_RX1 (0x7 << 12) + +#define RADIO_CORE_CR0 (0x0 << 10) +#define RADIO_CORE_CR1 (0x1 << 10) +#define RADIO_CORE_CR2 (0x2 << 10) +#define RADIO_CORE_ALL (0x3 << 10) + +#define RADIO_2069_CORE_CR0 (0x0 << 9) +#define RADIO_2069_CORE_CR1 (0x1 << 9) +#define RADIO_2069_CORE_CR2 (0x2 << 9) +#define RADIO_2069_CORE_ALL (0x3 << 9) +#define RADIO_2069_CORE_PLL (0x4 << 9) + +/* IOCtl version read from targeted driver */ +static int ioctl_version; + +/* dword align allocation */ +static union { + char bufdata[WLC_IOCTL_MAXLEN]; + uint32 alignme; +} bufstruct_wlu; +static char *buf = (char*) &bufstruct_wlu.bufdata; + +/* integer output format, default to signed integer */ +static uint8 int_fmt; + + +/* + * Country names and abbreviations from ISO 3166 + */ +typedef struct { + const char *name; /* Long name */ + const char *abbrev; /* Abbreviation */ +} cntry_name_t; +cntry_name_t cntry_names[]; /* At end of this file */ + +typedef struct { + uint value; + const char *string; +} dbg_msg_t; + +typedef struct { + uint value; + const char *string; +} phy_msg_t; + +typedef struct { + uint value; + const char *string; +} monitor_promisc_level_msg_t; + +#define WL_SCAN_PARAMS_SSID_MAX 10 +#define SCAN_USAGE "" \ +"\tDefault to an active scan across all channels for any SSID.\n" \ +"\tOptional arg: SSIDs, list of [up to 10] SSIDs to scan (comma or space separated).\n" \ +"\tOptions:\n" \ +"\t-s S, --ssid=S\t\tSSIDs to scan\n" \ +"\t-t ST, --scan_type=ST\t[active|passive|prohibit|offchan|hotspot] scan type\n" \ +"\t--bss_type=BT\t\t[bss/infra|ibss/adhoc] bss type to scan\n" \ +"\t-b MAC, --bssid=MAC\tparticular BSSID MAC address to scan, xx:xx:xx:xx:xx:xx\n" \ +"\t-n N, --nprobes=N\tnumber of probes per scanned channel\n" \ +"\t-a N, --active=N\tdwell time per channel for active scanning\n" \ +"\t-p N, --passive=N\tdwell time per channel for passive scanning\n" \ +"\t-h N, --home=N\t\tdwell time for the home channel between channel scans\n" \ +"\t-c L, --channels=L\tcomma or space separated list of channels to scan" \ + +#define RATE_2G_USAGE \ +"\tEither \"auto\", or a simple CCK/DSSS/OFDM rate value:\n" \ +"\t1 2 5.5 11 6 9 12 18 24 36 48 54\n\n" \ +"\tOr options to specify legacy, HT, or VHT rate:\n" \ +"\t-r R, --rate=R : legacy rate (CCK, DSSS, OFDM)\n" \ +"\t-h M, --ht=M : HT MCS index [0-23]\n" \ +"\t-v M[xS], --vht=M[xS] : VHT MCS index M [0-9],\n" \ +"\t : and optionally Nss S [1-8], eg. 5x2 is MCS=5, Nss=2\n" \ +"\t-c cM[sS] : VHT (c notation) MCS index M [0-9],\n" \ +"\t : and optionally Nss S [1-8], eg. c5s2 is MCS=5, Nss=2\n" \ +"\t-s S, --ss=S : VHT Nss [1-8], number of spatial streams, default 1.\n" \ +"\t : Only used with -v/--vht when MxS format is not used\n" \ +"\t-x T, --exp=T : Tx Expansion, number of tx chains (NTx) beyond the minimum\n" \ +"\t : required for the space-time-streams, exp = NTx - Nsts\n" \ +"\t--stbc : Use STBC expansion, otherwise no STBC\n" \ +"\t-l, --ldpc : Use LDPC encoding, otherwise no LDPC\n" \ +"\t-g, --sgi : SGI, Short Guard Interval, otherwise standard GI\n" \ +"\t-b, --bandwidth : transmit bandwidth MHz; 20, 40, 80" + +#define RATE_5G_USAGE \ +"\tEither \"auto\", or a simple OFDM rate value:\n" \ +"\t6 9 12 18 24 36 48 54\n\n" \ +"\tOr options to specify legacy OFDM, HT, or VHT rate:\n" \ +"\t-r R, --rate=R : legacy OFDM rate\n" \ +"\t-h M, --ht=M : HT MCS index [0-23]\n" \ +"\t-v M[xS], --vht=M[xS] : VHT MCS index M [0-9],\n" \ +"\t : and optionally Nss S [1-8], eg. 5x2 is MCS=5, Nss=2\n" \ +"\t-c cM[sS] : VHT (c notation) MCS index M [0-9],\n" \ +"\t : and optionally Nss S [1-8], eg. c5s2 is MCS=5, Nss=2\n" \ +"\t-s S, --ss=S : VHT Nss [1-8], number of spatial streams, default 1.\n" \ +"\t : Only used with -v/--vht when MxS format is not used\n" \ +"\t-x T, --exp=T : Tx Expansion, number of tx chains (NTx) beyond the minimum\n" \ +"\t : required for the space-time-streams, exp = NTx - Nsts\n" \ +"\t--stbc : Use STBC expansion, otherwise no STBC\n" \ +"\t-l, --ldpc : Use LDPC encoding, otherwise no LDPC\n" \ +"\t-g, --sgi : SGI, Short Guard Interval, otherwise standard GI\n" \ +"\t-b, --bandwidth : transmit bandwidth MHz; 20, 40, 80" + +#define MONITOR_PROMISC_LEVEL_USAGE \ +"\tUsage: wl monitor_promisc_level [<bitmap> | <+|-name>]\n" \ +"\tbitmap values and corresponding name are the following:\n" \ +"\tArgs:\n" \ +"\t\tbit:0:promisc: " \ +"When set, address filter accepts all received frames." \ +"When cleared, the address filter accepts only those frames " \ +"that match the BSSID or local MAC address\n" \ +"\t\tbit:1:ctrl: " \ +"When set, the RX filter accepts all received control frames " \ +"that are accepted by the address filter. " \ +"When cleared, the RX filter rejects all control frames other " \ +"than PS poll frames." \ +"\t\tbit:3:fcs: " \ +"When set, the RX filter forwards received frames with FCS " \ +"errors to the driver." \ +"When cleared, frames with FCS errors are discarded.\n\n" \ +"\tExample: wl monitor_promisc_level +promisc\n" \ +"\tExample: wl monitor_promisc_level 0x2\n" \ +"\tExample: wl monitor_promisc_level 0" + +#define WDS_TYPE_USAGE \ +"\tUsage: wl wds_type -i <ifname>\n" \ +"\tifname is the name of the interface to query the type.\n" \ +"\tReturn values:\n" \ +"\t\t0:The interface type is neither WDS nor DWDS.\n" \ +"\t\t1:The interface is WDS type.\n" \ +"\t\t2:The interface is DWDS type.\n" + +/* the default behavior is batching in driver, + * to indicate client batching, users should specify --interactive and --clientbatch + */ +static bool batch_in_client; + +/* If the new command needs to be part of 'wc.exe' tool used for WMM, + * be sure to modify wc_cmds[] array as well + * + * If you add a command, please update wlu_cmd.c cmd2cat to categorize the command. + */ +cmd_t wl_cmds[] = { +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "ver", wl_version, -1, -1, + "get version information" }, + { "cmds", wl_list, -1, -1, + "generate a short list of available commands"}, +#endif + { "up", wl_void, -1, WLC_UP, + "reinitialize and mark adapter up (operational)" }, + { "down", wl_void, -1, WLC_DOWN, + "reset and mark adapter down (disabled)" }, +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "out", wl_out, -1, WLC_OUT, + "mark adapter down but do not reset hardware(disabled)\n" + "\tOn dualband cards, cards must be bandlocked before use."}, + { "clk", wl_int, WLC_GET_CLK, WLC_SET_CLK, + "set board clock state. return error for set_clk attempt if the driver is not down\n" + "\t0: clock off\n" + "\t1: clock on" }, + { "restart", wl_void, -1, WLC_RESTART, + "Restart driver. Driver must already be down."}, + { "reboot", wl_void, -1, WLC_REBOOT, + "Reboot platform"}, + { "radio", wl_radio, WLC_GET_RADIO, WLC_SET_RADIO, + "Set the radio on or off.\n" + "\t\"on\" or \"off\"" }, + { "dump", wlu_dump, WLC_GET_VAR, -1, + "Give suboption \"list\" to list various suboptions" }, + { "ol_stats", wlu_offloads_stats, WLC_GET_VAR, -1, + "Give suboption \"list\" to list various suboptions" }, + { "ol_eventlog", wlu_offloads_stats, WLC_GET_VAR, -1, + "Give suboption \"list\" to list various suboptions" }, + { "ol_cons", wlu_offloads_stats, WLC_GET_VAR, WLC_SET_VAR, + "Display the ARM console or issue a command to the ARM console\n" + " Usage: ol_cons [<cmd>]\n" + "\t\"?\" - Display the list of active console commands" + }, + { "ol_wowl_cons", wlu_offloads_stats, WLC_GET_VAR, -1, + "Give suboption \"list\" to list various suboptions" }, + { "ol_clr", wlu_offloads_stats, WLC_GET_VAR, -1, + "Give suboption \"list\" to list various suboptions" }, + { "srclear", wlu_srwrite, -1, WLC_SET_SROM, + "Clears first 'len' bytes of the srom, len in decimal or hex\n" + "\tUsage: srclear <len>" }, + { "srdump", wlu_srdump, WLC_GET_SROM, -1, + "print contents of SPROM to stdout" }, + { "srwrite", wlu_srwrite, -1, WLC_SET_SROM, + "Write the srom: srwrite byteoffset value" }, + { "srcrc", wlu_srwrite, WLC_GET_SROM, -1, + "Get the CRC for input binary file" }, + { "ciswrite", wlu_ciswrite, -1, WLC_SET_VAR, + "Write specified <file> to the SDIO CIS source (either SROM or OTP)"}, + { "cisupdate", wlu_cisupdate, -1, WLC_SET_VAR, + "Write a hex byte stream to specified byte offset to the CIS source (either SROM or OTP)\n" + "--preview option allows you to review the update without committing it\n" + "\t<byte offset> <hex byte stream> [--preview]" }, + { "cisdump", wlu_cisdump, WLC_GET_VAR, -1, + "Display the content of the SDIO CIS source\n" + "\t-b <file> -- also write raw bytes to <file>\n" + "\t<len> -- optional count of bytes to display (must be even)"}, + { "cis_source", wl_varint, WLC_GET_VAR, -1, + "Display which source is used for the SDIO CIS"}, + { "cisconvert", wlu_srvar, -1, -1, + "Print CIS tuple for given name=value pair" }, + { "rdvar", wlu_srvar, WLC_GET_SROM, -1, + "Read a named variable to the srom" }, + { "wrvar", wlu_srvar, WLC_GET_SROM, WLC_SET_SROM, + "Write a named variable to the srom" }, + { "nvram_source", wl_nvsource, WLC_GET_VAR, -1, + "Display which source is used for nvram"}, + { "nvram_dump", wl_nvdump, WLC_NVRAM_DUMP, -1, + "print nvram variables to stdout" }, + { "nvset", wl_nvset, -1, WLC_NVRAM_SET, + "set an nvram variable\n" + "\tname=value (no spaces around \'=\')" }, + { "nvget", wl_nvget, WLC_NVRAM_GET, -1, + "get the value of an nvram variable" }, + { "nvram_get", wl_nvget, WLC_NVRAM_GET, -1, + "get the value of an nvram variable" }, + { "revinfo", wl_revinfo, WLC_GET_REVINFO, -1, + "get hardware revision information" }, + { "customvar1", wl_var_getinthex, -1, -1, + "print the value of customvar1 in hex format" }, + { "msglevel", wl_msglevel, WLC_GET_VAR, WLC_SET_VAR, + "set driver console debugging message bitvector\n" + "\ttype \'wl msglevel ?\' for values" }, + { "phymsglevel", wl_phymsglevel, WLC_GET_VAR, WLC_SET_VAR, + "set phy debugging message bitvector\n" + "\ttype \'wl phymsglevel ?\' for values" }, + { "PM", wl_int, WLC_GET_PM, WLC_SET_PM, + "set driver power management mode:\n" + "\t0: CAM (constantly awake)\n" + "\t1: PS (power-save)\n" + "\t2: FAST PS mode" }, + { "wake", wl_int, WLC_GET_WAKE, WLC_SET_WAKE, + "set driver power-save mode sleep state:\n" + "\t0: core-managed\n" + "\t1: awake" }, + { "promisc", wl_int, WLC_GET_PROMISC, WLC_SET_PROMISC, + "set promiscuous mode ethernet address reception\n" + "\t0 - disable\n" + "\t1 - enable" }, + { "monitor", wl_int, WLC_GET_MONITOR, WLC_SET_MONITOR, + "set monitor mode\n" + "\t0 - disable\n" + "\t1 - enable active monitor mode (interface still operates)" }, + { "frag", wl_print_deprecate, -1, -1, "Deprecated. Use fragthresh." }, + { "rts", wl_print_deprecate, -1, -1, "Deprecated. Use rtsthresh." }, + { "cwmin", wl_int, WLC_GET_CWMIN, WLC_SET_CWMIN, + "Set the cwmin. (integer [1, 255])" }, + { "cwmax", wl_int, WLC_GET_CWMAX, WLC_SET_CWMAX, + "Set the cwmax. (integer [256, 2047])" }, + { "srl", wl_int, WLC_GET_SRL, WLC_SET_SRL, + "Set the short retry limit. (integer [1, 255])" }, + { "lrl", wl_int, WLC_GET_LRL, WLC_SET_LRL, + "Set the long retry limit. (integer [1, 255])" }, + { "rate", wl_rate_mrate, WLC_GET_RATE, -1, + "force a fixed rate:\n" + "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n" + "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n" + "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n" + "\t-1 (default) means automatically determine the best rate" }, + { "mrate", wl_rate_mrate, -1, -1, /* Deprecated. Use "bg_mrate" or "a_mrate" */ + "force a fixed multicast rate:\n" + "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n" + "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n" + "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n" + "\t-1 (default) means automatically determine the best rate" }, + { "a_rate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR, + "force a fixed rate for the A PHY:\n" + "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n" + "\t-1 (default) means automatically determine the best rate" }, + { "a_mrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR, + "force a fixed multicast rate for the A PHY:\n" + "\tvalid values for 802.11a are (6, 9, 12, 18, 24, 36, 48, 54)\n" + "\t-1 (default) means automatically determine the best rate" }, + { "bg_rate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR, + "force a fixed rate for the B/G PHY:\n" + "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n" + "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n" + "\t-1 (default) means automatically determine the best rate" }, + { "bg_mrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR, + "force a fixed multicast rate for the B/G PHY:\n" + "\tvalid values for 802.11b are (1, 2, 5.5, 11)\n" + "\tvalid values for 802.11g are (1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 48, 54)\n" + "\t-1 (default) means automatically determine the best rate" }, + { "2g_rate", wl_rate, WLC_GET_VAR, WLC_SET_VAR, + "Force a fixed rate for data frames in the 2.4G band:\n\n" + RATE_2G_USAGE + }, + { "2g_mrate", wl_rate, WLC_GET_VAR, WLC_SET_VAR, + "Force a fixed rate for mulitcast/broadcast data frames in the 2.4G band:\n\n" + RATE_2G_USAGE + }, + { "5g_rate", wl_rate, WLC_GET_VAR, WLC_SET_VAR, + "Force a fixed rate for data frames in the 5G band:\n\n" + RATE_5G_USAGE + }, + { "5g_mrate", wl_rate, WLC_GET_VAR, WLC_SET_VAR, + "Force a fixed rate for mulitcast/broadcast data frames in the 5G band:\n\n" + RATE_5G_USAGE + }, + { "infra", wl_int, WLC_GET_INFRA, WLC_SET_INFRA, + "Set Infrastructure mode: 0 (IBSS) or 1 (Infra BSS)" }, + { "ap", wl_int, WLC_GET_AP, WLC_SET_AP, + "Set AP mode: 0 (STA) or 1 (AP)" }, + { "bssid", wl_bssid, WLC_GET_BSSID, -1, + "Get the BSSID value, error if STA and not associated"}, + { "bssmax", wl_bss_max, WLC_GET_VAR, -1, + "get number of BSSes " }, + { "bw_cap", wl_bw_cap, WLC_GET_VAR, WLC_SET_VAR, + "Get/set the per-band bandwidth.\n" + "Usage: wl bw_cap <2g|5g> [<cap>]\n" + "\t2g|5g - Band: 2.4GHz or 5GHz respectively\n" + "cap:\n" + "\t0x1 - 20MHz\n" + "\t0x3 - 20/40MHz\n" + "\t0x7 - 20/40/80MHz\n" + "\t0xff - Unrestricted" }, +#endif + { "channel", wl_channel, WLC_GET_CHANNEL, WLC_SET_CHANNEL, + "Set the channel:\n" + "\tvalid channels for 802.11b/g (2.4GHz band) are 1 through 14\n" + "\tvalid channels for 802.11a (5 GHz band) are:\n" + "\t\t36, 40, 44, 48, 52, 56, 60, 64,\n" + "\t\t100, 104, 108, 112, 116,120, 124, 128, 132, 136, 140,\n" + "\t\t149, 153, 157, 161,\n" + "\t\t184, 188, 192, 196, 200, 204, 208, 212, 216"}, +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "cur_mcsset", wl_cur_mcsset, WLC_GET_VAR, -1, + "Get the current mcs set" + }, + { "clmver", wl_var_getandprintstr, WLC_GET_VAR, -1, + "Get version information for CLM data and tools"}, + { "roam_channels_in_cache", wl_dump_chanspecs, WLC_GET_VAR, -1, + "Get a list of channels in roam cache" }, + { "roam_channels_in_hotlist", wl_dump_chanspecs, WLC_GET_VAR, -1, + "Get a list of channels in roam hot channel list" }, + { "chanspecs", wl_dump_chanspecs, WLC_GET_VAR, -1, + "Get all the valid chanspecs (default: all within current locale):\n" + "\t-b band (5(a) or 2(b/g))\n" + "\t-w bandwidth, 20, 40 or 80\n" + "\t[-c country_abbrev]" + }, + { "chanspecs_defset", wl_dump_chanspecs_defset, WLC_GET_VAR, -1, + "Get default chanspecs for current driver settings (default: all within current locale)" + }, + { "chanspec", wl_chanspec, WLC_GET_VAR, WLC_SET_VAR, + "Set current or configured channel:\n" + "\t20MHz : [2g|5g]<channel>[/20]\n" + "\t40MHz : [2g|5g]<channel>/40[u,l]\n" + "\t80MHz : [5g]<channel>/80\n" + "\toptional band 2g or 5g, default to 2g if channel <= 14\n" + "\tchannel number (0-200)\n" + "\tbandwidth, 20, 40, or 80, default 20\n" + "\tprimary sideband for 40MHz on 2g, l=lower, u=upper\n" + "OR Set channel with legacy format:\n" + "\t-c channel number (0-224)\n" + "\t-b band (5(a) or 2(b/g))\n" + "\t-w bandwidth 20 or 40\n" + "\t-s ctl sideband, -1=lower, 0=none, 1=upper"}, + { "rclass", wl_rclass, WLC_GET_VAR, -1, + "Get operation class:\n" + "\t chanspec \n"}, + { "dfs_channel_forced", wl_chanspec, WLC_GET_VAR, WLC_SET_VAR, + "Set <channel>[a,b][n][u,l]\n" + "\tchannel number (0-224)\n" + "\tband a=5G, b=2G, default to 2G if channel <= 14\n" + "\tbandwidth, n=10, non for 20 & 40\n" + "\tctl sideband, l=lower, u=upper"}, + { "tssi", wl_tssi, WLC_GET_TSSI, -1, + "Get the tssi value from radio" }, + { "txpwr", wl_txpwr, -1, -1, /* Deprecated. Use "txpwr1" */ + "Set tx power in milliwatts. Range [1, 84]." }, + { "txpwr1", wl_txpwr1, WLC_GET_VAR, WLC_SET_VAR, + "Set tx power in in various units. Choose one of (default: dbm): \n" + "\t-d dbm units\n" + "\t-q quarter dbm units\n" + "\t-m milliwatt units\n" + "Can be combined with:\n" + "\t-o turn on override to disable regulatory and other limitations\n" + "Use wl txpwr -1 to restore defaults"}, + { "txpathpwr", wl_int, WLC_GET_TX_PATH_PWR, WLC_SET_TX_PATH_PWR, + "Turn the tx path power on or off on 2050 radios" }, + { "txpwrlimit", wl_get_txpwr_limit, WLC_CURRENT_PWR, -1, + "Return current tx power limit" }, + { "powerindex", wl_int, WLC_GET_PWRIDX, WLC_SET_PWRIDX, + "Set the transmit power for A band(0-63).\n" + "\t-1 - default value" }, + { "atten", wl_atten, WLC_GET_ATTEN, WLC_SET_ATTEN, + "Set the transmit attenuation for B band. Args: bb radio txctl1.\n" + "\tauto to revert to automatic control\n" + "\tmanual to supspend automatic control" }, + { "phyreg", wl_reg, WLC_GET_PHYREG, WLC_SET_PHYREG, + "Get/Set a phy register:\n" + "\toffset [ value ] [ band ]" }, + { "radioreg", wl_reg, WLC_GET_RADIOREG, WLC_SET_RADIOREG, + "Get/Set a radio register:\n" + "\toffset [ value ] [ band/core ]\n" + "HTPHY:\n" + "\tGet a radio register: wl radioreg [ offset ] [ cr0/cr1/cr2 ]\n" + "\tSet a radio register: wl radioreg [ offset ] [ value ] [ cr0/cr1/cr2/all ]\n" + "ACPHY:\n" + "\tGet a radio register: wl radioreg [ offset ] [ cr0/cr1/cr2/pll ]\n" + "\tSet a radio register: wl radioreg [ offset ] [ value ] [ cr0/cr1/cr2/pll/all ]"}, + { "ucflags", wl_reg, WLC_GET_UCFLAGS, WLC_SET_UCFLAGS, + "Get/Set ucode flags 1, 2, 3(16 bits each)\n" + "\toffset [ value ] [ band ]" }, + { "shmem", wl_reg, WLC_GET_SHMEM, WLC_SET_SHMEM, + "Get/Set a shared memory location:\n" + "\toffset [ value ] [band ]" }, + { "macreg", wl_macreg, WLC_R_REG, WLC_W_REG, + "Get/Set any mac registers(include IHR and SB):\n" + "\tmacreg offset size[2,4] [ value ] [ band ]" }, + { "ucantdiv", wl_int, WLC_GET_UCANTDIV, WLC_SET_UCANTDIV, + "Enable/disable ucode antenna diversity (1/0 or on/off)" }, + { "gpioout", wl_gpioout, -1, -1, + "Set any GPIO pins to any value. Use with caution as GPIOs would be " + "assigned to chipcommon\n" + "\tUsage: gpiomask gpioval"}, + + { "devpath", wl_devpath, WLC_GET_VAR, -1, + "print device path" }, + + { "pcieserdesreg", wlu_reg3args, WLC_GET_VAR, WLC_SET_VAR, + "g/set SERDES registers: dev offset [val]"}, + { "ampdu_activate_test", wl_ampdu_activate_test, -1, WLC_SET_VAR, + "actiate" }, + /* nphy parameter setting is internal only for now */ + { "ampdu_tid", wl_ampdu_tid, WLC_GET_VAR, WLC_SET_VAR, + "enable/disable per-tid ampdu; usage: wl ampdu_tid <tid> [0/1]" }, + { "ampdu_retry_limit_tid", wl_ampdu_retry_limit_tid, WLC_GET_VAR, WLC_SET_VAR, + "Set per-tid ampdu retry limit; usage: wl ampdu_retry_limit_tid <tid> [0~31]" }, + { "ampdu_rr_retry_limit_tid", wl_ampdu_rr_retry_limit_tid, WLC_GET_VAR, WLC_SET_VAR, + "Set per-tid ampdu regular rate retry limit; usage: " + "wl ampdu_rr_retry_limit_tid <tid> [0~31]" }, + { "ampdu_send_addba", wl_ampdu_send_addba, WLC_GET_VAR, WLC_SET_VAR, + "send addba to specified ea-tid; usage: wl ampdu_send_addba <tid> <ea>" }, + { "ampdu_send_delba", wl_ampdu_send_delba, WLC_GET_VAR, WLC_SET_VAR, + "send delba to specified ea-tid; usage: wl ampdu_send_delba <tid> <ea>" }, + { "ampdu_clear_dump", wl_var_void, -1, WLC_SET_VAR, + "clear ampdu counters"}, + { "ampdu_txq_prof_start", wl_var_void, -1, WLC_SET_VAR, + "start sample txq profiling data"}, + { "ampdu_txq_prof_dump", wl_var_void, -1, WLC_SET_VAR, + "show txq histogram"}, + { "ampdu_txq_ss", wl_var_void, -1, WLC_SET_VAR, + "take txq snapshot"}, + { "dpt_deny", wl_dpt_deny, WLC_GET_VAR, WLC_SET_VAR, + "adds/removes ea to dpt deny list\n" + "\tusage: wl dpt_deny <add,remove> <ea>" }, + { "dpt_endpoint", wl_dpt_endpoint, WLC_GET_VAR, WLC_SET_VAR, + "creates/updates/deletes dpt endpoint for ea\n" + "\tusage: wl dpt_endpoint <create, update, delete> <ea>" }, + { "dpt_pmk", wl_dpt_pmk, -1, WLC_SET_VAR, + "sets DPT pre-shared key" }, + { "dpt_fname", wl_dpt_fname, WLC_GET_VAR, WLC_SET_VAR, + "sets/gets DPT friendly name" }, + { "dpt_list", wl_dpt_list, WLC_GET_VAR, -1, + "gets status of all dpt peers" }, +#ifdef WLBTAMP + { "HCI_cmd", wl_HCI_cmd, WLC_GET_VAR, WLC_SET_VAR, + "carries HCI commands to the driver\n" + "\tusage: wl HCI_cmd <command> <args>" }, + { "HCI_ACL_data", wl_HCI_ACL_data, WLC_GET_VAR, WLC_SET_VAR, + "carries HCI ACL data packet to the driver\n" + "\tusage: wl HCI_ACL_data <logical link handle> <data>" }, + { "btamp_statelog", wl_get_btamp_log, WLC_GET_VAR, WLC_SET_VAR, + "Return state transistion log of BTAMP" }, +#endif /* WLBTAMP */ + { "actframe", wl_actframe, -1, WLC_SET_VAR, + "Send a Vendor specific Action frame to a channel\n" + "\tusage: wl actframe <Dest Mac Addr> <data> channel dwell-time <BSSID>" }, + { "antdiv", wl_int, WLC_GET_ANTDIV, WLC_SET_ANTDIV, + "Set antenna diversity for rx\n" + "\t0 - force use of antenna 0\n" + "\t1 - force use of antenna 1\n" + "\t3 - automatic selection of antenna diversity" }, + { "txant", wl_int, WLC_GET_TXANT, WLC_SET_TXANT, + "Set the transmit antenna\n" + "\t0 - force use of antenna 0\n" + "\t1 - force use of antenna 1\n" + "\t3 - use the RX antenna selection that was in force during\n" + "\t the most recently received good PLCP header" }, + { "plcphdr", wl_plcphdr, WLC_GET_PLCPHDR, WLC_SET_PLCPHDR, + "Set the plcp header.\n" + "\t\"long\" or \"auto\" or \"debug\"" }, + { "phytype", wl_int, WLC_GET_PHYTYPE, -1, + "Get phy type" }, + { "rateparam", wl_rateparam, -1, WLC_SET_RATE_PARAMS, + "set driver rate selection tunables\n" + "\targ 1: tunable id\n" + "\targ 2: tunable value" }, + { "wepstatus", wl_wepstatus, -1, -1, /* Deprecated. Use "wsec" */ + "Set or Get WEP status\n" + "\twepstatus [on|off]" }, + { "primary_key", wl_primary_key, WLC_GET_KEY_PRIMARY, WLC_SET_KEY_PRIMARY, + "Set or get index of primary key" }, + { "addwep", wl_addwep, -1, WLC_SET_KEY, + "Set an encryption key. The key must be 5, 13 or 16 bytes long, or\n" + "\t10, 26, 32, or 64 hex digits long. The encryption algorithm is\n" + "\tautomatically selected based on the key size. keytype is accepted\n" + "\tonly when key length is 16 bytes/32 hex digits and specifies\n" + "\twhether AES-OCB or AES-CCM encryption is used. Default is ccm.\n" + "\tWAPI is selected if key len is 32 and arguments contain wapi.\n" + "\taddwep <keyindex> <keydata> [ocb | ccm | wapi] [notx] [xx:xx:xx:xx:xx:xx]" }, + { "rmwep", wl_rmwep, -1, WLC_SET_KEY, + "Remove the encryption key at the specified key index." }, + { "keys", wl_keys, WLC_GET_KEY, -1, + "Prints a list of the current WEP keys" }, + { "tsc", wl_tsc, WLC_GET_KEY_SEQ, -1, + "Print Tx Sequence Couter for key at specified key index." }, + { "wsec_test", wl_wsec_test, -1, WLC_SET_WSEC_TEST, + "Generate wsec errors\n" + "\twsec_test <test_type> <keyindex|xx:xx:xx:xx:xx:xx>\n" + "\ttype \'wl wsec_test ?\' for test_types" }, + { "tkip_countermeasures", wl_int, -1, WLC_TKIP_COUNTERMEASURES, + "Enable or disable TKIP countermeasures (TKIP-enabled AP only)\n" + "\t0 - disable\n" + "\t1 - enable" }, + { "wsec_restrict", wl_bsscfg_int, WLC_GET_WEP_RESTRICT, WLC_SET_WEP_RESTRICT, + "Drop unencrypted packets if WSEC is enabled\n" + "\t0 - disable\n" + "\t1 - enable" }, + { "eap", wl_int, WLC_GET_EAP_RESTRICT, WLC_SET_EAP_RESTRICT, + "restrict traffic to 802.1X packets until 802.1X authorization succeeds\n" + "\t0 - disable\n" + "\t1 - enable" }, + { "cur_etheraddr", wl_iov_mac, -1, -1, + "Get/set the current hw address" }, + { "perm_etheraddr", wl_iov_mac, -1, -1, + "Get the permanent address from NVRAM" }, + { "authorize", wl_mac, -1, WLC_SCB_AUTHORIZE, + "restrict traffic to 802.1X packets until 802.1X authorization succeeds" }, + { "deauthorize", wl_mac, -1, WLC_SCB_DEAUTHORIZE, + "do not restrict traffic to 802.1X packets until 802.1X authorization succeeds" }, +#endif + { "deauthenticate", wl_deauth_rc, -1, WLC_SCB_DEAUTHENTICATE_FOR_REASON, + "deauthenticate a STA from the AP with optional reason code (AP ONLY)" }, + { "wsec", wl_wsec, WLC_GET_WSEC, WLC_SET_WSEC, + "wireless security bit vector\n" + "\t1 - WEP enabled\n" + "\t2 - TKIP enabled\n" + "\t4 - AES enabled\n" + "\t8 - WSEC in software\n" + "\t0x80 - FIPS enabled\n" + "\t0x100 - WAPI enabled\n" + "\t0x200 - MFP capable\n" + "\t0x400 - MFP required\n" + "\t0x800 - MFP use KDF (SHA256)" + }, +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "auth", wl_bsscfg_int, WLC_GET_AUTH, WLC_SET_AUTH, + "set/get 802.11 authentication type. 0 = OpenSystem, 1= SharedKey, 3=Open/Shared" }, +#endif + { "wpa_auth", wl_wpa_auth, WLC_GET_WPA_AUTH, WLC_SET_WPA_AUTH, + "Bitvector of WPA authorization modes:\n" + "\t1 WPA-NONE\n" + "\t2 WPA-802.1X/WPA-Professional\n" + "\t4 WPA-PSK/WPA-Personal\n" +#ifdef BCMCCX + "\t8 CCKM (WPA)\n" +#endif /* BCMCCX */ +#if defined(BCMCCX) + "\t16 CCKM (WPA2)\n" +#endif /* BCMCCX */ + "\t64 WPA2-802.1X/WPA2-Professional\n" + "\t128 WPA2-PSK/WPA2-Personal\n" + "\t0 disable WPA" + }, +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "wpa_cap", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR, + "set/get 802.11i RSN capabilities" }, + { "set_pmk", wl_set_pmk, -1, WLC_SET_WSEC_PMK, + "Set passphrase for PMK in driver-resident supplicant." }, + { "scan", wl_scan, -1, WLC_SCAN, + "Initiate a scan.\n" SCAN_USAGE + }, + { "roamscan_parms", wl_roamparms, WLC_GET_VAR, WLC_SET_VAR, + "set/get roam scan parameters\n" + "Use standard scan params syntax below," + "but only active/passive/home times, nprobes, and type are used.\n" + "All other values are silently discarded.\n" + SCAN_USAGE + }, + { "iscan_s", wl_iscan, -1, WLC_SET_VAR, + "Initiate an incremental scan.\n" SCAN_USAGE + }, + { "iscan_c", wl_iscan, -1, WLC_SET_VAR, + "Continue an incremental scan.\n" SCAN_USAGE + }, + { "scancache_clear", wl_var_void, -1, WLC_SET_VAR, + "clear the scan cache"}, + { "escan", wl_escan, -1, WLC_SET_VAR, + "Start an escan.\n" SCAN_USAGE + }, + { "escanabort", wl_escan, -1, WLC_SET_VAR, + "Abort an escan.\n" SCAN_USAGE + }, +#ifdef EXTENDED_SCAN + { "extdscan", wl_extdscan, -1, WLC_SET_VAR, + "Initiate an extended scan.\n" + "\tDefault to an active scan across all channels for any SSID.\n" + "\tOptional args: list of SSIDs to scan.\n" + "\tOptions:\n" + "\t-s S1 S2 S3, --ssid=S1 S2 S3\t\tSSIDs to scan, comma or space separated\n" + "\t-x x, --split_scan=ST\t[split_scan] scan type\n" + "\t-t ST, --scan_type=ST\t[background:0/forcedbackground:1/foreground:2] scan type\n" + "\t-n N, --nprobes=N\tnumber of probes per scanned channel, per SSID\n" + "\t-c L, --channels=L\tcomma or space separated list of channels to scan"}, +#endif + { "passive", wl_int, WLC_GET_PASSIVE_SCAN, WLC_SET_PASSIVE_SCAN, + "Puts scan engine into passive mode" }, + { "regulatory", wl_int, WLC_GET_REGULATORY, WLC_SET_REGULATORY, + "Get/Set regulatory domain mode (802.11d). Driver must be down." }, + { "spect", wl_spect, WLC_GET_SPECT_MANAGMENT, WLC_SET_SPECT_MANAGMENT, + "Get/Set 802.11h Spectrum Management mode.\n" + "\t0 - Off\n" + "\t1 - Loose interpretation of 11h spec - may join non-11h APs\n" + "\t2 - Strict interpretation of 11h spec - may not join non-11h APs\n" + "\t3 - Disable 11h and enable 11d\n" + "\t4 - Loose interpretation of 11h+d spec - may join non-11h APs" + }, + { "scanabort", wl_var_void, -1, WLC_SET_VAR, + "Abort a scan." }, + { "scanresults", wl_dump_networks, WLC_SCAN_RESULTS, -1, + "Return results from last scan." }, + { "iscanresults", wl_dump_networks, WLC_GET_VAR, -1, + "Return results from last iscan. Specify a buflen (max 8188)\n" + "\tto artificially limit the size of the results buffer.\n" + "\tiscanresults [buflen]"}, + { "assoc", wl_status, -1, -1, + "Print information about current network association.\n" + "\t(also known as \"status\")" }, +#endif + { "status", wl_status, -1, -1, + "Print information about current network association.\n" + "\t(also known as \"assoc\")" }, +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "disassoc", wl_void, -1, WLC_DISASSOC, + "Disassociate from the current BSS/IBSS." }, + { "chanlist", wl_print_deprecate, WLC_GET_VALID_CHANNELS, -1, + "Deprecated. Use channels." }, + { "channels", wl_dump_chanlist, WLC_GET_VALID_CHANNELS, -1, + "Return valid channels for the current settings." }, + { "channels_in_country", wl_channels_in_country, WLC_GET_CHANNELS_IN_COUNTRY, -1, + "Return valid channels for the country specified.\n" + "\tArg 1 is the country abbreviation\n" + "\tArg 2 is the band(a or b)"}, + { "curpower", wl_get_current_power, WLC_CURRENT_PWR, -1, + "Return current tx power settings.\n" + "\t-v, --verbose: display the power settings for every " + "rate even when every rate in a rate group has the same power." }, + { "txpwr_target_max", wl_get_txpwr_target_max, WLC_GET_VAR, -1, + "Return current max tx target power settings.\n" }, + { "curppr", wl_get_current_txppr, WLC_GET_VAR, -1, + "Return current tx power per rate offset."}, + { "txinstpwr", wl_get_instant_power, WLC_GET_VAR, -1, + "Return tx power based on instant TSSI "}, + { "scansuppress", wl_int, WLC_GET_SCANSUPPRESS, WLC_SET_SCANSUPPRESS, + "Suppress all scans for testing.\n" + "\t0 - allow scans\n" + "\t1 - suppress scans" }, + { "evm", wl_evm, -1, WLC_EVM, + "Start an EVM test on the given channel, or stop EVM test.\n" + "\tArg 1 is channel number 1-14, or \"off\" or 0 to stop the test.\n" + "\tArg 2 is optional rate (1, 2, 5.5 or 11)"}, + { "rateset", wl_rateset, WLC_GET_RATESET, WLC_SET_RATESET, + "Returns or sets the supported and basic rateset, (b) indicates basic\n" + "\tWith no args, returns the rateset. Args are\n" + "\trateset \"default\" | \"all\" | <arbitrary rateset> [-m|-v <list of mcs masks>]\n" + "\t\tdefault - driver defaults\n" + "\t\tall - all rates are basic rates\n" + "\t\tarbitrary rateset - list of rates\n" + "\tList of rates are in Mbps and each rate is optionally followed\n" + "\tby \"(b)\" or \"b\" for a Basic rate. Example: 1(b) 2b 5.5 11\n" + "\tAt least one rate must be Basic for a legal rateset.\n\n" + "\t-m sets HT rates (bitmasks, 00-ff). Least significant bit is MCS0.\n" + "\t example: 'rateset -m 0x3f 0x01' limits rates to MCS0-MCS5 and MCS8\n\n" + "\t-v sets VHT MCS values for each supported count of spatial streams.\n" + "\t example: 'rateset -v 3ff 1ff ff' limits vht rates to MCS 0-9 for 1 stream,\n" + "\t MCS 0-8 for 2 streams, and MCS 0-7 for 3 streams." + }, + { "default_rateset", wl_default_rateset, WLC_GET_VAR, -1, + "Returns supported rateset of given phy.\n" + "\tYou have to insert following Args\n" + "\t\tArg 1. Phy Type: have to be one of the following: " + "[a, b, g, n, lp, ssn, ht, lcn, lcn40, ac]\n" + "\t\tArg 2. Band Type: 2 for 2.4G or 5 for 5G\n" + "\t\tArg 3. CCK Only: 1 for CCK Only or 0 for CCK and OFDM rates\n" + "\t\tArg 4. Basic Rates: 1 for all rates WITH basic rates or " + "0 for all rates WITHOUT basic rates\n" + "\t\tArg 5. MCS Rates: 1 for all rates WITH MCS rates or " + "0 for all rates WITHOUT MCS rates\n" + "\t\tArg 6. Bandwidth: have to be one of the following: [10, 20, 40, 80, 160]\n" + "\t\tArg 7. TX/RX Stream: \"tx\" for TX streams or \"rx\" for RX streams\n" + "\t\tExample: PHY: AC, Band 2.4G, CCK rates only, With Basec rates, " + "WithOut MCS rates, BW: 40 and TX streams\n" + "\t\tInput: default_rateset ac 2 0 1 0 40 tx\n" + }, + { "roam_trigger", wl_band_elm, WLC_GET_ROAM_TRIGGER, WLC_SET_ROAM_TRIGGER, + "Get or Set the roam trigger RSSI threshold:\n" + "\tGet: roam_trigger [a|b]\n" + "\tSet: roam_trigger <integer> [a|b|all]\n" + "\tinteger - 0: default\n" + "\t 1: optimize bandwidth\n" + "\t 2: optimize distance\n" + "\t [-1, -99]: dBm trigger value"}, + { "roam_delta", wl_band_elm, WLC_GET_ROAM_DELTA, WLC_SET_ROAM_DELTA, + "Set the roam candidate qualification delta. roam_delta [integer [, a/b]]" }, + { "roam_scan_period", wl_int, WLC_GET_ROAM_SCAN_PERIOD, WLC_SET_ROAM_SCAN_PERIOD, + "Set the roam candidate qualification delta. (integer)" }, + { "suprates", wl_sup_rateset, WLC_GET_SUP_RATESET_OVERRIDE, WLC_SET_SUP_RATESET_OVERRIDE, + "Returns or sets the 11g override for the supported rateset\n" + "\tWith no args, returns the rateset. Args are a list of rates,\n" + "\tor 0 or -1 to specify an empty rateset to clear the override.\n" + "\tList of rates are in Mbps, example: 1 2 5.5 11"}, + { "scan_channel_time", wl_int, WLC_GET_SCAN_CHANNEL_TIME, WLC_SET_SCAN_CHANNEL_TIME, + "Get/Set scan channel time"}, + { "scan_unassoc_time", wl_int, WLC_GET_SCAN_UNASSOC_TIME, WLC_SET_SCAN_UNASSOC_TIME, + "Get/Set unassociated scan channel dwell time"}, + { "scan_home_time", wl_int, WLC_GET_SCAN_HOME_TIME, WLC_SET_SCAN_HOME_TIME, + "Get/Set scan home channel dwell time"}, + { "scan_passive_time", wl_int, WLC_GET_SCAN_PASSIVE_TIME, WLC_SET_SCAN_PASSIVE_TIME, + "Get/Set passive scan channel dwell time"}, + { "scan_nprobes", wl_int, WLC_GET_SCAN_NPROBES, WLC_SET_SCAN_NPROBES, + "Get/Set scan parameter for number of probes to use per channel scanned"}, + { "prb_resp_timeout", wl_int, WLC_GET_PRB_RESP_TIMEOUT, WLC_SET_PRB_RESP_TIMEOUT, + "Get/Set probe response timeout"}, + { "channel_qa", wl_int, WLC_GET_CHANNEL_QA, -1, + "Get last channel quality measurment"}, + { "channel_qa_start", wl_void, -1, WLC_START_CHANNEL_QA, + "Start a channel quality measurment"}, + { "country", wl_country, WLC_GET_COUNTRY, WLC_SET_COUNTRY, + "Select Country Code for driver operational region\n" + "\tFor simple country setting: wl country <country>\n" + "\tWhere <country> is either a long name or country code from ISO 3166; " + "for example \"Germany\" or \"DE\"\n" + "\n\tFor a specific built-in country definition: " + "wl country <built-in> [<advertised-country>]\n" + "\tWhere <built-in> is a country country code followed by '/' and " + "regulatory revision number.\n" + "\tFor example, \"US/3\".\n" + "\tAnd where <advertised-country> is either a long name or country code from ISO 3166.\n" + "\tIf <advertised-country> is omitted, it will be the same as the built-in country code.\n" + "\n\tUse 'wl country list [band(a or b)]' for the list of supported countries"}, + { "country_ie_override", wl_country_ie_override, WLC_GET_VAR, WLC_SET_VAR, + "To set/get country ie"}, + { "autocountry_default", wl_varstr, WLC_GET_VAR, WLC_SET_VAR, + "Select Country Code for use with Auto Contry Discovery"}, + { "join", wl_join, -1, -1, + "Join a specified network SSID.\n" + "\tUsage: join <ssid> [key <0-3>:xxxxx] [imode bss|ibss] " + "[amode open|shared|openshared|wpa|wpapsk|wpa2|wpa2psk|wpanone|ftpsk] [options]\n" + "\tOptions:\n" + "\t-b MAC, --bssid=MAC \tBSSID (xx:xx:xx:xx:xx:xx) to scan and join\n" + "\t-c CL, --chanspecs=CL \tchanspecs (comma or space separated list)\n" + "\tprescanned \tuses channel and bssid list from scanresults\n" + "\t-p, -passive: force passive assoc scan (useful for P2P)"}, +#endif + { "ssid", wl_ssid, WLC_GET_SSID, WLC_SET_SSID, + "Set or get a configuration's SSID.\n" + "\twl ssid [-C num]|[--cfg=num] [<ssid>]\n" + "\tIf the configuration index 'num' is not given, configuraion #0 is assumed and\n" + "\tsetting will initiate an assoication attempt if in infrastructure mode,\n" + "\tor join/creation of an IBSS if in IBSS mode,\n" + "\tor creation of a BSS if in AP mode."}, +#ifdef BUILD_FEATURE_WIFI_BCM_WL +#ifdef BCMCCX + { "leap", wl_leap, WLC_GET_LEAP_LIST, WLC_SET_LEAP_LIST, + "Set parameters for LEAP authentication\n" + "\tleap <ssid> <username> <password> [domain]" }, +#endif /* BCMCCX */ + { "mac", wl_maclist, WLC_GET_MACLIST, WLC_SET_MACLIST, + "Set or get the list of source MAC address matches.\n" + "\twl mac xx:xx:xx:xx:xx:xx [xx:xx:xx:xx:xx:xx ...]\n" + "\tTo Clear the list: wl mac none" }, + { "macmode", wl_int, WLC_GET_MACMODE, WLC_SET_MACMODE, + "Set the mode of the MAC list.\n" + "\t0 - Disable MAC address matching.\n" + "\t1 - Deny association to stations on the MAC list.\n" + "\t2 - Allow association to stations on the MAC list."}, + { "wds", wl_maclist, WLC_GET_WDSLIST, WLC_SET_WDSLIST, + "Set or get the list of WDS member MAC addresses.\n" + "\tSet using a space separated list of MAC addresses.\n" + "\twl wds xx:xx:xx:xx:xx:xx [xx:xx:xx:xx:xx:xx ...]" }, + { "lazywds", wl_int, WLC_GET_LAZYWDS, WLC_SET_LAZYWDS, + "Set or get \"lazy\" WDS mode (dynamically grant WDS membership to anyone)."}, + { "noise", wl_int, WLC_GET_PHY_NOISE, -1, + "Get noise (moving average) right after tx in dBm" }, + { "fqacurcy", wl_int, -1, WLC_FREQ_ACCURACY, + "Manufacturing test: set frequency accuracy mode.\n" + "\tfreqacuracy syntax is: fqacurcy <channel>\n" + "\tArg is channel number 1-14, or 0 to stop the test." }, + { "crsuprs", wl_int, -1, WLC_CARRIER_SUPPRESS, + "Manufacturing test: set carrier suppression mode.\n" + "\tcarriersuprs syntax is: crsuprs <channel>\n" + "\tArg is channel number 1-14, or 0 to stop the test." }, + { "longtrain", wl_int, -1, WLC_LONGTRAIN, + "Manufacturing test: set longtraining mode.\n" + "\tlongtrain syntax is: longtrain <channel>\n" + "\tArg is A band channel number or 0 to stop the test." }, + { "band", wl_band, WLC_GET_BAND, WLC_SET_BAND, + "Returns or sets the current band\n" + "\tauto - auto switch between available bands (default)\n" + "\ta - force use of 802.11a band\n" + "\tb - force use of 802.11b band" }, + { "bands", wl_bandlist, WLC_GET_BANDLIST, -1, + "Return the list of available 802.11 bands" }, + { "phylist", wl_phylist, WLC_GET_PHYLIST, -1, + "Return the list of available phytypes" }, + { "shortslot", wl_int, WLC_GET_SHORTSLOT, -1, + "Get current 11g Short Slot Timing mode. (0=long, 1=short)" }, + { "shortslot_override", wl_int, WLC_GET_SHORTSLOT_OVERRIDE, WLC_SET_SHORTSLOT_OVERRIDE, + "Get/Set 11g Short Slot Timing mode override. (-1=auto, 0=long, 1=short)" }, + { "shortslot_restrict", wl_int, WLC_GET_SHORTSLOT_RESTRICT, WLC_SET_SHORTSLOT_RESTRICT, + "Get/Set AP Restriction on associations for 11g Short Slot Timing capable STAs.\n" + "\t0 - Do not restrict association based on ShortSlot capability\n" + "\t1 - Restrict association to STAs with ShortSlot capability" }, + { "ignore_bcns", wl_int, WLC_GET_IGNORE_BCNS, WLC_SET_IGNORE_BCNS, + "AP only (G mode): Check for beacons without NONERP element" + "(0=Examine beacons, 1=Ignore beacons)" }, + { "pktcnt", wl_get_pktcnt, WLC_GET_PKTCNTS, -1, + "Get the summary of good and bad packets." }, + { "upgrade", wl_upgrade, -1, WLC_UPGRADE, + "Upgrade the firmware on an embedded device" }, + { "gmode", wl_gmode, WLC_GET_GMODE, WLC_SET_GMODE, + "Set the 54g Mode (LegacyB|Auto||GOnly|BDeferred|Performance|LRS)" }, + { "gmode_protection", wl_int, WLC_GET_GMODE_PROTECTION, -1, + "Get G protection mode. (0=disabled, 1=enabled)" }, + { "gmode_protection_control", wl_int, WLC_GET_PROTECTION_CONTROL, + WLC_SET_PROTECTION_CONTROL, + "Get/Set 11g protection mode control alg." + "(0=always off, 1=monitor local association, 2=monitor overlapping BSS)" }, + { "gmode_protection_override", wl_int, WLC_GET_GMODE_PROTECTION_OVERRIDE, + WLC_SET_GMODE_PROTECTION_OVERRIDE, + "Get/Set 11g protection mode override. (-1=auto, 0=disable, 1=enable)" }, + { "protection_control", wl_int, WLC_GET_PROTECTION_CONTROL, + WLC_SET_PROTECTION_CONTROL, + "Get/Set protection mode control alg." + "(0=always off, 1=monitor local association, 2=monitor overlapping BSS)" }, + { "legacy_erp", wl_int, WLC_GET_LEGACY_ERP, WLC_SET_LEGACY_ERP, + "Get/Set 11g legacy ERP inclusion (0=disable, 1=enable)" }, + { "scb_timeout", wl_int, WLC_GET_SCB_TIMEOUT, WLC_SET_SCB_TIMEOUT, + "AP only: inactivity timeout value for authenticated stas" }, + { "assoclist", wl_maclist, WLC_GET_ASSOCLIST, -1, + "AP only: Get the list of associated MAC addresses."}, + { "isup", wl_int, WLC_GET_UP, -1, + "Get driver operational state (0=down, 1=up)"}, + { "rssi", wl_rssi, WLC_GET_RSSI, -1, + "Get the current RSSI val, for an AP you must specify the mac addr of the STA" }, + { "rssi_event", wl_rssi_event, WLC_GET_VAR, WLC_SET_VAR, + "Set parameters associated with RSSI event notification\n" + "\tusage: wl rssi_event <rate_limit> <rssi_levels>\n" + "\trate_limit: Number of events posted to application will be limited" + " to 1 per this rate limit. Set to 0 to disable rate limit.\n" + "\trssi_levels: Variable number of RSSI levels (maximum 8) " + " in increasing order (e.g. -85 -70 -60). An event will be posted" + " each time the RSSI of received beacons/packets crosses a level."}, + { "fasttimer", wl_print_deprecate, -1, -1, + "Deprecated. Use fast_timer."}, + { "slowtimer", wl_print_deprecate, -1, -1, + "Deprecated. Use slow_timer."}, + { "glacialtimer", wl_print_deprecate, -1, -1, + "Deprecated. Use glacial_timer."}, + { "radar", wl_int, WLC_GET_RADAR, WLC_SET_RADAR, + "Enable/Disable radar"}, + { "radarargs", wl_radar_args, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set Radar parameters in \n" + "\torder as version, npulses, ncontig, min_pw, max_pw, thresh0,\n" + "\tthresh1, blank, fmdemodcfg, npulses_lp, min_pw_lp, max_pw_lp,\n" + "\tmin_fm_lp, max_span_lp, min_deltat, max_deltat,\n" + "\tautocorr, st_level_time, t2_min, fra_pulse_err, npulses_fra,\n" + "\tnpulses_stg2, npulses_stg3, percal_mask, quant, \n" + "\tmin_burst_intv_lp, max_burst_intv_lp, nskip_rst_lp, max_pw_tol, feature_mask"}, + { "radarargs40", wl_radar_args, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set Radar parameters for 40Mhz channel in \n" + "\torder as version, npulses, ncontig, min_pw, max_pw, thresh0,\n" + "\tthresh1, blank, fmdemodcfg, npulses_lp, min_pw_lp, max_pw_lp,\n" + "\tmin_fm_lp, max_span_lp, min_deltat, max_deltat,\n" + "\tautocorr, st_level_time, t2_min, fra_pulse_err, npulses_fra,\n" + "\tnpulses_stg2, npulses_stg3, percal_mask, quant, \n" + "\tmin_burst_intv_lp, max_burst_intv_lp, nskip_rst_lp, max_pw_tol, feature_mask"}, + { "radarthrs", wl_radar_thrs, -1, WLC_SET_VAR, + "Set Radar threshold for both 20 & 40MHz & 80MHz BW:\n" + "\torder as thresh0_20_lo, thresh1_20_lo, thresh0_40_lo, thresh1_40_lo\n" + "\tthresh0_80_lo, thresh1_80_lo, thresh0_20_hi, thresh1_20_hi\n" + "\tthresh0_40_hi, thresh1_40_hi, thresh0_80_hi, thresh1_80_hi\n"}, + + { "dfs_status", wl_dfs_status, WLC_GET_VAR, -1, + "Get dfs status"}, + { "interference", wl_interfere, WLC_GET_INTERFERENCE_MODE, WLC_SET_INTERFERENCE_MODE, + "Get/Set interference mitigation mode. Choices are:\n" + "\t0 = none\n" + "\t1 = non wlan\n" + "\t2 = wlan manual\n" + "\t3 = wlan automatic\n" + "\t4 = wlan automatic with noise reduction"}, + { "interference_override", wl_interfere_override, + WLC_GET_INTERFERENCE_OVERRIDE_MODE, + WLC_SET_INTERFERENCE_OVERRIDE_MODE, + "Get/Set interference mitigation override. Choices are:\n" + "\t0 = no interference mitigation\n" + "\t1 = non wlan\n" + "\t2 = wlan manual\n" + "\t3 = wlan automatic\n" + "\t4 = wlan automatic with noise reduction\n" + "\t-1 = remove override, override disabled"}, + { "frameburst", wl_int, WLC_GET_FAKEFRAG, WLC_SET_FAKEFRAG, + "Disable/Enable frameburst mode" }, + { "pwr_percent", wl_int, WLC_GET_PWROUT_PERCENTAGE, WLC_SET_PWROUT_PERCENTAGE, + "Get/Set power output percentage"}, + { "toe", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Enable/Disable tcpip offload feature"}, + { "toe_ol", wl_offload_cmpnt, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set tcpip offload components"}, + { "toe_stats", wl_toe_stats, WLC_GET_VAR, -1, + "Display checksum offload statistics"}, + { "toe_stats_clear", wl_var_void, -1, WLC_SET_VAR, + "Clear checksum offload statistics"}, +#endif + { "arpoe", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Enable/Disable arp agent offload feature"}, +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "arp_ol", wl_offload_cmpnt, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set arp offload components"}, + { "arp_peerage", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set age of the arp entry in minutes"}, + { "arp_table_clear", wl_var_void, -1, WLC_SET_VAR, + "Clear arp cache"}, +#ifdef WLOFFLD + { "ol_notify_bcn_ie", wl_ol_notify_bcn_ie, WLC_GET_VAR, WLC_SET_VAR, + "Enable/Disable IE ID notification"}, + { "ol_arp_hostip", wl_hostip, WLC_GET_VAR, WLC_SET_VAR, + "Add a host-ip address or display them"}, + { "ol_nd_hostip", wl_hostipv6, WLC_GET_VAR, WLC_SET_VAR, + "Add a local host-ipv6 address or display them"}, +#endif + { "arp_hostip", wl_hostip, WLC_GET_VAR, WLC_SET_VAR, + "Add a host-ip address or display them"}, + { "arp_hostip_clear", wl_var_void, -1, WLC_SET_VAR, + "Clear all host-ip addresses"}, + { "ns_hostip", wl_nshostip, WLC_GET_VAR, WLC_SET_VAR, + "Add a ns-ip address or display then"}, + { "ns_hostip_clear", wl_var_void, -1, WLC_SET_VAR, + "Clear all ns-ip addresses"}, + { "arp_stats", wl_arp_stats, WLC_GET_VAR, -1, + "Display ARP offload statistics"}, + { "arp_stats_clear", wl_var_void, -1, WLC_SET_VAR, + "Clear ARP offload statistics"}, + { "wet", wl_int, WLC_GET_WET, WLC_SET_WET, + "Get/Set wireless ethernet bridging mode"}, + { "bi", wl_int, WLC_GET_BCNPRD, WLC_SET_BCNPRD, + "Get/Set the beacon period (bi=beacon interval)"}, + { "dtim", wl_int, WLC_GET_DTIMPRD, WLC_SET_DTIMPRD, + "Get/Set DTIM"}, + { "wds_remote_mac", wl_mac, WLC_WDS_GET_REMOTE_HWADDR, -1, + "Get WDS link remote endpoint's MAC address"}, + { "wds_wpa_role_old", wl_wds_wpa_role_old, WLC_WDS_GET_WPA_SUP, -1, + "Get WDS link local endpoint's WPA role (old)"}, + { "wds_wpa_role", wl_wds_wpa_role, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set WDS link local endpoint's WPA role"}, + { "authe_sta_list", wl_maclist_1, WLC_GET_VAR, -1, + "Get authenticated sta mac address list"}, + { "autho_sta_list", wl_maclist_1, WLC_GET_VAR, -1, + "Get authorized sta mac address list"}, + { "measure_req", wl_measure_req, -1, WLC_MEASURE_REQUEST, + "Send an 802.11h measurement request.\n" + "\tUsage: wl measure_req <type> <target MAC addr>\n" + "\tMeasurement types are: TPC, Basic, CCA, RPI\n" + "\tTarget MAC addr format is xx:xx:xx:xx:xx:xx"}, + { "quiet", wl_send_quiet, -1, WLC_SEND_QUIET, + "Send an 802.11h quiet command.\n" + "\tUsage: wl quiet <TBTTs until start>, <duration (in TUs)>, <offset (in TUs)>"}, +#endif + { "csa", wl_send_csa, -1, WLC_SET_VAR, + "Send an 802.11h channel switch anouncement with chanspec:\n" + "\t<mode> <count> <channel>[a,b][n][u,l][frame type]\n" + "\tmode (0 or 1)\n" + "\tcount (0-254)\n" + "\tchannel format:\n" + "\t20MHz : [2g|5g]<channel>[/20]\n" + "\t40MHz : [2g|5g]<channel>/40[u,l]\n" + "\t80MHz : [5g]<channel>/80\n" + "\toptional band 2g or 5g, default to 2g if channel <= 14\n" + "\tchannel number (0-200)\n" + "\tbandwidth, 20, 40, or 80, default 20\n" + "\tprimary sideband for 40MHz on 2g, l=lower, u=upper\n" + "\tcsa frame type(optional), default is broadcast if not specified, u=unicast"}, +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "constraint", wl_int, -1, WLC_SEND_PWR_CONSTRAINT, + "Send an 802.11h Power Constraint IE\n" + "\tUsage: wl constraint 1-255 db"}, + { "rm_req", wl_rm_request, -1, WLC_SET_VAR, + "Request a radio measurement of type basic, cca, or rpi\n" + "\tspecify a series of measurement types each followed by options.\n" + "\texample: wl rm_req cca -c 1 -d 50 cca -c 6 cca -c 11\n" + "\tOptions:\n" + "\t-t n numeric token id for measurement set or measurement\n" + "\t-c n channel\n" + "\t-d n duration in TUs (1024 us)\n" + "\t-p parallel flag, measurement starts at the same time as previous\n" + "\n" + "\tEach measurement specified uses the same channel and duration as the\n" + "\tprevious unless a new channel or duration is specified."}, + { "rm_rep", wl_rm_report, WLC_GET_VAR, -1, + "Get current radio measurement report"}, + { "join_pref", wl_join_pref, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get join target preferences."}, + { "assoc_pref", wl_assoc_pref, WLC_GET_ASSOC_PREFER, WLC_SET_ASSOC_PREFER, + "Set/Get association preference.\n" + "Usage: wl assoc_pref [auto|a|b|g]"}, + { "wme", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Set WME (Wireless Multimedia Extensions) mode (0=off, 1=on, -1=auto)"}, + { "wme_ac", wl_wme_ac_req, WLC_GET_VAR, WLC_SET_VAR, + "wl wme_ac ap|sta [be|bk|vi|vo [ecwmax|ecwmin|txop|aifsn|acm <value>] ...]"}, + { "wme_apsd", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Set APSD (Automatic Power Save Delivery) mode on AP (0=off, 1=on)" }, + { "wme_apsd_sta", wl_wme_apsd_sta, WLC_GET_VAR, WLC_SET_VAR, + "Set APSD parameters on STA. Driver must be down.\n" + "Usage: wl wme_apsd_sta <max_sp_len> <be> <bk> <vi> <vo>\n" + " <max_sp_len>: number of frames per USP: 0 (all), 2, 4, or 6\n" + " <xx>: value 0 to disable, 1 to enable U-APSD per AC" }, + { "wme_dp", wl_wme_dp, WLC_GET_VAR, WLC_SET_VAR, + "Set AC queue discard policy.\n" + "Usage: wl wme_dp <be> <bk> <vi> <vo>\n" + " <xx>: value 0 for newest-first, 1 for oldest-first" }, + { "wme_counters", wl_wme_counters, WLC_GET_VAR, -1, + "print WMM stats" }, + { "wme_clear_counters", wl_var_void, -1, WLC_SET_VAR, + "clear WMM counters"}, + { "wme_tx_params", wme_tx_params, -1, -1, + "wl wme_tx_params [be|bk|vi|vo [short|sfb|long|lfb|max_rate <value>] ...]"}, + { "wme_maxbw_params", wme_maxbw_params, WLC_GET_VAR, WLC_SET_VAR, + "wl wme_maxbw_params [be|bk|vi|vo <value> ....]"}, + { "lifetime", wl_lifetime, WLC_GET_VAR, WLC_SET_VAR, + "Set Lifetime parameter (milliseconds) for each ac.\n" + "wl lifetime be|bk|vi|vo [<value>]"}, + { "reinit", wl_void, -1, WLC_INIT, + "Reinitialize device"}, + { "sta_info", wl_sta_info, WLC_GET_VAR, -1, + "wl sta_info <xx:xx:xx:xx:xx:xx>"}, + { "staprio", wl_staprio, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get sta priority \n" + "Usage: wl staprio <xx:xx:xx:xx:xx:xx> <prio> \n" + "<prio>: 0~3"}, + { "pktq_stats", wl_iov_pktqlog_params, WLC_GET_VAR, -1, + "Dumps packet queue log info for [C] common, [A] AMPDU, [N] NAR or [P] power save queues\n" + "A:, N: or P: are used to prefix a MAC address (a colon : separator is necessary),\n" + "or else C: is used alone. The '+' option after the colon gives more details.\n" + "Up to 4 parameters may be given, the common queue is default when no parameters\n" + "are supplied\n" + "Use '/<PREC>' as suffix to restrict to certain prec indices; multiple /<PREC>/<PREC>/..." + "can be used\n" + "Also, '//' as a suffix to the MAC address or 'C://' will enable automatic logging of\n" + "all prec as they are seen.\n" + "Full automatic operation is also possible with the shorthand\n" + "'A:' (or 'A://'), 'P:' (or 'P://') etc which scans through all known addresses for\n" + "those parameters that take a MAC address.\n" + "wl pktq_stats [C:[+]]|[A:[+]|P:[+]|N:[+]<xx:xx:xx:xx:xx:xx>][/<PREC>[/<PREC>]][//]..." }, + { "bs_data", wl_scb_bs_data, WLC_GET_VAR, -1, "Display per station band steering data\n" + "usage: bs_data [options]\n" + " options are:\n" + " -comma Use commas to separate values rather than blanks.\n" + " -tab Use <TAB> to separate values rather than blanks.\n" + " -raw Display raw values as received from driver.\n" + " -noidle Do not display idle stations\n" + " -noreset Do not reset counters after reading" }, + { "cap", wl_var_getandprintstr, WLC_GET_VAR, -1, "driver capabilities"}, + { "malloc_dump", wl_print_deprecate, -1, -1, "Deprecated. Folded under 'wl dump malloc"}, + { "chan_info", wl_chan_info, WLC_GET_VAR, -1, "channel info"}, + { "add_ie", wl_add_ie, -1, WLC_SET_VAR, + "Add a vendor proprietary IE to 802.11 management packets\n" + "Usage: wl add_ie <pktflag> length OUI hexdata\n" + "<pktflag>: Bit 0 - Beacons\n" + " Bit 1 - Probe Rsp\n" + " Bit 2 - Assoc/Reassoc Rsp\n" + " Bit 3 - Auth Rsp\n" + " Bit 4 - Probe Req\n" + " Bit 5 - Assoc/Reassoc Req\n" + "Example: wl add_ie 3 10 00:90:4C 0101050c121a03\n" + " to add this IE to beacons and probe responses" }, + { "del_ie", wl_del_ie, -1, WLC_SET_VAR, + "Delete a vendor proprietary IE from 802.11 management packets\n" + "Usage: wl del_ie <pktflag> length OUI hexdata\n" + "<pktflag>: Bit 0 - Beacons\n" + " Bit 1 - Probe Rsp\n" + " Bit 2 - Assoc/Reassoc Rsp\n" + " Bit 3 - Auth Rsp\n" + " Bit 4 - Probe Req\n" + " Bit 5 - Assoc/Reassoc Req\n" + "Example: wl del_ie 3 10 00:90:4C 0101050c121a03" }, + { "list_ie", _wl_list_ie, WLC_GET_VAR, -1, + "Dump the list of vendor proprietary IEs" }, + { "rand", wl_rand, WLC_GET_VAR, -1, + "Get a 2-byte Random Number from the MAC's PRNG\n" + "Usage: wl rand"}, + { "otpraw", wl_otpraw, WLC_GET_VAR, WLC_SET_VAR, + "Read/Write raw data to on-chip otp\n" + "Usage: wl otpraw <offset> <bits> [<data>]"}, + { "otpw", wl_otpw, -1, WLC_OTPW, + "Write an srom image to on-chip otp\n" + "Usage: wl otpw file"}, + { "nvotpw", wl_otpw, -1, WLC_NVOTPW, + "Write nvram to on-chip otp\n" + "Usage: wl nvotpw file"}, + { "bcmerrorstr", wl_var_getandprintstr, WLC_GET_VAR, -1, "errorstring"}, + { "freqtrack", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Set Frequency Tracking Mode (0=Auto, 1=On, 2=OFF)"}, + { "eventing", wl_eventbitvec, WLC_GET_VAR, WLC_SET_VAR, + "set/get hex filter bitmask for MAC event reporting up to application layer"}, + { "event_msgs", wl_eventbitvec, WLC_GET_VAR, WLC_SET_VAR, + "set/get hex filter bitmask for MAC event reporting via packet indications"}, + { "counters", wl_counters, WLC_GET_VAR, -1, + "Return driver counter values" }, + { "delta_stats_interval", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "set/get the delta statistics interval in seconds (0 to disable)"}, + { "delta_stats", wl_delta_stats, WLC_GET_VAR, -1, + "get the delta statistics for the last interval" }, + { "assoc_info", wl_assoc_info, WLC_GET_VAR, -1, + "Returns the assoc req and resp information [STA only]" }, + { "beacon_info", wl_management_info, WLC_GET_VAR, -1, + "Returns the 802.11 management frame beacon information\n" + "Usage: wl beacon_info [-f file] [-r]\n" + "\t-f Write beacon data to file\n" + "\t-r Raw hex dump of beacon data" }, + { "probe_resp_info", wl_management_info, WLC_GET_VAR, -1, + "Returns the 802.11 management frame probe response information\n" + "Usage: wl probe_resp_info [-f file] [-r]\n" + "\t-f Write probe response data to file\n" + "\t-r Raw hex dump of probe response data" }, + { "autochannel", wl_auto_channel_sel, WLC_GET_CHANNEL_SEL, WLC_START_CHANNEL_SEL, + "auto channel selection: \n" + "\t1 to issue a channel scanning;\n" + "\t2 to set chanspec based on the channel scan result;\n" + "\twithout argument to only show the chanspec selected; \n" + "\tssid must set to null before this process, RF must be up"}, + { "csscantimer", wl_int, WLC_GET_CS_SCAN_TIMER, WLC_SET_CS_SCAN_TIMER, + "auto channel scan timer in minutes (0 to disable)" }, + { "closed", wl_int, WLC_GET_CLOSED, WLC_SET_CLOSED, + "hides the network from active scans, 0 or 1.\n" + "\t0 is open, 1 is hide" }, + { "pmkid_info", wl_pmkid_info, WLC_GET_VAR, WLC_SET_VAR, + "Returns the pmkid table" }, +#endif + { "bss", wl_bsscfg_enable, WLC_GET_VAR, WLC_SET_VAR, + "set/get BSS enabled status: up/down"}, +#ifdef BUILD_FEATURE_WIFI_BCM_WL + { "closednet", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR, + "set/get BSS closed network attribute"}, + { "ap_isolate", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR, + "set/get AP isolation"}, + { "eap_restrict", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR, + "set/get EAP restriction"}, + { "diag", wl_diag, WLC_GET_VAR, -1, + "diag testindex(1-interrupt, 2-loopback, 3-memory, 4-led);" + " precede by 'wl down' and follow by 'wl up'" }, + { "reset_d11cnts", wl_var_void, -1, WLC_SET_VAR, + "reset 802.11 MIB counters"}, + { "staname", wl_varstr, WLC_GET_VAR, WLC_SET_VAR, + "get/set station name: \n" + "\tMaximum name length is 15 bytes"}, + { "apname", wl_varstr, WLC_GET_VAR, -1, + "get AP name"}, + { "otpdump", wl_var_setintandprintstr, WLC_GET_VAR, -1, + "Dump raw otp"}, + { "otpstat", wl_var_setintandprintstr, WLC_GET_VAR, -1, + "Dump OTP status"}, + { "nrate", wl_nrate, WLC_GET_VAR, WLC_SET_VAR, + "\"auto\" to clear a rate override, or:\n" + "-r legacy rate (CCK, OFDM)\n" + "-m HT MCS index\n" + "-s stf mode (0=SISO,1=CDD,2=STBC,3=SDM)\n" + "-w Override MCS only to support STA's with/without STBC capability"}, + { "mimo_txbw", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "get/set mimo txbw (2=20Mhz(lower), 3=20Mhz upper, 4=40Mhz)"}, + { "cac_addts", wl_cac, -1, WLC_SET_VAR, + "add TSPEC, error if STA is not associated or WME is not enabled\n" + "\targ: TSPEC parameter input list"}, + { "cac_delts", wl_cac, -1, WLC_SET_VAR, + "delete TSPEC, error if STA is not associated or WME is not enabled\n" + "\targ: TSINFO for the target tspec"}, + { "cac_delts_ea", wl_cac_delts_ea, -1, WLC_SET_VAR, + "delete TSPEC, error if STA is not associated or WME is not enabled\n" + "\targ1: Desired TSINFO for the target tspec\n" + "\targ2: Desired MAC address"}, + { "cac_tslist", wl_tslist, WLC_GET_VAR, -1, + "Get the list of TSINFO in driver\n" + "\teg. 'wl cac_tslist' get a list of TSINFO"}, + { "cac_tslist_ea", wl_tslist_ea, WLC_GET_VAR, -1, + "Get the list of TSINFO for given STA in driver\n" + "\teg. 'wl cac_tslist_ea ea' get a list of TSINFO"}, + { "cac_tspec", wl_tspec, WLC_GET_VAR, -1, + "Get specific TSPEC with matching TSINFO\n" + "\teg. 'wl cac_tspec 0xaa 0xbb 0xcc' where 0xaa 0xbb & 0xcc are TSINFO octets"}, + { "cac_tspec_ea", wl_tspec_ea, WLC_GET_VAR, -1, + "Get specific TSPEC for given STA with matching TSINFO\n" + "\teg. 'wl cac_tspec 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx'\n" + "\t where 0xaa 0xbb & 0xcc are TSINFO octets and xx is mac address"}, + + { "sd_cis", wl_var_getandprintstr, WLC_GET_VAR, -1, + "dump sdio CIS"}, + { "sd_devreg", wl_sd_reg, WLC_GET_VAR, WLC_SET_VAR, + "g/set device register across SDIO bus"}, + { "sd_drivestrength", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "g/set SDIO bus drive strenth in mA"}, + { "sd_hostreg", wl_sd_reg, WLC_GET_VAR, WLC_SET_VAR, + "g/set local controller register"}, + { "sd_blockmode", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "g/set blockmode"}, + { "sd_blocksize", wl_sd_blocksize, WLC_GET_VAR, WLC_SET_VAR, + "g/set block size for a function"}, + { "sd_ints", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "g/set client ints"}, + { "sd_dma", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "g/set dma usage"}, + { "sd_numints", wl_varint, WLC_GET_VAR, -1, + "number of device interrupts"}, + { "sd_numlocalints", wl_varint, WLC_GET_VAR, -1, + "number of non-device controller interrupts"}, + { "sd_divisor", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "set the divisor for SDIO clock generation"}, + { "sd_mode", wl_sd_mode, WLC_GET_VAR, WLC_SET_VAR, + "g/set SDIO bus mode (spi, sd1, sd4)"}, + { "sd_highspeed", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "set the high-speed clocking mode"}, + { "sd_msglevel", wl_sd_msglevel, WLC_GET_VAR, WLC_SET_VAR, + "g/set debug message level"}, + + { "overlay", wl_overlay, WLC_GET_VAR, WLC_SET_VAR, + "overlay virt_addr phy_addr size"}, + { "phy_txpwrindex", wl_phy_txpwrindex, WLC_GET_VAR, WLC_SET_VAR, + "usage: (set) phy_txpwrindex core0_idx core1_idx core2_idx core3_idx" + " (get) phy_txpwrindex, return format: core0_idx core1_idx core2_idx core3_idx" + "Set/Get txpwrindex" + }, + { "rssi_cal_freq_grp_2g", wl_rssi_cal_freq_grp_2g, WLC_GET_VAR, WLC_SET_VAR, + "usage: wl_rssi_cal_freq_grp_2g [chan_1_2,chan_3_4,...,chan_13_14]\n" + "Each of the variables like - chan_1_2 is a byte" + "Upper nibble of this byte is for chan1 and lower for chan2" + "MSB of the nibble tells if the channel is used for calibration" + "3 LSB's tell which group the channel falls in" + "Set/get rssi calibration frequency grouping" + }, + { "phy_rssi_gain_delta_2gb0", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_2gb0 [val0 val1 ....]\n" + "Number of arguments can be - " + "\t 8 for single core (4345 and 4350)" + "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)" + "\t 16 for both cores (4350)" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_2gb1", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_2gb1 [val0 val1 ....]\n" + "Number of arguments can be - " + "\t 8 for single core (4345 and 4350)" + "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)" + "\t 16 for both cores (4350)" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_2gb2", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_2gb2 [val0 val1 ....]\n" + "Number of arguments can be - " + "\t 8 for single core (4345 and 4350)" + "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)" + "\t 16 for both cores (4350)" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_2gb3", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_2gb3 [val0 val1 ....]\n" + "Number of arguments can be - " + "\t 8 for single core (4345 and 4350)" + "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)" + "\t 16 for both cores (4350)" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_2gb4", wl_phy_rssi_gain_delta_2g_sub, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_2gb4 [val0 val1 ....]\n" + "Number of arguments can be - " + "\t 8 for single core (4345 and 4350)" + "\t 9 by specifying core_num followed by 8 arguments (4345 and 4350)" + "\t 16 for both cores (4350)" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_2g", wl_phy_rssi_gain_delta_2g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_2g [val0 val1 ....]\n" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_5gl", wl_phy_rssi_gain_delta_5g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_5gl [val0 val1 ....]\n" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_5gml", wl_phy_rssi_gain_delta_5g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_5gml [val0 val1 ....]\n" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_5gmu", wl_phy_rssi_gain_delta_5g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_5gmu [val0 val1 ....]\n" + "Set/get rssi gain delta values" + }, + { "phy_rssi_gain_delta_5gh", wl_phy_rssi_gain_delta_5g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rssi_gain_delta_5gh [val0 val1 ....]\n" + "Set/get rssi gain delta values" + }, + { "phy_rxgainerr_2g", wl_phy_rxgainerr_2g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rxgainerr_2g [val0 val1 ....]\n" + "Set/get rx gain delta values" + }, + { "phy_rxgainerr_5gl", wl_phy_rxgainerr_5g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rxgainerr_5gl [val0 val1 ....]\n" + "Set/get rx gain delta values" + }, + { "phy_rxgainerr_5gm", wl_phy_rxgainerr_5g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rxgainerr_5gml [val0 val1 ....]\n" + "Set/get rx gain delta values" + }, + { "phy_rxgainerr_5gh", wl_phy_rxgainerr_5g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rxgainerr_5gmu [val0 val1 ....]\n" + "Set/get rx gain delta values" + }, + { "phy_rxgainerr_5gu", wl_phy_rxgainerr_5g, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_rxgainerr_5gh [val0 val1 ....]\n" + "Set/get rx gain delta values" + }, + { "phy_test_tssi", wl_test_tssi, WLC_GET_VAR, -1, + "wl phy_test_tssi val"}, + { "phy_test_tssi_offs", wl_test_tssi_offs, WLC_GET_VAR, -1, + "wl phy_test_tssi_offs val"}, + { "phy_rssiant", wl_phy_rssiant, WLC_GET_VAR, -1, + "wl phy_rssiant antindex(0-3)"}, + { "phy_rssi_ant", wl_phy_rssi_ant, WLC_GET_VAR, WLC_SET_VAR, + "Get RSSI per antenna (only gives RSSI of current antenna for SISO PHY)"}, + { "lpphy_papdepstbl", wl_phy_papdepstbl, -1, WLC_GET_VAR, + "print papd eps table; Usage: wl lpphy_papdepstbl" + }, + { "phy_test_idletssi", wl_test_idletssi, WLC_GET_VAR, -1, + "get idletssi for the given core; wl phy_test_idletssi corenum"}, + { "phy_setrptbl", wl_var_void, -1, WLC_SET_VAR, + "populate the reciprocity compensation table based on SROM cal content\n\n" + "\tusage: wl phy_setrptbl"}, + { "phy_forceimpbf", wl_var_void, -1, WLC_SET_VAR, + "force the beamformer into implicit TXBF mode and ready to construct steering matrix\n\n" + "\tusage: wl phy_forceimpbf"}, + { "phy_forcesteer", wl_var_setint, -1, WLC_SET_VAR, + "force the beamformer to apply steering matrix when TXBF is turned on\n\n" + "\tusage: wl phy_forcesteer 1/0"}, + { "lcnphy_papdepstbl", wl_phy_papdepstbl, -1, WLC_GET_VAR, + "print papd eps table; Usage: wl lcnphy_papdepstbl" + }, + { "rifs", wl_rifs, WLC_GET_VAR, WLC_SET_VAR, + "set/get the rifs status; usage: wl rifs <1/0> (On/Off)" + }, + { "rifs_advert", wl_rifs_advert, WLC_GET_VAR, WLC_SET_VAR, + "set/get the rifs mode advertisement status; usage: wl rifs_advert <-1/0> (Auto/Off)" + }, + { "phy_rxiqest", wl_rxiq, WLC_GET_VAR, -1, + "Get phy RX IQ noise in dBm:\n" + "\t-s # of samples (2^n)\n" + "\t-a antenna select, 0,1 or 3\n" + "\t-r resolution select, 0 (coarse) or 1 (fine)\n" + "\t-f lpf hpc override select, 0 (hpc unchanged) or 1 (overridden to ltrn mode)\n" + "\t-w dig lpf override select, 0 (lpf unchanged) or 1 (overridden to ltrn_lpf mode)" + "\t or 2 (bypass)\n" + "\t-g gain-correction select, 0 (disable), 1(enable full correction) \n" + "\t 2 (enable temperature correction) or 3(verify rssi_gain_delta)\n" + "\t-e extra INITgain in dB on top of default. Valid values = {0, 3, 6, .., 21, 24}\n" + "\t-i gain mode select, 0 (default gain), 1 (fixed high gain) or 4 (fixed low gain). \n" + }, + { "phy_txiqcc", wl_phy_txiqcc, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_txiqcc [a b]\n" + "Set/get the iqcc a, b values" + }, + { "phy_txlocc", wl_phy_txlocc, WLC_GET_VAR, WLC_SET_VAR, + "usage: phy_txlocc [di dq ei eq fi fq]\n" + "Set/get locc di dq ei eq fi fq values" + }, + { "phytable", wl_phytable, WLC_GET_VAR, WLC_SET_VAR, + "usage: wl phytable table_id offset width_of_table_element [table_element]\n" + "Set/get table element of a table with the given ID at the given offset\n" + "Note that table width supplied should be 8 or 16 or 32\n" + "table ID, table offset can not be negative" + }, + /* WLOTA_EN START */ + { "ota_teststop", wl_ota_teststop, -1, WLC_SET_VAR, + "\tUsage: ota_teststop \n" + }, + { "ota_loadtest", wl_ota_loadtest, -1, WLC_SET_VAR, + "\tUsage: ota_loadtest [filename] \n" + "\t\tpicks up ota_test.txt if file is not given \n" + }, + { "ota_stream", wl_load_cmd_stream, -1, WLC_SET_VAR, + "\tUsage: wl ota_stream start : to start the test\n" + "\twl ota_stream ota_sync \n" + "\twl ota_stream test_setup synchtimeoout(seconds) synchbreak/loop synchmac txmac rxmac \n" + "\twl ota_stream ota_tx chan bandwidth contrlchan rates stf txant rxant tx_ifs tx_len" + "num_pkt pwrctrl start:delta:end \n" + "\twl ota_stream ota_rx chan bandwidth contrlchan -1 stf txant rxant tx_ifs" + "tx_len num_pkt \n" + "\twl ota_stream stop : to stop the test\n" + }, + { "ota_teststatus", wl_otatest_status, WLC_GET_VAR, -1, + "\tUsage: otatest_status" + "\t\tDisplays current running test details" + "\totatest_status n " + "\t\tdisplays test arguments for nth line \n" + }, + /* WLOTA_EN END */ + { "force_vsdb_chans", wl_phy_force_vsdb_chans, WLC_GET_VAR, WLC_SET_VAR, + "Set/get channels for forced vsdb mode\n" + "usage: wl force_vsdb_chans chan1 chan2\n" + "Note: Give chan in the same format as chanspec: eg force_vsdb_chans 1l 48u\n" + }, + { "pavars", wl_phy_pavars, WLC_GET_VAR, WLC_SET_VAR, + "Set/get temp PA parameters\n" + "usage: wl down\n" + " wl pavars pa2gw0a0=0x1 pa2gw1a0=0x2 pa2gw2a0=0x3 ... \n" + " wl pavars\n" + " wl up\n" + " override the PA parameters after driver attach(srom read), before diver up\n" + " These override values will be propogated to HW when driver goes up\n" + " PA parameters in one band range (2g, 5gl, 5g, 5gh) must all present if\n" + " one of them is specified in the command, otherwise it will be filled with 0" + }, + { "povars", wl_phy_povars, WLC_GET_VAR, WLC_SET_VAR, + "Set/get temp power offset\n" + "usage: wl down\n" + " wl povars cck2gpo=0x1 ofdm2gpo=0x2 mcs2gpo=0x3 ... \n" + " wl povars\n" + " wl up\n" + " override the power offset after driver attach(srom read), before diver up\n" + " These override values will be propogated to HW when driver goes up\n" + " power offsets in one band range (2g, 5gl, 5g, 5gh) must all present if\n" + " one of them is specified in the command, otherwise it will be filled with 0" + " cck(2g only), ofdm, and mcs(0-7) for NPHY are supported " + }, + { "rpcalvars", wl_phy_rpcalvars, WLC_GET_VAR, WLC_SET_VAR, + "Set/get temp RPCAL parameters\n" + "usage: wl down\n" + " wl rpcalvars rpcal2g=0x1 \n" + " wl rpcalvars\n" + " wl up\n" + " override the RPCAL parameters after driver attach(srom read), before diver up\n" + " These override values will be propogated to HW when driver goes up\n" + " Only the RPCAL parameter specified in the command is updated, the rest is untouched \n" + }, + { "fem", wl_phy_fem, WLC_GET_VAR, WLC_SET_VAR, + "Set temp fem2g/5g value\n" + "usage: wl fem (tssipos2g=0x1 extpagain2g=0x2 pdetrange2g=0x1 triso2g=0x1 antswctl2g=0)\n" + " (tssipos5g=0x1 extpagain5g=0x2 pdetrange5g=0x1 triso5g=0x1 antswctl5g=0)" + }, + { "antgain", wl_antgain, WLC_GET_VAR, WLC_SET_VAR, + "Set temp ag0/1 value\n" + "usage: wl antgain ag0=0x1 ag1=0x2" + }, + { "maxpower", wl_phy_maxpower, WLC_GET_VAR, WLC_SET_VAR, + "Set temp maxp2g(5g)a0(a1) value\n" + "usage: wl maxpower maxp2ga0=0x1 maxp2ga1=0x2 maxp5ga0=0xff maxp5ga1=0xff\n" + " maxp5gla0=0x3 maxp5gla1=0x4 maxp5gha0=0x5 maxp5gha1=0x6" + }, + + { "phy_antsel", wl_antsel, WLC_GET_VAR, -1, + "get/set antenna configuration \n" + "\tset: -1(AUTO), 0xAB(fixed antenna selection)\n" + "\t\twhere A and B is the antenna numbers used for RF chain 1 and 0 respectively\n" + "\tquery: <utx>[AUTO] <urx>[AUTO] <dtx>[AUTO] <drx>[AUTO]\n" + "\t\twhere utx = TX unicast antenna configuration\n" + "\t\t\turx = RX unicast antenna configuration\n" + "\t\t\tdtx = TX default (non-unicast) antenna configuration\n" + "\t\t\tdrx = RX default (non-unicast) antenna configuration" + }, + { "txcore", wl_txcore, WLC_GET_VAR, WLC_SET_VAR, + "Usage: wl txcore -k <CCK core mask> -o <OFDM core mask> -s <1..4> -c <core bitmap>\n" + "\t-k CCK core mask\n" + "\t-o OFDM core mask\n" + "\t-s # of space-time-streams\n" + "\t-c active core (bitmask) to be used when transmitting frames" + }, + { "txcore_override", wl_txcore, WLC_GET_VAR, -1, + "Usage: wl txcore_override\n" + "\tget the user override of txcore" + }, + { "txchain_pwr_offset", wl_txcore_pwr_offset, WLC_GET_VAR, WLC_SET_VAR, + "Usage: wl txchain_pwr_offset [qdBm offsets]\n" + "\tGet/Set the current offsets for each core in qdBm (quarter dBm)" + }, + { "sample_collect", wl_sample_collect, WLC_PHY_SAMPLE_COLLECT, -1, + "Optional parameters ACPHY/HTPHY/(NPHY with NREV >= 7) are:\n" + "\t-f File name to dump the sample buffer (default \"sample_collect.dat\")\n" + "\t-t Trigger condition (default now)\n" + "\t\t now, good_fcs, bad_fcs, bad_plcp, crs, crs_glitch, crs_deassert\n" + "\t-b PreTrigger duration in us (default 10)\n" + "\t-a PostTrigger duration in us (default 10) \n" + "\t-m Sample collect mode (default 1) \n" + "\t\tSC_MODE_0_sd_adc\t\t\t0\n" + "\t\tSC_MODE_1_sd_adc_5bits\t\t\t1\n" + "\t\tSC_MODE_2_cic0\t\t\t\t2\n" + "\t\tSC_MODE_3_cic1\t\t\t\t3\n" + "\t\tSC_MODE_4s_rx_farrow_1core\t\t4\n" + "\t\tSC_MODE_4m_rx_farrow\t\t\t5\n" + "\t\tSC_MODE_5_iq_comp\t\t\t6\n" + "\t\tSC_MODE_6_dc_filt\t\t\t7\n" + "\t\tSC_MODE_7_rx_filt\t\t\t8\n" + "\t\tSC_MODE_8_rssi\t\t\t\t9\n" + "\t\tSC_MODE_9_rssi_all\t\t\t10\n" + "\t\tSC_MODE_10_tx_farrow\t\t\t11\n" + "\t\tSC_MODE_11_gpio\t\t\t\t12\n" + "\t\tSC_MODE_12_gpio_trans\t\t\t13\n" + "\t\tSC_MODE_14_spect_ana\t\t\t14\n" + "\t\tSC_MODE_5s_iq_comp\t\t\t15\n" + "\t\tSC_MODE_6s_dc_filt\t\t\t16\n" + "\t\tSC_MODE_7s_rx_filt\t\t\t17\n" + "\t\t HTPHY: 0=adc, 1..3=adc+rssi, 4=gpio\n" + "\t\t NPHY: 1=Dual-Core adc[9:2], 2=Core0 adc[9:0], 3=Core1 adc[9:0], gpio=gpio\n" + "\t-g GPIO mux select (default 0)\n" + "\t\t use only for gpio mode\n" + "\t-d Downsample enable (default 0)\n" + "\t\t use only for HTPHY\n" + "\t-e BeDeaf enable (default 0)\n" + "\t-i Timeout in units of 10us. (ACPHY is in 10ms unit) (default 1000)\n" + "Optional parameters (NPHY with NREV < 7) are:\n" + "\t-f File name to dump the sample buffer (binary format, default \"sample_collect.dat\")\n" + "\t-u Sample collect duration in us (default 60)\n" + "\t-c Cores to do sample collect, only if BW=40MHz (default both)\n" + "Optional parameters LCN40PHY are:\n" + "\t-f File name to dump the sample buffer (default \"sample_collect.dat\")\n" + "\t-t Trigger condition (default now)\n" + "\t\t now\n" + "\t-s Trigger State (default 0)\n" + "\t-x Module_Sel1 (default 2)\n" + "\t-y Module_Sel2 (default 6)\n" + "\t-n Number of samples (Max 2048, default 2048)\n" + "For (NREV < 7), the NPHY buffer returned has the format:\n" + "\tIn 20MHz [(uint16)num_bytes, <I(core0), Q(core0), I(core1), Q(core1)>]\n" + "\tIn 40MHz [(uint16)num_bytes(core0), <I(core0), Q(core0)>,\n" + "\t\t(uint16)num_bytes(core1), <I(core1), Q(core1)>]"}, +#ifdef PLC + { "plc", wl_plc, WLC_GET_VAR, WLC_SET_VAR, + "set/get the plc config params; usage: wl plc [[0|1] [node_list]" + "[link_affinity|mac_affinity <etheraddr> [<affinity>]]]" }, +#endif /* PLC */ + { "txfifo_sz", wl_txfifo_sz, WLC_GET_VAR, WLC_SET_VAR, + "set/get the txfifo size; usage: wl txfifo_sz <fifonum> <size_in_bytes>" }, +#ifdef WLPFN + { "pfnset", wl_pfn_set, -1, -1, + "Configures preferred network offload parameter\n" + "\tpfnset syntax is: pfnset [scanfrq xxxxx(30 sec)] [netimeout xxxx(60 sec)]" + "[slowfrq xxxx(180 sec)] [bestn (2)|[1-BESTN_MAX]] [mscan (0)|[0-MSCAN_MAX]]" + "[bdscan (0)|1] [adapt (off)|[smart, strict, slow]]" + "[rssi_delta xxxx(30 dBm)] [sort (listorder)|rssi] [bkgscan (0)|1] [immediateevent (0)|1]" + "[immediate 0|(1)] [repeat (10)|[1-20]] [exp (2)|[1-5]] [separate 0|(1)]"}, + { "pfnadd", wl_pfn_add, -1, -1, + "Adding SSID based preferred networks to monitor and connect\n" + "\tpfnadd syntax is: pfnadd ssid <SSID> [hidden (0)|1]" + "[imode (bss)|ibss]" + "[amode (open)|shared] [wpa_auth (wpadisabled)|wpapsk|wpa2psk|wpanone|any]" + "[wsec WEP|TKIP|AES|TKIPAES] [suppress (neither)|found|lost] [rssi <rssi>(0 dBm)]\n" + "Up to 16 SSID networks can be added together in one pfnadd\n" + "\tTo specify more than one WPA methods, use a number (same format as wpa_auth iovar) " + "as the parameter of wpa_auth (e.g. 0x84 for wpapsk and wpa2psk.)"}, + { "pfnadd_bssid", wl_pfn_add_bssid, -1, -1, + "Adding BSSID based preferred networks to monitor and connect\n" + "\tpfnadd_bssid syntax is: pfnadd_bssid bssid <BSSID> [suppress (neither)|found|lost]" + "[rssi <rssi>(0 dBm)]\n" + "\tUp to 150 BSSIDs can be added together in one pfnadd_bssid\n"}, + { "pfncfg", wl_pfn_cfg, -1, -1, + "Configures channel list and report type\n" + "Usage: pfncfg [channel <list>] [report <type>] [prohibited 1|0]\n" + "\treport <type> is ssidonly, bssidonly, or both (default: both)\n" + "\tprohibited flag 1: allow and (passively) scan any channel (default 0)"}, + { "pfn", wl_pfn, -1, -1, + "Enable/disable preferred network off load monitoring\n" + "\tpfn syntax is: pfn 0|1"}, + { "pfnclear", wl_var_void, -1, WLC_SET_VAR, + "Clear the preferred network list\n" + "\tpfnclear syntax is: pfnclear"}, + { "pfnbest", wl_pfnbest, -1, -1, + "Get the best n networks in each of up to m scans, with 16bit timestamp\n" + "\tpfnbest syntax is: pfnbest"}, + { "pfnlbest", wl_pfnlbest, -1, -1, + "Get the best n networks in each scan, up to m scans, with 32bit timestmp\n" + "\tpfnbest syntax is: pfnlbest"}, + { "pfnsuspend", wl_pfn_suspend, -1, -1, + "Suspend/resume pno scan\n" + "\tpfnsuspend syntax is: pfnsuspend 0|1"}, + { "pfnmem", wl_pfn_mem, -1, -1, + "Get supported mscan with given bestn\n" + "\tpfnmem syntax is: pfnmscan bestn [1-BESTN_MAX]"}, + { "pfneventchk", wl_pfn_event_check, -1, -1, + "Listen and prints the preferred network off load event from dongle\n" + "\tpfneventchk syntax is: pfneventchk [ifname]"}, + { "escan_event_check", wl_escan_event_check, -1, -1, + "Listen and prints the escan events from the dongle\n" + "\tescan_event_check syntax is: escan_event_check ifname flag\n" + "\tflag 1 = sync_id info, 2 = bss info, 4 = state + bss info [default], " + "8 = TLV check for IEs"}, + { "escanresults", wl_escanresults, -1, WLC_SET_VAR, + "Start escan and display results.\n" SCAN_USAGE + }, + { "event_filter", wl_event_filter, -1, -1, + "Set/get event filter\n" + "\tevent_filter syntax is: event_filter [value]"}, +#endif /* WLPFN */ +#ifdef WLP2PO + { "p2po_listen", wl_p2po_listen, -1, WLC_SET_VAR, + "start listen (with period and interval)\n" + "\tusage: p2po_listen [\"period\"] [\"interval\"]\n" + }, + { "p2po_find", wl_var_void, -1, WLC_SET_VAR, + "start discovery\n" + }, + { "p2po_stop", wl_p2po_stop, -1, WLC_SET_VAR, + "stop both P2P listen and P2P device discovery offload(0:stop; 1:pause).\n" + "\tusage: p2po_stop <0|1>\n" + }, + { "p2po_addsvc", wl_p2po_addsvc, -1, WLC_SET_VAR, + "add query-service pair\n" + "\tusage: p2po_addsvc <protocol> <\"query\"> <\"response\">\n" + "\t\t<protocol>: 1 = Bonjour, 2 = UPnP\n" + }, + { "p2po_delsvc", wl_p2po_delsvc, -1, WLC_SET_VAR, + "delete query-service pair\n" + "\tusage: p2po_delsvc <protocol> <\"query\">\n" + "\t\t<protocol>: 1 = Bonjour, 2 = UPnP, 0 = delete all\n" + }, + { "p2po_sd_req_resp", wl_p2po_sd_reqresp, -1, WLC_SET_VAR, + "find a service\n" + "\tusage: p2po_sd_req_resp <protocol> <\"query\">\n" + "\t\t<protocol>: 1 = Bonjour, 2 = UPnP\n" + }, + { "p2po_sd_cancel", wl_var_void, -1, WLC_SET_VAR, + "cancel finding a service\n" + }, + { "p2po_listen_channel", wl_p2po_listen_channel, -1, WLC_SET_VAR, + "set listen channel to channel 1, 6, 11, or default\n" + "\tusage: p2po_listen_channel <1|6|11|0>\n" + }, + { "p2po_results", wl_p2po_results, -1, WLC_SET_VAR, + "Listens and displays P2PO results.\n" + }, +#endif /* WLP2PO */ +#ifdef WLANQPO + { "anqpo_set", wl_anqpo_set, -1, -1, + "set ANQP offload parameters\n" + "\tusage: anqpo_set [max_retransmit <number>]\n" + "\t\t[response_timeout <msec>] [max_comeback_delay <msec>]\n" + "\t\t[max_retries <number>] [query \"encoded ANQP query\"]\n" + }, + { "anqpo_stop_query", wl_anqpo_stop_query, -1, WLC_SET_VAR, + "stop ANQP query\n" + "\tusage: anqpo_stop_query\n" + }, + { "anqpo_start_query", wl_anqpo_start_query, -1, WLC_SET_VAR, + "start ANQP query to peer(s)\n" + "\tusage: anqpo_start_query <channel> <xx:xx:xx:xx:xx:xx>\n" + "\t\t[<channel> <xx:xx:xx:xx:xx:xx>]>\n" + }, + { "anqpo_auto_hotspot", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "automatic ANQP query to maximum number of hotspot APs, default 0 (disabled)\n" + "\tusage: anqpo_auto_hotspot [max]\n" + }, + { "anqpo_ignore_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "ignore duplicate SSIDs or BSSIDs, default 0 (SSID)\n" + "\tusage: anqpo_ignore_mode [0 (SSID) | 1 (BSSID)]\n" + }, + { "anqpo_ignore_ssid_list", wl_anqpo_ignore_ssid_list, WLC_GET_VAR, WLC_SET_VAR, + "get, clear, set, or append to ANQP offload ignore SSID list\n" + "\tusage: wl anqpo_ignore_ssid_list [clear |\n" + "\t\tset <ssid1> [ssid2] |\n" + "\t\tappend <ssid3> [ssid4]>\n" + }, + { "anqpo_ignore_bssid_list", wl_anqpo_ignore_bssid_list, WLC_GET_VAR, WLC_SET_VAR, + "get, clear, set, or append to ANQP offload ignore BSSID list\n" + "\tusage: wl anqpo_ignore_bssid_list [clear |\n" + "\t\tset <xx:xx:xx:xx:xx:xx> [xx:xx:xx:xx:xx:xx] |\n" + "\t\tappend <xx:xx:xx:xx:xx:xx> [xx:xx:xx:xx:xx:xx]]>\n" + }, + { "anqpo_results", wl_anqpo_results, -1, WLC_SET_VAR, + "Listens and displays ANQP results.\n" + }, +#endif /* WLANQPO */ + { "hs20_ie", wl_hs20_ie, -1, WLC_SET_VAR, + "set hotspot 2.0 indication IE\n" + "\tusage: wl hs20_ie <length> <hexdata>\n" + }, + {"rate_histo", wl_rate_histo, -1, WLC_GET_VAR, + "Get rate hostrogram" + }, + { "pkteng_start", wl_pkteng, -1, WLC_SET_VAR, + "start packet engine tx usage: wl pkteng_start <xx:xx:xx:xx:xx:xx>" + " <tx|txwithack> [(async)|sync] [ipg] [len] [nframes] [src]\n" + "\tstart packet engine rx usage: wl pkteng_start <xx:xx:xx:xx:xx:xx>" + " <rx|rxwithack> [(async)|sync] [rxframes] [rxtimeout]\n" + "\tsync: synchronous mode\n" + "\tipg: inter packet gap in us\n" + "\tlen: packet length\n" + "\tnframes: number of frames; 0 indicates continuous tx test\n" + "\tsrc: source mac address\n" + "\trxframes: number of receive frames (sync mode only)\n" + "\trxtimeout: maximum timout in msec (sync mode only)"}, + { "pkteng_stop", wl_pkteng, -1, WLC_SET_VAR, + "stop packet engine; usage: wl pkteng_stop <tx|rx>"}, + { "pkteng_stats", wl_pkteng_stats, -1, WLC_GET_VAR, + "packet engine stats; usage: wl pkteng_stats"}, + { "wowl", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Enable/disable WOWL events\n" + " 0 - Clear all events\n" + "Bit 0 - Wakeup on Magic Packet\n" + "Bit 1 - Wakeup on NetPattern (use 'wl wowl_pattern' to configure pattern)\n" + "Bit 2 - Wakeup on loss-of-link due to Disassociation/Deauth\n" + "Bit 3 - Wakeup on retrograde tsf\n" + "Bit 4 - Wakeup on loss of beacon (use 'wl wowl_bcn_loss' to configure time)"}, + { "wowl_bcn_loss", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Set #of seconds of beacon loss for wakeup event"}, + { "wowl_pattern", wl_wowl_pattern, -1, -1, + "usage: wowl_pattern [ [clr | [[ add | del ] offset mask value ]]]\n" + "No options -- lists existing pattern list\n" + "add -- Adds the pattern to the list\n" + "del -- Removes a pattern from the list\n" + "clr -- Clear current list\n" + "offset -- Starting offset for the pattern\n" + "mask -- Mask to be used for pattern. Bit i of mask => byte i of the pattern\n" + "value -- Value of the pattern" + }, + /* wowl_keepalive shares structures and functions with "mkeep_alive" */ + {"wowl_keepalive", wl_mkeep_alive, WLC_GET_VAR, WLC_SET_VAR, + "Send specified keep alive packet periodically in wowl mode.\n" + "\tUsage: wl wowl_keepalive <index0-1> <period> <packet>\n" + "\t\tindex: 0 - 1.\n" + "\t\tperiod: Re-transmission period in milli-seconds. 0 to disable packet transmits.\n" + "\t\tpacket: Hex packet contents to transmit. The packet contents should include " + "the entire ethernet packet (ethernet header, IP header, UDP header, and UDP " + "payload) specified in network byte order.\n" + "\n\te.g. Send keep alive packet every 30 seconds using id-1:\n" + "\twl wowl_keepalive 1 30000 0x0014a54b164f000f66f45b7e08004500001e000040004011c" + "52a0a8830700a88302513c413c4000a00000a0d\n" }, + + { "wowl_wakeind", wl_wowl_wakeind, WLC_GET_VAR, WLC_SET_VAR, + "usage: wowl_wakeind [clear]\n" + "Shows last system wakeup event indications from PCI and D11 cores\n" + "clear - Clear the indications" + }, + { "wowl_status", wl_wowl_status, WLC_GET_VAR, -1, + "usage: wowl_status [clear]\n" + "Shows last system wakeup setting" + }, + {"wowl_pkt", wl_wowl_pkt, -1, -1, + "Send a wakeup frame to wakup a sleeping STA in WAKE mode\n" + "Usage: wl wowl_pkt <len> <dst ea | bcast | ucast <STA ea>>" + "[ magic [<STA ea>] | net <offset> <pattern> <reason code> ]\n" + "e.g. To send bcast magic frame -- " + "wl wowl_pkt 102 bcast magic 00:90:4c:AA:BB:CC\n" + " To send ucast magic frame -- " + "wl wowl_pkt 102 ucast 00:90:4c:aa:bb:cc magic\n" + " To send a frame with L2 unicast - " + "wl wowl_pkt 102 00:90:4c:aa:bb:cc net 0 0x00904caabbcc 0x03\n" + " NOTE: offset for netpattern frame starts from \"Dest EA\" of ethernet frame." + "So dest ea will be used only when offset is >= 6\n" + " To send a eapol identity frame with L2 unicast - " + "wl wowl_pkt 102 00:90:4c:aa:bb:cc eapid id-string"}, + {"wowl_ext_magic", wl_wowl_extended_magic, WLC_GET_VAR, WLC_SET_VAR, + "Set 6-byte extended magic pattern\n" + "Usage: wl wowl_ext_magic 0x112233445566"}, + { "wme_apsd_trigger", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Set Periodic APSD Trigger Frame Timer timeout in ms (0=off)"}, + { "wme_autotrigger", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Enable/Disable sending of APSD Trigger frame when all ac are delivery enabled"}, + { "reassoc", wl_reassoc, -1, WLC_REASSOC, + "Initiate a (re)association request.\n" + "\tUsage: wl reassoc <bssid> [options]\n" + "\tOptions:\n" + "\t-c CL, --chanspecs=CL \tchanspecs (comma or space separated list)"}, + { "send_nulldata", wl_iov_mac, -1, -1, + "Sed a null frame to the specified hw address" }, + { "btc_params", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set BT Coex parameters"}, + { "btc_flags", wlu_reg2args, WLC_GET_VAR, WLC_SET_VAR, "g/set BT Coex flags"}, + { "obss_scan_params", wl_obss_scan, WLC_GET_VAR, WLC_SET_VAR, + "set/get Overlapping BSS scan parameters\n" + "Usage: wl obss_scan a b c d e ...; where\n" + "\ta-Passive Dwell, {5-1000TU}, default = 100\n" + "\tb-Active Dwell, {10-1000TU}, default = 20\n" + "\tc-Width Trigger Scan Interval, {10-900sec}, default = 300\n" + "\td-Passive Total per Channel, {200-10000TU}, default = 200\n" + "\te-Active Total per Channel, {20-1000TU}, default = 20\n" + "\tf-Channel Transition Delay Factor, {5-100}, default = 5\n" + "\tg-Activity Threshold, {0-100%}, default = 25"}, + {"mkeep_alive", wl_mkeep_alive, WLC_GET_VAR, WLC_SET_VAR, + "Send specified \"mkeep-alive\" packet periodically.\n" + "\tUsage: wl mkeep_alive <index0-3> <period> <packet>\n" + "\t\tindex: 0 - 3.\n" + "\t\tperiod: Re-transmission period in milli-seconds. 0 to disable packet transmits.\n" + "\t\tpacket: Hex packet contents to transmit. The packet contents should include " + "the entire ethernet packet (ethernet header, IP header, UDP header, and UDP " + "payload) specified in network byte order. If no packet is specified, a nulldata frame " + "will be sent instead.\n" + "\n\te.g. Send keep alive packet every 30 seconds using id-1:\n" + "\twl mkeep_alive 1 30000 0x0014a54b164f000f66f45b7e08004500001e000040004011c" + "52a0a8830700a88302513c413c4000a00000a0d" }, + {"keep_alive", wl_keep_alive, -1, -1, + "Send specified \"keep-alive\" packet periodically.\n" + "\tUsage: wl keep_alive <period> <packet>\n" + "\t\tperiod: Re-transmission period in milli-seconds. 0 to disable packet transmits.\n" + "\t\tpacket: Hex packet contents to transmit. The packet contents should include " + "the entire ethernet packet (ethernet header, IP header, UDP header, and UDP " + "payload) specified in network byte order.\n" + "\n\te.g. Send keep alive packet every 30 seconds:\n" + "\twl keep_alive 30000 0x0014a54b164f000f66f45b7e08004500001e000040004011c" + "52a0a8830700a88302513c413c4000a00000a0d" }, + { "srchmem", wl_srchmem, WLC_GET_VAR, WLC_SET_VAR, + "g/set ucode srch engine memory"}, + { "pkt_filter_add", wl_pkt_filter_add, -1, -1, + "Install a packet filter.\n" + "\tUsage: wl pkt_filter_add <id> <polarity> <type> <offset> <bitmask> <pattern>\n" + "\tid: Integer. User specified id.\n" + "\ttype: 0 (Pattern matching filter)\n" + "\t 5 (Pattern matching filter with timeout event)\n" + "\toffset: (type 0): Integer offset in received packet to start matching.\n" + "\t (type 5): Integer offset in received packet to start matching.\n" + "\tpolarity: Set to 1 to negate match result. 0 is default.\n" + "\tbitmask: Hex bitmask that indicates which bits of 'pattern' to match.\n" + "\t Must be same size as 'pattern'. Bit 0 of bitmask corresponds\n" + "\t to bit 0 of pattern, etc. If bit N of bitmask is 0, then do\n" + "\t *not* match bit N of the pattern with the received payload. If\n" + "\t bit N of bitmask is 1, then perform match.\n" + "\tpattern: Hex pattern to match. Must be same size as <bitmask>.\n" + "\ttimeout: (type 5): Number of seconds to wait before sending a timeout event when\n" + "\t a matching pattern packet is not received.\n"}, + { "pkt_filter_clear_stats", wl_varint, -1, WLC_SET_VAR, + "Clear packet filter statistic counter values.\n" + "\tUsage: wl pkt_filter_clear_stats <id>" }, + { "pkt_filter_enable", wl_pkt_filter_enable, -1, -1, + "Enable/disable a packet filter.\n" + "\tUsage: wl pkt_filter_enable <id> <0|1>"}, + { "pkt_filter_list", wl_pkt_filter_list, -1, -1, + "List installed packet filters.\n" + "\tUsage: wl pkt_filter_list [val]\n" + "\tval: 0 (disabled filters) 1 (enabled filters)"}, + { "pkt_filter_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Set packet filter match action.\n" + "\tUsage: wl pkt_filter_mode <value>\n" + "\tvalue: 1 - Forward packet on match, discard on non-match (default).\n" + "\t 0 - Discard packet on match, forward on non-match." }, + { "pkt_filter_delete", wl_varint, -1, WLC_SET_VAR, + "Uninstall a packet filter.\n" + "\tUsage: wl pkt_filter_delete <id>"}, + { "pkt_filter_stats", wl_pkt_filter_stats, -1, -1, + "Retrieve packet filter statistic counter values.\n" + "\tUsage: wl pkt_filter_stats <id>"}, + +#ifdef TRAFFIC_MGMT + {"trf_mgmt_config", wl_trf_mgmt_config, WLC_GET_VAR, WLC_SET_VAR, + "Sets/gets traffic management configuration.\n" + "\tUsage: wl trf_mgmt_config [<enable> \n" + "\t [<host IP address> <host IP subnet mask> \n" + "\t <downlink kbps> <uplink kbps> [<flags>]]] \n" + "\tenable: 0 - Disable traffic management\n" + "\t 1 - Enables traffic management (host IP arguments required)\n" + "\tFlag values are the following:\n" + "\t0x0001 : Add DSCP values to tx packets\n" + "\t0x0002 : Disable traffic shaping...just do priority classification\n" + "\nIf no arguments are entered, the current traffic management configuration \n" + "is displayed.\n" + "\ne.g. Configure traffic management and specify local ip addr. and bandwidth data:\n" + "\nwl trf_mgmt_config 1 12.0.0.1 255.0.0.0 5000 650\n"}, + + {"trf_mgmt_filters_add", wl_trf_mgmt_filters_add, -1, WLC_SET_VAR, + "Adds a traffic management filter.\n" + "\tUsage: wl trf_mgmt_filter_add [dst_port src_port prot priority]\n" + "\tdst_port : Destination TCP or UDP port \n" + "\tsrc_port : Source TCP or UDP port (0 - wildcard for any source port)\n" + "\tprot : L4 protocol (6 - TCP, 17 - UDP)\n" + "\tpriority : Priority value (see trf_mgmt_priority_values enum) \n" + "\ne.g. Add a tcp wildcard filter:\n" + "\nwl trf_mgmt_filters_add 80 0 6 2\n"}, + + {"trf_mgmt_filters_addex", wl_trf_mgmt_filters_addex, -1, WLC_SET_VAR, + "Adds a traffic management filter.\n" + "\tUsage: wl trf_mgmt_filter_add flag [dst_port src_port prot priority]\n" + "\tUsage: wl trf_mgmt_filter_add flag [dst_mac priority] \n" + "\tFlag values are the following:\n" + "\t0x0000 : filter on tcp/udp src/dst port\n" + "\t0x0001 : filter on destination MAC address\n" + "\t0x0010 : do not update the packet priority \n" + "\t0x0020 : Tag packets as Favored\n" + "\tdst_mac : Destination MAC address \n" + "\tdst_port : Destination TCP or UDP port \n" + "\tsrc_port : Source TCP or UDP port (0 - wildcard for any source port)\n" + "\tprot : L4 protocol (6 - TCP, 17 - UDP)\n" + "\tpriority : Priority value (see trf_mgmt_priority_values enum) \n" + "\ne.g. Add a tcp wildcard filter for all src/dst ports:\n" + "\nwl trf_mgmt_filters_addex 0 0 0 6 2\n" + "\ne.g. Add a dst mac address filter\n" + "\nwl trf_mgmt_filters_addex 0x31 aa:bb:cc:dd:ee:ff 2\n"}, + + {"trf_mgmt_filters_remove", wl_trf_mgmt_filters_remove, -1, WLC_SET_VAR, + "Removes a traffic management filter.\n" + "\tUsage: wl trf_mgmt_filter_remove [dst_port src_port prot]\n" + "\tdst_port : Destination TCP or UDP port \n" + "\tsrc_port : Source TCP or UDP port (0 - wildcard for any source port)\n" + "\tprot : L4 protocol (6 - TCP, 17 - UDP)\n" + "\ne.g. Remove a tcp wildcard filter:\n" + "\nwl trf_mgmt_filters_remove 80 0 6\n"}, + + {"trf_mgmt_filters_removeex", wl_trf_mgmt_filters_removeex, -1, WLC_SET_VAR, + "Removes a traffic management filter.\n" + "\tUsage: wl trf_mgmt_filter_remove flag [dst_port src_port prot]\n" + "\tUsage: wl trf_mgmt_filter_remove flag [dst_mac]\n" + "\tFlag values are the following:\n" + "\t0x0000 : filter on tcp/udp src/dst port\n" + "\t0x0001 : filter on destination MAC address\n" + "\t0x0010 : do not update the packet priority \n" + "\t0x0020 : Tag packets as Favored\n" + "\tdst_mac : Destination MAC address \n" + "\tdst_port : Destination TCP or UDP port \n" + "\tsrc_port : Source TCP or UDP port (0 - wildcard for any source port)\n" + "\tprot : L4 protocol (6 - TCP, 17 - UDP)\n" + "\ne.g. Remove a tcp wildcard filter:\n" + "\nwl trf_mgmt_filters_removeex 0 80 0 6\n" + "\nwl trf_mgmt_filters_removeex 0x31 00:90:4c:52:a8:83\n"}, + + {"trf_mgmt_filters_list", wl_trf_mgmt_filters_list, WLC_GET_VAR, -1, + "Lists all traffic management filters.\n" + "\tUsage: wl trf_mgmt_filter_list\n"}, + + {"trf_mgmt_filters_clear", wl_trf_mgmt_filters_clear, -1, WLC_SET_VAR, + "Clears all traffic management filters.\n" + "\tUsage: wl trf_mgmt_filters_clear\n"}, + + {"trf_mgmt_bandwidth", wl_trf_mgmt_bandwidth, WLC_GET_VAR, WLC_SET_VAR, + "Sets/gets traffic management bandwidth configuration.\n" + "\tUsage: wl trf_mgmt_bandwidth \n" + "\t [downlink uplink min_tx_bk min_tx_be min_tx_vi\n" + "\t [min_rx_b min_rx_be min_rx_vi]]\n" + "\tdownlink : downlink bandwidth (kbps)\n" + "\tuplink : uplink bandwidth (kbps)\n" + "\tmin_tx_bk : min. guaranteed tx bandwidth percentage for BK (kbps)\n" + "\tmin_tx_be : min. guaranteed tx bandwidth percentage for BE (kbps)\n" + "\tmin_tx_vi : min. guaranteed tx bandwidth percentage for VI (kbps)\n" + "\n(min_tx_bo + min_tx_be + min_tx_vi) must equal 100.\n" + "\tmin_rx_bk : min. guaranteed rx bandwidth percentage for BK (kbps)\n" + "\tmin_rx_be : min. guaranteed rx bandwidth percentage for BE (kbps)\n" + "\tmin_rx_vi : min. guaranteed rx bandwidth percentage for VI (kbps)\n" + "\n(min_rx_bk + min_rx_be + min_rx_vi) must equal 100." + "\nIf no rx gandwidth arguments are entered, tx bandwidth is used for rx." + "\nIf no arguments are entered, the current bandwidth configuration is displayed."}, + + {"trf_mgmt_flags", wl_trf_mgmt_flags, WLC_GET_VAR, WLC_SET_VAR, + "Sets/gets traffic management operational flags.\n" + "\tUsage: wl trf_mgmt_flags [flags]\n\n" + "\tFlag values are the following:\n" + "\t0x0001 : Add DSCP values to tx packets\n" + "\t0x0002 : Disable traffic shaping...just do priority classification\n" + "\nIf no arguments are entered, the current operational flags are displayed."}, + + {"trf_mgmt_stats", wl_trf_mgmt_stats, WLC_GET_VAR, -1, + "Gets traffic management statistics.\n" + "\tUsage: wl trf_mgmt_stats [index]\n" + "\tindex : Queue index \n"}, + + {"trf_mgmt_stats_clear", wl_trf_mgmt_stats_clear, -1, WLC_SET_VAR, + "Clears traffic management statistics.\n" + "\tUsage: wl trf_mgmt_stats_clear\n"}, + + {"trf_mgmt_shaping_info", wl_trf_mgmt_shaping_info, WLC_GET_VAR, -1, + "Gets traffic management shaping parameters.\n" + "\tUsage: wl trf_mgmt_shaping_info [index]\n" + "\tindex : Queue index \n"}, +#endif /* TRAFFIC_MGMT */ + + { "seq_start", wl_seq_start, -1, WLC_SET_VAR, + "Initiates command batching sequence. Subsequent IOCTLs will be queued until\n" + "seq_stop is received."}, + { "seq_stop", wl_seq_stop, -1, WLC_SET_VAR, + "Defines the end of command batching sequence. Queued IOCTLs will be executed."}, + { "seq_delay", wl_varint, -1, WLC_SET_VAR, + "Driver should spin for the indicated amount of time.\n" + "It is only valid within the context of batched commands."}, + { "seq_error_index", wl_varint, WLC_GET_VAR, -1, + "Used to retrieve the index (starting at 1) of the command that failed within a batch"}, +#ifdef CLMDOWNLOAD + { "clmload", wl_clmload, -1, WLC_SET_VAR, + "Used to download CLM data onto the dongle"}, +#endif /* CLMDOWNLOAD */ + { "bmac_reboot", wl_var_void, -1, WLC_SET_VAR, + "Reboot BMAC"}, +#ifdef RWL_WIFI + { "findserver", wl_wifiserver, -1, -1, + "Used to find the remote server with proper mac address given by the user,this " + "cmd is specific to wifi protocol."}, +#endif + { "txmcsset", wl_txmcsset, WLC_GET_VAR, -1, "get Transmit MCS rateset for 11N device"}, + { "rxmcsset", wl_rxmcsset, WLC_GET_VAR, -1, "get Receive MCS rateset for 11N device"}, + { "mimo_ss_stf", wl_mimo_stf, WLC_GET_VAR, WLC_SET_VAR, + "get/set SS STF mode.\n" + "\tUsage: wl mimo_ss_stf <value> <-b a | b>\n" + "\tvalue: 0 - SISO; 1 - CDD\n" + "\t-b(band): a - 5G; b - 2.4G"}, +#ifdef WLEXTLOG + { "extlog", wl_extlog, WLC_GET_VAR, -1, + "get external logs\n" + "\tUsage: wl extlog <from_last> <number>\n" + "\tfrom_last: 1 - from the last log record; 0 - whole log recrods\n" + "\tnumber: number of log records to get, MAX is 32."}, + { "extlog_clr", wl_var_void, -1, WLC_SET_VAR, "clear external log records"}, + { "extlog_cfg", wl_extlog_cfg, WLC_GET_VAR, WLC_SET_VAR, + "get/set external log configuration"}, +#endif + { "assertlog", wl_assertlog, WLC_GET_VAR, -1, + "get external assert logs\n" + "\tUsage: wl assertlog"}, + { "assert_type", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "set/get the asset_bypass flag; usage: wl assert_type <1/0> (On/Off)" + }, + { "ledbh", wl_ledbh, WLC_GET_VAR, WLC_SET_VAR, + "set/get led behavior\n" + "\tUsage: wl ledbh [0-3] [0-15]"}, + { "obss_coex_action", wl_obss_coex_action, -1, WLC_SET_VAR, + "send OBSS 20/40 Coexistence Mangement Action Frame\n" + "\tUsage: wl obss_coex_action -i <1/0> -w <1/0> -c <channel list>\n" + "\t -i: 40MHz intolerate bit; -w: 20MHz width Req bit;\n" + "\t -c: channel list, 1 - 14\n" + "\t At least one option must be provided" + }, + {"chanim_state", wl_chanim_state, WLC_GET_VAR, -1, + "get channel interference state\n" + "\tUsage: wl chanim_state channel\n" + "\tValid channels: 1 - 14\n" + "\treturns: 0 - Acceptable; 1 - Severe" + }, + {"chanim_mode", wl_chanim_mode, WLC_GET_VAR, WLC_SET_VAR, + "get/set channel interference measure (chanim) mode\n" + "\tUsage: wl chanim_mode <value>\n" + "\tvalue: 0 - disabled; 1 - detection only; 2 - detection and avoidance" + }, + { "ledbh", wl_ledbh, WLC_GET_VAR, WLC_SET_VAR, "set/get led behavior\n" + "\tUsage: wl ledbh [0-3] [0-15]"}, + { "led_blink_sync", wl_led_blink_sync, WLC_GET_VAR, WLC_SET_VAR, "set/get led_blink_sync\n" + "\tUsage: wl led_blink_sync [0-3] [0/1]"}, +#ifdef BCMWAPI_WAI + { "wai_restrict", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR, + "set/get WAI restriction"}, + { "wai_rekey", wl_iov_mac, -1, -1, + "set rekey event"}, +#endif /* BCMWAPI_WAI */ + + {"cca_get_stats", wl_cca_get_stats, WLC_GET_VAR, -1, + "Usage: wl cca_stats [-c channel] [-s num seconds][-n]\n" + "\t -c channel: Optional. specify channel. 0 = All channels. Default = current channel \n" + "\t -n: no analysis of results\n" + "\t -s num_seconds: Optional. Default = 10, Max = 60\n" + "\t -i: list individual measurements in addition to the averages\n" + "\t -curband: Only recommend channels on current band" + }, + { "itfr_get_stats", wl_itfr_get_stats, WLC_GET_VAR, -1, + "get interference source information" + }, + { "itfr_enab", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "get/set STA interference detection mode(STA only)\n" + "\t 0 - disable\n" + "\t 1 - enable maual detection\n" + "\t 2 - enable auto detection" + }, + { "itfr_detect", wl_var_void, -1, WLC_SET_VAR, + "issue an interference detection request" + }, + { "smfstats", wl_smfstats, WLC_GET_VAR, WLC_SET_VAR, + "get/clear selected management frame (smf) stats" + "\twl smfstats [-C num]|[--cfg=num] [auth]|[assoc]|[reassoc]|[clear]\n" + "\tclear - to clear the stats" }, +#ifdef RWL_DONGLE + { "dongleset", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Enable uart driver" + }, +#endif + { "manfinfo", wl_var_getandprintstr, WLC_GET_VAR, -1, + "show chip package info in OTP"}, + { "rrm", wl_rrm, WLC_GET_VAR, WLC_SET_VAR, + "enable or disable RRM feature\n" + "\tUsage: wl rrm [0/1] to disable/enable RRM feature"}, + { "rrm_bcn_req", wl_rrm_bcn_req, -1, WLC_SET_VAR, + "send 11k beacon measurement request\n" + "\tUsage: wl rrm_bcn_req [bcn mode] [da] [duration] [random int] [channel] [ssid]" + " [repetitions]"}, + { "rrm_chload_req", wl_rrm_chload_req, -1, WLC_SET_VAR, + "send 11k channel load measurement request\n" + "\tUsage: wl rrm_chload_req [regulatory] [da] [duration] [random int] [channel]" + " [repetitions]"}, + { "rrm_noise_req", wl_rrm_noise_req, -1, WLC_SET_VAR, + "send 11k noise measurement request\n" + "\tUsage: wl rrm_noise_req [regulatory] [da] [duration] [random int] [channel]" + " [repetitions] "}, + { "rrm_frame_req", wl_rrm_frame_req, -1, WLC_SET_VAR, + "send 11k frame measurement request\n" + "\tUsage: wl rrm_frame_req [regulatory] [da] [duration] [random int] [channel] [ta]" + " [repetitions]"}, + { "rrm_stat_req", wl_rrm_stat_req, -1, WLC_SET_VAR, + "send 11k stat measurement request\n" + "\tUsage: wl rrm_stat_req [da] [random int] [duration] [peer] [group id] [repetitions]"}, + { "rrm_lm_req", wl_rrm_lm_req, -1, WLC_SET_VAR, + "send 11k link measurement request\n" + "\tUsage: wl rrm_lm_req [da]"}, + { "rrm_nbr_req", wl_rrm_nbr_req, -1, WLC_SET_VAR, + "send 11k neighbor report measurement request\n" + "\tUsage: wl rrm_nbr_req [ssid]"}, + { "rrm_nbr_list", wl_rrm_nbr_list, WLC_GET_VAR, -1, + "get 11k neighbor report list\n" + "\tUsage: wl rrm_nbr_list"}, + { "rrm_nbr_del_nbr", wl_rrm_nbr_del_nbr, -1, WLC_SET_VAR, + "delete node from 11k neighbor report list\n" + "\tUsage: wl rrm_nbr_del_nbr [bssid]"}, + { "rrm_nbr_add_nbr", wl_rrm_nbr_add_nbr, -1, WLC_SET_VAR, + "add node to 11k neighbor report list\n" + "\tUsage: wl rrm_nbr_add_nbr [bssid] [bssid info] [regulatory] [channel] [phytype]"}, + { "wnm", wl_wnm, WLC_GET_VAR, WLC_SET_VAR, + "set driver wnm feature mask\n" + "\ttype \'wl msglevel ?\' for values" }, + { "wnm_bsstq", wl_wnm_bsstq, -1, WLC_SET_VAR, + "send 11v BSS transition management query\n" + "\tUsage: wl wnm_bsstq [ssid]"}, + { "tclas_add", wl_tclas_add, -1, WLC_SET_VAR, + "add tclas frame classifier type entry\n" + "\tUsage: wl tclas_add <user priority> <type> <mask> <...>\n" + "\ttype 0 eth2: <src mac> <dst mac> <ether type>\n" + "\ttype 1/4 ipv4: <ver> <src> <dst> <s_port> <d_port> <dscp> <prot>\n" + "\ttype 2 802.1Q: <vlan tag>\n" + "\ttype 3 filter: <offset> <value> <mask>\n" + "\ttype 4 ipv6: <ver> <src> <dst> <s_port> <d_port> <dscp> <nxt_hdr> <flw_lbl>\n" + "\ttype 5 802.1D/Q: <802.1Q PCP> <802.1Q CFI> <802.1Q VID>" + }, + { "tclas_del", wl_tclas_del, -1, WLC_SET_VAR, + "delete tclas frame classifier type entry\n" + "\tUsage: wl tclas_del [<idx> [<len>]]" + }, + { "tclas_list", wl_tclas_list, WLC_GET_VAR, -1, + "list the added tclas frame classifier type entry\n" + "\tUsage: wl tclas_list" + }, +#ifdef WLWNM + { "wnm_tfsreq_add", wl_wnm_tfsreq_add, -1, WLC_SET_VAR, + "add one tfs request element and send tfs request frame\n" + "\tUsage: wl wnm_tfsreq_add <tfs_id> <tfs_action_code> <tfs_subelem_id> <send>\n" + "\ttfs_id: a non-zero value (1 ~ 255)\n" + "\ttfs_action_code bitfield: 1: delete after match, 2: notify\n" + "\ttfs_subelem_id: TFS subelement (0 for none or 1 for previous tclas_add)\n" + "\tsend: 0: store element, 1: send all stored elements" + }, + { "wnm_dms_set", wl_wnm_dms_set, -1, WLC_SET_VAR, + "Optionally add pending DMS desc (after tclas_add) and optionally register all desc\n" + "on AP side to enable the service (with send=1)" + "\tUsage: wl wnm_dms_set <send> [<user_id> [<tc_pro>]]\n" + "\t\tsend: 0: store descriptor, 1: send all stored descs/enable DMS on AP\n" + "\t\tuser_id: new ID to assign to the created desc (if TCLAS added)\n" + "\t\t or existing ID to enable on AP (if no TCLAS added), 0 for all desc\n" + "\t\ttc_pro: TCLAS processing element (if several TCLAS added)" + }, + { "wnm_dms_status", wl_wnm_dms_status, WLC_GET_VAR, -1, + "list all DMS descriptors and provide their internal and AP status\n" + "\tUsage: wl wl_wnm_dms_status" + }, + { "wnm_dms_term", wl_wnm_dms_term, -1, WLC_SET_VAR, + "Disable registered DMS des on AP side and optionally discard them\n" + "\tUsage: wl wnm_dms_term <del> [<user_id>]\n" + "\t\tdel: Discard desc after disabling the service on AP side\n" + "\t\tuser_id: desc to disable/delete, 0 for all desc" + }, + { "wnm_service_term", wl_wnm_service_term, -1, WLC_SET_VAR, + "Disable service. Check specific wnm_XXX_term for more info\n" + "\tUsage: wl wnm_service_term <srv> <service realted params>\n" + "\t\tsrv: 1 for DMS, 2 for FMS, 3 for TFS" + }, + { "wnm_timbc_offset", wl_wnm_timbc_offset, WLC_GET_VAR, WLC_SET_VAR, + "get/set TIM broadcast offset by -32768 period > offset(us) > 32768\n" + "CAUTION!! Due to resource limitation, one radio can have only one set of TIMBC offset\n" + "setting. MBSS need to share the same setting\n" + "\tUsage: wl wnm_timbc_offset <offset> [<tsf_present> [<fix_interval> [<rate_ovreride>]]]\n" + "\t\toffset: in unit of us. Transmit TIM frame in specific TBTT transmit time time\n" + "\t\ttsf_present: can be omitted. If set to 1, timestamp field will present in TIM frame." + "If omitted, default setup to 1\n" + "\t\tfix_interval: can be omitted. If set with non-zero value, override STA request " + "interval in TIM Broadcast request. If omitted, default setup to 0\n" + "\t\trate_override: can be omitted. In unit of 500k, max setup to 108. If set, override" + "override high rate used to transmit TIM broadcast high rate frame" + }, + { "wnm_timbc_set", wl_wnm_timbc_set, -1, WLC_SET_VAR, + "Enable/disable TIM Broadcast. Station will send appropriate request if AP suport TIMBC\n" + "\tUsage: wl wnm_timbc_set <interval> [<flags> [<min_rate> [<max_rate>]]]\n" + "\t\tinterval: Beacon interval requested for TIM frames, 0 to disable TIM BC\n" + "\t\tflags: Bitfield with minimal requirements to keep the service enabled (check doc)\n" + "\t\tmin_rate: Minimal rate requirement, in Mbps, for TIM high or low rate frames\n" + "\t\tmax_rate: Maximal rate requirement" + }, + { "wnm_timbc_status", wl_wnm_timbc_status, WLC_GET_VAR, -1, + "Retrieve TIM Broadcast configuration set with current AP" + }, + { "wnm_maxidle", wl_wnm_maxidle, WLC_GET_VAR, WLC_SET_VAR, + "setup WNM BSS Max Idle Period interval and option\n" + "\tUsage: wl wnm_maxidle <Idle Period> <Option>\n" + "\tIdle Period: in unit of 1000TU(1.024s)\n" + "\tOption: protected keep alive required(0 ~ 1)" + }, + { "wnm_bsstrans_query", wl_wnm_bsstq, -1, WLC_SET_VAR, + "send 11v BSS transition management query\n" + "\tUsage: wl wnm_bsstrans_query [ssid]"}, + { "wnm_bsstrans_req", wl_wnm_bsstrans_req, -1, WLC_SET_VAR, + "send BSS transition management request frame with BSS termination included bit set\n" + "\tUsage: wl wnm_bsstrans_req <reqmode> <tbtt> <dur> [unicast]\n" + "\treqmode: request mode of BSS transition request\n" + "\ttbtt: time of BSS to end of life, in unit of TBTT, max to 65535\n" + "\tdur: time of BSS to keep off, in unit of minute, max to 65535\n" + "\tunicast: [1|0] unicast or broadcast to notify STA in BSS. Default in unicast.\n" + }, + { "wnm_keepalives_max_idle", wl_wnm_keepalives_max_idle, -1, -1, + "\tUsage: wl wnm_keepalives_max_idle <keepalives_per_bss_max_idle> <mkeepalive_index>" + " [<max_interval>]\n" + "set/get the number of keepalives, mkeep-alive index and max_interval configured" + " per BSS-Idle period.\n"}, +#endif /* WLWNM */ +#ifdef WLP2P + { "p2p_ssid", wl_ssid, -1, WLC_SET_VAR, + "set WiFi P2P wildcard ssid.\n" + "\tUsage: wl p2p_ssid <ssid>" + }, + { "p2p_state", wl_p2p_state, -1, WLC_SET_VAR, + "set WiFi P2P discovery state.\n" + "\tUsage: wl p2p_state <state> [<chanspec> <dwell time>]" + }, + { "p2p_scan", wl_p2p_scan, -1, WLC_SET_VAR, + "initiate WiFi P2P scan.\n" + "\tUsage: wl p2p_scan S|E <scan parms>\n" + SCAN_USAGE + }, + { "p2p_ifadd", wl_p2p_ifadd, -1, WLC_SET_VAR, + "add WiFi P2P interface\n" + "\tUsage: wl p2p_ifadd <MAC-address> go|client|dyngo [chanspec]\n" + "MAC-address: xx:xx:xx:xx:xx:xx" + }, + { "p2p_ifdel", wl_p2p_ifdel, -1, WLC_SET_VAR, + "delete WiFi P2P interface\n" + "\tUsage: wl p2p_ifdel <MAC-address>\n" + "MAC-address: xx:xx:xx:xx:xx:xx" + }, + { "p2p_ifupd", wl_p2p_ifupd, -1, WLC_SET_VAR, + "update an interface to WiFi P2P interface\n" + "\tUsage: wl p2p_ifupd <MAC-address> go|client\n" + "MAC-address: xx:xx:xx:xx:xx:xx" + }, + { "p2p_if", wl_p2p_if, WLC_GET_VAR, -1, + "query WiFi P2P interface bsscfg index\n" + "\tUsage: wl p2p_if <MAC-address>\n" + "MAC-address: xx:xx:xx:xx:xx:xx" + }, + { "p2p_noa", wl_p2p_noa, WLC_GET_VAR, WLC_SET_VAR, + "set/get WiFi P2P NoA schedule\n" + "\tUsage: wl p2p_noa <type> <type-specific-params>\n" + "\t\ttype 0: Scheduled Absence (on GO): <type> <action> <action-specific-params>\n" + "\t\t\taction -1: Cancel the schedule: <type> <action>\n" + "\t\t\taction 0,1,2: <type> <action> <option> <option-specific-params>\n" + "\t\t\t\taction 0: Do nothing during absence periods\n" + "\t\t\t\taction 1: Sleep during absence periods\n" + "\t\t\t\toption 0: <start:tsf> <interval> <duration> <count> ...\n" + "\t\t\t\toption 1 [<start-percentage>] <duration-percentage>\n" + "\t\t\t\toption 2 <start:tsf-offset> <interval> <duration> <count>\n" + "\t\ttype 1: Requested Absence (on GO): \n" + "\t\t\taction -1: Cancel the schedule: <type> <action>\n" + "\t\t\taction 2: <type> <action> <option> <option-specific-params>\n" + "\t\t\t\taction 2: Turn off GO beacons and probe responses during absence period\n" + "\t\t\t\toption 2 <start:tsf-offset> <interval> <duration> <count>" + }, + { "p2p_ops", wl_p2p_ops, WLC_GET_VAR, WLC_SET_VAR, + "set/get WiFi P2P OppPS and CTWindow\n" + "\tUsage: wl p2p_ops <ops> [<ctw>]\n" + "\t\t<ops>:\n" + "\t\t\t0: Disable OppPS\n" + "\t\t\t1: Enable OppPS\n" + "\t\t<ctw>:\n" + "\t\t\t10 and up to beacon interval" + }, + { "p2p_da_override", wl_iov_mac, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set WiFi P2P device interface addr\n" + "\tUsage: wl p2p_da_override <MAC-address>\n" + "MAC-address: xx:xx:xx:xx:xx:xx\n" + "(When MAC-address is set to 00:00:00:00:00:00, default da restored)" + }, +#endif /* WLP2P */ + { "pm_dur", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Retrieve accumulated PM duration information (GET only)\n" + }, + { "mpc_dur", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Retrieve accumulated MPC duration information in ms (GET) or clear accumulator (SET)\n" + "\tUsage: wl mpc_dur <any-number-to-clear>"}, + {"chanim_acs_record", wl_chanim_acs_record, WLC_GET_VAR, -1, + "get the auto channel scan record. \n" + "\t Usage: wl acs_record" + }, + {"chanim_stats", wl_chanim_stats, WLC_GET_VAR, -1, + "get chanim stats \n" + "\t Usage: wl chanim_stats" + }, + {"txdelay_params", wl_txdelay_params, WLC_GET_VAR, -1, + "get chanim stats \n" + "\t Usage: wl txdelay_params ratio cnt period tune" + }, + {"intfer_params", wl_intfer_params, WLC_GET_VAR, WLC_SET_VAR, + "set/get intfer params \n" + "\tUsage: wl intfer_params period (in sec) cnt(0~4) txfail_thresh tcptxfail_thresh\n" + "\tperiod=0: disable Driver monitor txfail" + }, + { "dngl_wd", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "enable or disable dongle keep alive watchdog timer\n" + "\tUsage: wl dngl_wd 0\\1 (to turn off\\on)"}, + { "tsf", wl_tsf, WLC_GET_VAR, WLC_SET_VAR, + "set/get tsf register\n" + "\tUsage: wl tsf [<high> <low>]"}, + { "tpc_mode", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Enable/disable AP TPC.\n" + "Usage: wl tpc_mode <mode> \n" + "\t0 - disable, 1 - BSS power control, 2 - AP power control, 3 - Both (1) and (2)"}, + { "tpc_period", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Set AP TPC periodicity in secs.\n" + "Usage: wl tpc_period <secs> "}, + { "tpc_lm", wl_tpc_lm, WLC_GET_VAR, -1, + "Get current link margins."}, + { "mfp_config", wl_mfp_config, -1, WLC_SET_VAR, + "Config PMF capability\n" + "\tusage: wl mfp 0/disable, 1/capable, 2/requred" }, + { "mfp_sha256", wl_mfp_sha256, WLC_GET_VAR, WLC_SET_VAR, + "Config SHA256 capability\n" + "\tusage: wl sha256 0/disable, 1/enable" }, + { "mfp_sa_query", wl_mfp_sa_query, -1, WLC_SET_VAR, + "Send a sa query req/resp to a peer\n" + "\tusage: wl mfp_sa_query flag action id" }, + { "mfp_disassoc", wl_mfp_disassoc, WLC_GET_VAR, WLC_SET_VAR, + "send bogus disassoc\n" + "\tUsage: wl mfp_disassoc"}, + { "mfp_deauth", wl_mfp_deauth, WLC_GET_VAR, WLC_SET_VAR, + "send bogus deauth\n" + "\tUsage: wl mfp_dedauth"}, + { "mfp_assoc", wl_mfp_assoc, WLC_GET_VAR, WLC_SET_VAR, + "send assoc\n" + "\tUsage: wl mfp_assoc"}, + { "mfp_auth", wl_mfp_auth, WLC_GET_VAR, WLC_SET_VAR, + "send auth\n" + "\tUsage: wl mfp_auth"}, + { "mfp_reassoc", wl_mfp_reassoc, WLC_GET_VAR, WLC_SET_VAR, + "send reassoc\n" + "\tUsage: wl mfp_reassoc"}, + { "monitor_lq", wl_monitor_lq, WLC_GET_VAR, WLC_SET_VAR, + "Start/Stop monitoring link quality metrics - RSSI and SNR\n" + "\tUsage: wl monitor_lq <0: turn off / 1: turn on"}, + { "monitor_lq_status", wl_dump_lq, WLC_GET_VAR, -1 /* Set not reqd */, + "Returns averaged link quality metrics - RSSI and SNR values"}, + { "mac_rate_histo", wl_mac_rate_histo, WLC_GET_VAR, WLC_SET_VAR, + "Usage: wl mac_rate_histo <mac address> <access category> <num_pkts>\n" + "\t(MAC address e.g. 00:11:20:11:33:33)\n" + "\t(Access Category(AC) - 0x10:for entire MAC or 0x4:for video AC for this MAC)\n" + "\t(num_pkts (optional) - Number of packets to average - max 64 for AC 0x10," + " max 32 for AC 0x4)" + }, + { "rpmt", wl_rpmt, -1, WLC_SET_VAR, "rpmt <pm1-to> <pm0-to>"}, +#ifdef WLTDLS + { "tdls_endpoint", wl_tdls_endpoint, WLC_GET_VAR, WLC_SET_VAR, + "Available TDLS operations to each TDLS peer.\n" + "\tusage: wl tdls_endpoint <disc, create, delete, PM, wake, cw> <ea> [chanspec]\n" + "\t [chanspec] only applies to 'cw' operaton.\n\n" + "\t addendum:\n" + "\t wl tdls_endpoint wfd_disc <ea> sends a WFD tunneled Probe Request"}, + { "tdls_wfd_ie", wl_tdls_wfd_ie, WLC_GET_VAR, -1, + "To set, get and clear additional WFD IE in setup_req and setup_resp\n" + "\tTo set2, get2 and clear2 additional WFD IE in tunneled probe_req and probe_resp\n" + "\tusage: wl tdls_wfd_ie get <own|peer_eth_addr#> [ip] [port]\n" + "\t wl tdls_wfd_ie get2 <own|peer_eth_addr#> [alt_mac] [port] [PC_bit]\n" + "\t\t peer_eth_addr#: HH:HH:HH:HH:HH:HH\n" + "\t\t and peer must be TDLS connected (only in case of setup)\n\n" + "\t wl tdls_wfd_ie <clr|clr2> own\n\n" + "\t wl tdls_wfd_ie set own wfd_ie_hexa_string [ip# [port# [type# [bssid#]]]]\n" + "\t wl tdls_wfd_ie set2 own wfd_ie_hexa_string [alt_mac# [port# [type#]]]\n" + "\t\t wfd_ie_hexa_string: should start with the full WFD IE header\n" + "\t\t e.g. 0xDDXX506F9A0A...\n" + "\t\t ip#: XXX.XXX.XXX.XXX\n" + "\t\t alt_mac#: HH:HH:HH:HH:HH:HH\n" + "\t\t port#: 0-65535\n" + "\t\t type#: 0 for source, 1 for primary sink\n" + "\t\t bssid#: HH:HH:HH:HH:HH:HH"}, +#endif /* WLTDLS */ + { "spatial_policy", wl_spatial_policy, WLC_GET_VAR, WLC_SET_VAR, + "set/get spatial_policy\n" + "\tUsage: wl spatial_policy <-1: auto / 0: turn off / 1: turn on>\n" + "\t to control individual band/sub-band use\n" + "\t wl spatial_policy a b c d e\n" + "\t where a is 2.4G band setting\n" + "\t where b is 5G lower band setting\n" + "\t where c is 5G middle band setting\n" + "\t where d is 5G high band setting\n" + "\t where e is 5G upper band setting"}, + { "ie", wl_ie, WLC_GET_VAR, WLC_SET_VAR, + "set/get IE\n" + "\tUsage: For set: wl ie type length hexdata\n" + "\t For get: wl ie type" }, + { "wnm_url", wl_wnm_url, WLC_GET_VAR, WLC_SET_VAR, + "set/get wnm session information url\n" + "Usage for set: wl wnm_url length urlstring\n" + "Usage for get: wl wnm_url" }, + { "ratetbl_ppr", wl_ratetbl_ppr, WLC_GET_VAR, WLC_SET_VAR, + "Usage: For get: wl ratetbl_ppr\n" + "\t For set: wl ratetbl_ppr <rate> <ppr>" }, + { "wowl_wakeup_reason", wl_wowl_wake_reason, WLC_GET_VAR, -1 /* Set not reqd */, + "Returns pattern id and associated wakeup reason"}, + { "mempool", wlu_mempool, WLC_GET_VAR, -1, + "Get memory pool statistics" }, +#ifdef SR_DEBUG + { "sr_dump_pmu", wl_dump_pmu, WLC_GET_VAR, WLC_SET_VAR, + "Dump value of PMU registers"}, + { "sr_pmu_keep_on", wl_pmu_keep_on, WLC_GET_VAR, WLC_SET_VAR, + "Keep resource on"}, + { "sr_skip", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Skip Save Restore Operation"}, + { "sr_power_island", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "Keep power islands on/off"}, +#endif /* SR_DEBUG */ +#ifdef UC_FATAL + { "uc_fatal", wl_varint, WLC_GET_VAR, -1, + "dump ucode info"}, +#endif /* UC_FATAL */ +#ifdef WLNDOE + { "nd_hostip", wl_hostipv6, WLC_GET_VAR, WLC_SET_VAR, + "Add a local host-ipv6 address or display them"}, + { "nd_solicitip", wl_solicitipv6, WLC_GET_VAR, WLC_SET_VAR, + "Add a local host solicit ipv6 address or display them"}, + { "nd_remoteip", wl_remoteipv6, WLC_GET_VAR, WLC_SET_VAR, + "Add a local remote ipv6 address or display them"}, + { "nd_status", wl_ndstatus, WLC_GET_VAR, -1, + "Displays Neighbor Discovery Status"}, + { "nd_hostip_clear", wl_var_void, -1, WLC_SET_VAR, + "Clear all host-ip addresses"}, + { "nd_macaddr", wl_iov_mac, WLC_GET_VAR, WLC_SET_VAR, + "Get/set the MAC address for offload" }, + { "nd_status_clear", wl_var_void, -1, WLC_SET_VAR, + "Clear neighbor discovery status"}, +#endif + { "antdiv_bcnloss", wl_varint, WLC_GET_VAR, WLC_SET_VAR, + "0 - Disable Rx antenna flip feature based on consecutive beacon loss\n" + "\tX - beacon loss count after which Rx ant will be flipped\n" + "\tUsage: wl antdiv_bcnloss <beaconloss_count>\n" + }, + { "lpc_params", wl_power_sel_params, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get Link Power Control params\n" + "\tUsage: wl powersel_params <tp_ratio_thresh> <rate_stab_thresh>\n" + "\t\t<pwr_stab_thresh> <pwr_sel_exp_time>\n"}, + { "mode_reqd", wl_bsscfg_int, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get operational capabilities required for STA to associate to the BSS " + "supported by the interface.\n" + "\tUsage: wl [-i ifname] mode_reqd [value]\n" + "\t wl mode_reqd [-C bss_idx ] [value]\n" + "\t\t <ifname> is the name of the interface corresponding to the BSS.\n" + "\t\t\t If the <ifname> is not given, the primary BSS is assumed.\n" + "\t\t <bss_idx> is the the BSS configuration index.\n" + "\t\t\t If the <bss_idx> is not given, configuraion #0 is assumed\n" + "\t\t <value> is the numeric values in the range [0..3]\n" + "\t\t 0 - no requirements on joining devices.\n" + "\t\t 1 - devices must advertise ERP (11g) capabilities to be allowed to associate\n" + "\t\t\t to a 2.4 GHz BSS.\n" + "\t\t 2 - devices must advertise HT (11n) capabilities to be allowed to associate\n" + "\t\t\t to a BSS.\n" + "\t\t 3 - devices must advertise VHT (11ac) capabilities to be allowed to associate\n" + "\t\t\t to a BSS.\n" + "\tThe command returns an error if the BSS interface is up.\n" + "\tThis configuration can only be changed while the BSS interface is down.\n" + "\tNote that support for HT implies support for ERP,\n" + "\tand support for VHT implies support for HT."}, + { "nar_clear_dump", wl_var_void, -1, WLC_SET_VAR, + "Clear non-aggregated regulation counters"}, + { "sar_limit", wl_sarlimit, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get sar_limit\n" + "\tusage: (set) sar_limit <2Gcore0 2Gcore1 2Gcore2 2Gcore3 5G[0]core0 5G[0]core1...>\n" + "\t (get) sar_limit, return sar limit table\n" + "\tunit: all input/output values are absolute and in unit of qdbm\n" + }, + { "bmon_bssid", wl_bmon_bssid, WLC_GET_VAR, WLC_SET_VAR, + "Set monitored BSSID\n" + "\tusage: bmon_bssid xx:xx:xx:xx:xx:xx 0|1\n"}, + +#ifdef EVENT_LOG_COMPILE + { "event_log_set_init", wl_event_log_set_init, -1, WLC_SET_VAR, + "Initialize an event log set\n" + "\tUsage: wl event_log_set_init <set> <size>\n"}, + { "event_log_set_expand", wl_event_log_set_expand, -1, WLC_SET_VAR, + "Increase the size of an event log set\n" + "\tUsage: wl event_log_set_expand <set> <size>\n"}, + { "event_log_set_shrink", wl_event_log_set_shrink, -1, WLC_SET_VAR, + "Decrease the size of an event log set\n" + "\tUsage: wl event_log_set_expand <set>\n"}, + { "event_log_tag_control", wl_event_log_tag_control, -1, WLC_SET_VAR, + "Modify the state of an event log tag\n" + "\tUsage: wl event_log_tag_control <tag> <set> <flags>\n"}, + +#endif /* EVENT_LOG_COMPILE */ + { "rmc_ackmac", wl_mcast_ackmac, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get ACK required multicast mac address\n" + "\tusage: wl rmc_ackmac -i [index] -t [multicast mac address]\n" + }, + { "rmc_ackreq", wl_mcast_ackreq, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get ACK rmc_mode 0 disable, 1 enable transmitter, 2 enable initiator \n" + "\tusage: wl rmc_ackreq [mode] \n" + }, + { "rmc_txrate", wl_phy_rate, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get a fixed transmit rate for the reliable multicast:\n" + "\tvalid values for 802.11ac are (6, 9, 12, 18, 24, 36, 48, 54)\n" + "\t-1 (default) means automatically determine the best rate\n" + }, + { "rmc_status", wl_mcast_status, WLC_GET_VAR, -1, + "Display reliable multicast client status\n" + }, + { "rmc_actf_time", wl_mcast_actf_time, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get mcast action frame tx time period in ms\n" + "\tusage: wl rmc_actf_time [value] \n" + }, + { "rmc_ar_timeout", wl_mcast_ar_timeout, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get rmc active receiver timeout in ms\n" + "\tusage: wl rmc_ar_timeout [duration in ms] \n" + }, + { "rmc_rssi_thresh", wl_mcast_rssi_thresh, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get minimum rssi needed for a station to be an active receiver\n" + "\tusage: wl rmc_rssi_thresh [value] \n" + }, + { "rmc_stats", wl_mcast_stats, WLC_GET_VAR, WLC_SET_VAR, + "Display/Clear reliable multicast client statistical counters\n" + "\tusage: wl rmc_stats [arg] \n" + }, + { "rmc_rssi_delta", wl_mcast_rssi_delta, WLC_GET_VAR, WLC_SET_VAR, + "Display/Set RSSI delta to switch receive leader\n" + "\tusage: wl rmc_rssi_delta [arg] \n" + }, + { "rmc_vsie", wl_mcast_vsie, WLC_GET_VAR, WLC_SET_VAR, + "Display/Set vendor specific IE contents\n" + "\tusage: wl rmc_vsie [OUI] [Data] \n" + }, + { "pm2_sleep_ret_ext", wl_sleep_ret_ext, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set Dynamic Fast Return To Sleep params"}, + { "sta_monitor", wl_stamon_sta_config, WLC_GET_VAR, WLC_SET_VAR, + "wl sta_monitor [<add/del> <xx:xx:xx:xx:xx:xx>]"}, + { "monitor_promisc_level", wl_monitor_promisc_level, WLC_GET_VAR, WLC_SET_VAR, + "Set a bitmap of different MAC promiscuous level of monitor mode.\n\n" + MONITOR_PROMISC_LEVEL_USAGE}, +#if defined(DWDS) + { "dwds_config", wl_dwds_config, -1, WLC_SET_VAR, + "wl dwds_config <enable/disable> <sta/ap> <xx:xx:xx:xx:xx:xx>"}, +#endif + { "aibss_bcn_force_config", wl_aibss_bcn_force_config, WLC_GET_VAR, WLC_SET_VAR, + "Get/Set AIBSS beacon force configuration \n" + "wl aibss_bcn_force_config <initial_min_bcn_dur,min_bcn_dur,initial_bcn_flood_dur>\n"}, + {"bcnlenhist", wl_bcnlenhist, WLC_GET_VAR, -1, + "Usage: wl bcnlenhist [0]"}, + { "wds_type", wl_varint, WLC_GET_VAR, -1, + "Indicate whether the interface to which this IOVAR is sent is of WDS or DWDS type.\n\n" + WDS_TYPE_USAGE}, + { "bss_peer_info", wl_bss_peer_info, WLC_GET_VAR, -1, + "Get BSS peer info of all the peer's in the indivudual interface\n" + "\tIf a non-zero MAC address is specified, gets the peer info of the PEER alone\n" + "\tUsage: wl bss_peer_info [MAC address]"}, + { "bssload_static", wl_bssload_static, WLC_GET_VAR, WLC_SET_VAR, + "get or set static BSS load\n" + "\tusage: wl bssload_static [off | <sta_count> <chan_util> <acc>]\n"}, + { "aibss_txfail_config", wl_aibss_txfail_config, WLC_GET_VAR, WLC_SET_VAR, + "Set/Get txfail configuration for bcn_timeout and max tx retries\n" + "\tUsage: wl aibss_txfail_config [bcn_timeout, max_retry]"}, +#ifdef TBTT_OFFSET_STAT + { "tbtt_offset_stat", wl_tbtt_offset_stat, WLC_GET_VAR, -1, + "Get TBTT offset stat (only for STA mode)\n" + "\tUsage: wl tbtt_offset_stat\n"}, +#endif /* TBTT_OFFSET_STAT */ +#endif + { NULL, NULL, 0, 0, NULL } +}; + +cmd_t wl_varcmd = {"var", wl_varint, -1, -1, "unrecognized name, type -h for help"}; + +#ifdef WC_TOOL +/* Include any commands for wc tool used for WMM + * These need to be only the command names from port_cmds and wl_cmds array + */ +static const char *wc_cmds[] = { + "ver", "cmds", "up", "down", + "gmode", "listen", "wme", "wme_ac", "wme_apsd", + "wme_apsd_sta", "wme_dp" +}; +#else +static const char **wc_cmds = NULL; +#endif /* WC_TOOL */ + +/* initialize stuff needed before processing the command */ +void +wl_cmd_init(void) +{ + int_fmt = INT_FMT_DEC; + g_wlc_idx = -1; +} + + +void +wlu_init(void) +{ + /* Init global variables at run-time, not as part of the declaration. + * This is required to support init/de-init of the driver. Initialization + * of globals as part of the declaration results in non-deterministic + * behaviour since the value of the globals may be different on the + * first time that the driver is initialized vs subsequent initializations. + */ + int_fmt = INT_FMT_DEC; + g_wlc_idx = -1; + batch_in_client = FALSE; + init_cmd_batchingmode(); +} + +int +wl_check(void *wl) +{ + int ret; + int val; + + if ((ret = wlu_get(wl, WLC_GET_MAGIC, &val, sizeof(int))) < 0) + return ret; + + /* Detect if IOCTL swapping is necessary */ + if (val == (int)bcmswap32(WLC_IOCTL_MAGIC)) + { + val = bcmswap32(val); + g_swap = TRUE; + } + if (val != WLC_IOCTL_MAGIC) + return -1; + if ((ret = wlu_get(wl, WLC_GET_VERSION, &val, sizeof(int))) < 0) + return ret; + ioctl_version = dtoh32(val); + if (ioctl_version != WLC_IOCTL_VERSION && + ioctl_version != 1) { + fprintf(stderr, "Version mismatch, please upgrade. Got %d, expected %d or 1\n", + ioctl_version, WLC_IOCTL_VERSION); + return -1; + } + return 0; +} + +static int +ARGCNT(char **argv) +{ + int i; + + for (i = 0; argv[i] != NULL; i ++) + ; + return i; +} + +/* parse/validate the command line arguments */ +/* + * pargv is updated upon return if the first argument is an option. + * It remains intact otherwise. + */ +int +wl_option(char ***pargv, char **pifname, int *phelp) +{ + char *ifname = NULL; + int help = FALSE; + int status = CMD_OPT; + char **argv = *pargv; + + while (*argv) { + /* select different adapter */ + if (!strcmp(*argv, "-a") || !strcmp(*argv, "-i")) { + char *opt = *argv++; + ifname = *argv; + if (!ifname) { + fprintf(stderr, + "error: expected interface name after option %s\n", opt); + status = CMD_ERR; + break; + } + } + + /* integer output format */ + else if (!strcmp(*argv, "-d")) + int_fmt = INT_FMT_DEC; + else if (!strcmp(*argv, "-u")) + int_fmt = INT_FMT_UINT; + else if (!strcmp(*argv, "-x")) + int_fmt = INT_FMT_HEX; + + /* command usage */ + else if (!strcmp(*argv, "-h") || !strcmp(*argv, "--help")) + help = TRUE; + + else if (!strcmp(*argv, "--clientbatch")) { + wl_seq_batch_in_client(TRUE); + } + /* To handle endian mis-matches between wl utility and wl driver */ + else if (!strcmp(*argv, "--es")) { + g_swap = TRUE; + } + else if (!stricmp(*argv, "-W") || !strcmp(*argv, "--wlc")) { + char *opt = *argv++; + char *endptr = NULL; + if (*argv) { + g_wlc_idx = strtol(*argv, &endptr, 0); + } + if (endptr == *argv) { + fprintf(stderr, + "error: expected wlc integer index after option %s\n", opt); + status = CMD_ERR; + /* just to ensure that we trigger error */ + argv--; + break; + } + } + /* start of non wl options */ + else { + status = CMD_WL; + break; + } + + /* consume the argument */ + argv ++; + break; + } + + *phelp = help; + *pifname = ifname; + *pargv = argv; + + return status; +} + +void +wl_cmd_usage(FILE *fid, cmd_t *cmd) +{ + if (strlen(cmd->name) >= 8) + fprintf(fid, "%s\n\t%s\n\n", cmd->name, cmd->help); + else + fprintf(fid, "%s\t%s\n\n", cmd->name, cmd->help); +} + +static int +wl_print_deprecate(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(argv); + + wl_cmd_usage(stderr, cmd); /* warning string is in command table */ + return 0; +} + +/* Dump out short list of commands */ +static int +wl_list(void *wl, cmd_t *garb, char **argv) +{ + cmd_t *cmd; + int nrows, i, len; + char *list_buf; + int letter, col, row, pad; + + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(garb); + UNUSED_PARAMETER(argv); + + for (cmd = wl_cmds, nrows = 0; cmd->name; cmd++) + /* Check for wc_cmd */ + if (wc_cmd_check(cmd->name)) + nrows++; + + nrows /= 4; + nrows++; + + len = nrows * 80 + 2; + list_buf = malloc(len); + if (list_buf == NULL) { + fprintf(stderr, "Failed to allocate buffer of %d bytes\n", len); + return BCME_NOMEM; + } + for (i = 0; i < len; i++) + *(list_buf+i) = 0; + + row = col = 0; + for (letter = 'a'; letter < 'z'; letter++) { + for (cmd = wl_cmds; cmd->name; cmd++) { + /* Check for wc_cmd */ + if (!wc_cmd_check(cmd->name)) + continue; + if (cmd->name[0] == letter || cmd->name[0] == letter - 0x20) { + strcat(list_buf+row*80, cmd->name); + pad = 18 * (col + 1) - strlen(list_buf+row*80); + if (pad < 1) + pad = 1; + for (; pad; pad--) + strcat(list_buf+row*80, " "); + row++; + if (row == nrows) { + col++; row = 0; + } + } + } + } + for (row = 0; row < nrows; row++) + printf("%s\n", list_buf+row*80); + + printf("\n"); + + free(list_buf); + return (0); +} + +void +wl_cmds_usage(FILE *fid, cmd_t *port_cmds) +{ + cmd_t *port_cmd; + cmd_t *cmd; + + /* print usage of port commands */ + for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++) + /* Check for wc_cmd */ + if (wc_cmd_check(port_cmd->name)) + wl_cmd_usage(fid, port_cmd); + + /* print usage of common commands without port counterparts */ + for (cmd = wl_cmds; cmd->name; cmd++) { + /* search if port counterpart exists */ + for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++) + if (!strcmp(port_cmd->name, cmd->name)) + break; + /* Also, check for this being a wc_cmd */ + if ((!port_cmd || !port_cmd->name) && (wc_cmd_check(cmd->name))) + wl_cmd_usage(fid, cmd); + } +} + +void +wl_usage(FILE *fid, cmd_t *port_cmds) +{ + fprintf(fid, "Usage: %s [-a|i <adapter>]" + " [-h] [-d|u|x] [-w|--wlc <index>] <command> [arguments]\n", wlu_av0); + + fprintf(fid, "\n"); + fprintf(fid, " -h this message and command descriptions\n"); + fprintf(fid, " -h [cmd] command description for cmd\n"); + fprintf(fid, " -a, -i adapter name or number\n"); + fprintf(fid, " -d output format signed integer\n"); + fprintf(fid, " -u output format unsigned integer\n"); + fprintf(fid, " -x output format hexdecimal\n"); + fprintf(fid, " -w <idx> index of WLC for RSDB only\n"); + fprintf(fid, "\n"); + + wl_cmds_usage(fid, port_cmds); +} + +void +wl_printint(int val) +{ + switch (int_fmt) { + case INT_FMT_UINT: + printf("%u\n", val); + break; + case INT_FMT_HEX: + printf("0x%x\n", val); + break; + case INT_FMT_DEC: + default: + printf("%d\n", val); + break; + } +} + + +/* Common routine to check for an option arg specifying the configuration index. + * Takes the syntax -C num, --cfg=num, --config=num, or --configuration=num + * Returns BCME_BADARG if there is a command line parsing error. + * Returns 0 if no error, and sets *consumed to the number of argv strings + * used. Sets *bsscfg_idx to the index to use. Will set *bsscfg_idx to zero if there + * was no config arg. + */ +static int +wl_cfg_option(char **argv, const char *fn_name, int *bsscfg_idx, int *consumed) +{ + miniopt_t mo; + int opt_err; + + *bsscfg_idx = 0; + *consumed = 0; + + miniopt_init(&mo, fn_name, NULL, FALSE); + + /* process the first option */ + opt_err = miniopt(&mo, argv); + + /* check for no args or end of options */ + if (opt_err == -1) + return 0; + + /* check for no options, just a positional arg encountered */ + if (mo.positional) + return 0; + + /* check for error parsing options */ + if (opt_err == 1) + return BCME_USAGE_ERROR; + + /* check for -C, --cfg=X, --config=X, --configuration=X */ + if (mo.opt == 'C' || + !strcmp(mo.key, "cfg") || + !strcmp(mo.key, "config") || + !strcmp(mo.key, "configuration")) { + if (!mo.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an integer for the configuartion index\n", + fn_name, mo.valstr); + return BCME_BADARG; + } + *bsscfg_idx = mo.val; + *consumed = mo.consumed; + } + + return 0; +} + +static int +wl_void(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(argv); + + if (cmd->set < 0) + return -1; + return wlu_set(wl, cmd->set, NULL, 0); +} + +int +wl_int(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + char *endptr = NULL; + + if (!*++argv) { + if (cmd->get == -1) + return -1; + if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0) + return ret; + + val = dtoh32(val); + wl_printint(val); + } else { + if (cmd->set == -1) + return -1; + if (!stricmp(*argv, "on")) + val = 1; + else if (!stricmp(*argv, "off")) + val = 0; + else { + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + } + + val = htod32(val); + ret = wlu_set(wl, cmd->set, &val, sizeof(int)); + } + + return ret; +} + +/* Return a new chanspec given a legacy chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_from_legacy(chanspec_t legacy_chspec) +{ + chanspec_t chspec; + + /* get the channel number */ + chspec = LCHSPEC_CHANNEL(legacy_chspec); + + /* convert the band */ + if (LCHSPEC_IS2G(legacy_chspec)) { + chspec |= WL_CHANSPEC_BAND_2G; + } else { + chspec |= WL_CHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (LCHSPEC_IS20(legacy_chspec)) { + chspec |= WL_CHANSPEC_BW_20; + } else { + chspec |= WL_CHANSPEC_BW_40; + if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { + chspec |= WL_CHANSPEC_CTL_SB_L; + } else { + chspec |= WL_CHANSPEC_CTL_SB_U; + } + } + + if (wf_chspec_malformed(chspec)) { + fprintf(stderr, "wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", + chspec); + return INVCHANSPEC; + } + + return chspec; +} + +/* Return a legacy chanspec given a new chanspec + * Returns INVCHANSPEC on error + */ +chanspec_t +wl_chspec_to_legacy(chanspec_t chspec) +{ + chanspec_t lchspec; + + if (wf_chspec_malformed(chspec)) { + fprintf(stderr, "wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", + chspec); + return INVCHANSPEC; + } + + /* get the channel number */ + lchspec = CHSPEC_CHANNEL(chspec); + + /* convert the band */ + if (CHSPEC_IS2G(chspec)) { + lchspec |= WL_LCHANSPEC_BAND_2G; + } else { + lchspec |= WL_LCHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (CHSPEC_IS20(chspec)) { + lchspec |= WL_LCHANSPEC_BW_20; + lchspec |= WL_LCHANSPEC_CTL_SB_NONE; + } else if (CHSPEC_IS40(chspec)) { + lchspec |= WL_LCHANSPEC_BW_40; + if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { + lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; + } else { + lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; + } + } else { + /* cannot express the bandwidth */ + char chanbuf[CHANSPEC_STR_LEN]; + fprintf(stderr, + "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " + "to pre-11ac format\n", + wf_chspec_ntoa(chspec, chanbuf), chspec); + return INVCHANSPEC; + } + + return lchspec; +} + +/* given a chanspec value, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_to_driver(chanspec_t chanspec) +{ + if (ioctl_version == 1) { + chanspec = wl_chspec_to_legacy(chanspec); + if (chanspec == INVCHANSPEC) { + return chanspec; + } + } + chanspec = htodchanspec(chanspec); + + return chanspec; +} + +/* given a chanspec value, do the endian and chanspec version conversion to + * a chanspec_t value in a 32 bit integer + * Returns INVCHANSPEC on error + */ +static uint32 +wl_chspec32_to_driver(chanspec_t chanspec) +{ + uint32 val; + + if (ioctl_version == 1) { + chanspec = wl_chspec_to_legacy(chanspec); + if (chanspec == INVCHANSPEC) { + return chanspec; + } + } + val = htod32((uint32)chanspec); + + return val; +} + +/* given a chanspec value from the driver, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_from_driver(chanspec_t chanspec) +{ + chanspec = dtohchanspec(chanspec); + if (ioctl_version == 1) { + chanspec = wl_chspec_from_legacy(chanspec); + } + + return chanspec; +} + +/* given a chanspec value from the driver in a 32 bit integer, do the endian and + * chanspec version conversion to a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec32_from_driver(uint32 chanspec32) +{ + chanspec_t chanspec; + + chanspec = (chanspec_t)dtoh32(chanspec32); + + if (ioctl_version == 1) { + chanspec = wl_chspec_from_legacy(chanspec); + } + + return chanspec; +} + + +#ifdef CLMDOWNLOAD +/* +Generic interface for downloading required data onto the dongle +*/ +int +download2dongle(void *wl, uint16 dload_type, unsigned char *dload_buf, int len) +{ + struct wl_dload_data *dload_ptr = (struct wl_dload_data *)dload_buf; + int err = 0; + int dload_data_offset; + + dload_data_offset = OFFSETOF(wl_dload_data_t, data); + dload_ptr->flag = (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT); + dload_ptr->dload_type = dload_type; + dload_ptr->len = htod32(len - dload_data_offset); + + dload_ptr->crc = 0; + + len = len + 8 - (len%8); + + err = wlu_iovar_setbuf(wl, "generic_dload", + dload_buf, len, buf, WLC_IOCTL_MEDLEN); + return err; +} + +int +dload_clm(void *wl, uint32 datalen, unsigned char *org_buf, int ds_id) +{ + int num_chunks, chunk_len, cumulative_len = 0; + int size2alloc; + unsigned char *new_buf; + wl_clm_dload_info_t *clm_info_ptr; + int err = 0, clm_info_offset, chunk_offset; + + clm_info_offset = OFFSETOF(wl_dload_data_t, data); + chunk_offset = OFFSETOF(wl_clm_dload_info_t, data_chunk); + + num_chunks = datalen/MAX_CHUNK_LEN; + if (datalen % MAX_CHUNK_LEN != 0) + num_chunks++; + size2alloc = clm_info_offset + chunk_offset + MAX_CHUNK_LEN; + + if ((new_buf = (unsigned char *)malloc(size2alloc)) != NULL) { + memset(new_buf, 0, size2alloc); + clm_info_ptr = (wl_clm_dload_info_t*)((uint8 *)new_buf + clm_info_offset); + clm_info_ptr->num_chunks = num_chunks; + clm_info_ptr->clm_total_len = datalen; + clm_info_ptr->ds_id = ds_id; + do { + if (datalen >= MAX_CHUNK_LEN) + chunk_len = MAX_CHUNK_LEN; + else + chunk_len = datalen; + memset(new_buf + clm_info_offset + chunk_offset, 0, + size2alloc - clm_info_offset - chunk_offset); + clm_info_ptr->chunk_len = htod32(chunk_len); + + memcpy(&clm_info_ptr->data_chunk[0], org_buf + cumulative_len, chunk_len); + clm_info_ptr->chunk_offset = cumulative_len; + cumulative_len += chunk_len; + + err = download2dongle(wl, DL_TYPE_CLM, new_buf, + chunk_len + clm_info_offset + chunk_offset); + + datalen = datalen - chunk_len; + } while ((datalen > 0) && (err == 0)); + free(new_buf); + } else { + err = BCME_NOMEM; + } + + return err; +} + +#define CLM_INPUT_FILE_MIN_LEN 32 +int +process_clm_data(void *wl, char *clmfn, int ds_id) +{ + int ret = 0; + + FILE *fp = NULL; + + unsigned int clm_filelen; + struct stat filest; + unsigned long status = 0; + unsigned char *new_buf = NULL; + uint32 clm_data_len; + unsigned char *new_ptr; + int ifd; + const char trx_magic_string[] = {'H', 'D', 'R', '0'}; + const char clm_magic_string[] = {'C', 'L', 'M', ' ', 'D', 'A', 'T', 'A'}; + + if (clmfn == NULL) { + printf("Reverting any previous %s CLM download\n", + ds_id ? "incremental":"base"); + /* Performing a zero length CLM download reverts the previous download + * of that type. + */ + clm_data_len = 0; + new_ptr = NULL; + goto do_clm_load; + } + + /* Open the clm download file */ + if (!(fp = fopen(clmfn, "rb"))) { + fprintf(stderr, "unable to open input file %s\n", clmfn); + ret = BCME_BADARG; + goto error; + } + + ifd = fileno(fp); + + if (fstat(ifd, &filest)) { + fprintf(stderr, "fstat on input file %s return error %s\n", clmfn, strerror(errno)); + ret = BCME_ERROR; + goto error; + } + + clm_filelen = filest.st_size; + + if (clm_filelen == 0) { + fprintf(stderr, "input file %s is empty (i.e. zero length)\n", clmfn); + ret = BCME_ERROR; + goto error; + } + + if ((new_buf = malloc(clm_filelen)) == NULL) { + fprintf(stderr, "unable to allocate %u bytes based on input file size!\n", + clm_filelen); + ret = BCME_NOMEM; + goto error; + } + + /* We can read the pure CLM binary file or a trx format wrapped CLM binary. + * The CLM download iovar receives the CLM binary file content so any difference + * in processing is limited to our local processing. + * + * The trx wrapped CLM binary was the original approach but it now being phased + * out for the simpler, non-wrapped binary. To maintain backward compatibility + * for some period of time, wlu is accepting both formats transparently to the + * user. The two file types are identified by the magic word(s) at the beginning + * of each. A trx file starts with "HDR0" and a CLM binary starts with "CLM DATA". + */ + + status = fread(new_buf, 1, clm_filelen, fp); + + /* Basic sanity check on size. Make sure there is enough for any magic string plus + * a little more for good measure. + */ + if (status < CLM_INPUT_FILE_MIN_LEN) { + fprintf(stderr, "size of input file %s is less than %d bytes." + " This can't be a CLM file!\n", clmfn, CLM_INPUT_FILE_MIN_LEN); + ret = BCME_ERROR; + goto error; + } else if (status != clm_filelen) { + fprintf(stderr, "read of input file %s wasn't good based on fstat size %u\n", + clmfn, clm_filelen); + ret = BCME_ERROR; + goto error; + } + + /* trx wrapped CLM binary file? Look for the 'HDR0' magic string */ + if (memcmp(new_buf, trx_magic_string, sizeof(trx_magic_string)) == 0) + { + struct trx_header *trx; + + /* Extract trx header */ + trx = (struct trx_header *)new_buf; + + /* The clm binary data follows the trx header and the length is the trx + * header's first offset field. All other trx header files are unused. + * Note length in the offset doesn't include the trx header or any + * trailing/padding zeroes add by the trx format. + */ + clm_data_len = trx->offsets[0]; + + /* A sanity testing on length value in the trx offset field. It can't + * indicate the following CLM data is bigger than the actual file. + */ + if (clm_data_len + sizeof(struct trx_header) > clm_filelen) { + fprintf(stderr, + "input file %s trx offset[0] is inconsistent" + " for being a CLM file\n", + clmfn); + ret = -1; + goto error; + } + new_ptr = new_buf + sizeof(struct trx_header); + } else if (memcmp(new_buf, clm_magic_string, sizeof(clm_magic_string)) == 0) { + /* pure CLM binary file? CLM binary files start with 'CLM DATA' */ + clm_data_len = clm_filelen; + new_ptr = new_buf; + } else { + fprintf(stderr, "input file is missing trx or CLM binary magic string\n"); + ret = -1; + goto error; + } + + printf("Downloading file %s as a %s CLM\n", clmfn, ds_id ? "incremental":"base"); + +do_clm_load: + ret = dload_clm(wl, clm_data_len, new_ptr, ds_id); + +error: + if (new_buf) + free(new_buf); + if (fp) + fclose(fp); + + return ret; +} + +static int +wl_clmload(void *wl, cmd_t *cmd, char **argv) +{ + int ret = 0; + + ++argv; + if (cmd->set == -1) + return -1; + { + int ds_id = atoi(*argv); + char* fname = *++argv; + + if ((ds_id == 0) || (ds_id == 1)) + ret = process_clm_data(wl, fname, ds_id); + } + return ret; +} +#endif /* CLMDOWNLOAD */ + +static int +wl_bsscfg_int(void *wl, cmd_t *cmd, char **argv) +{ + char *endptr = NULL; + char *val_name; + int bsscfg_idx = 0; + int val = 0; + int consumed; + int ret; + + val_name = *argv++; + + /* parse a bsscfg_idx option if present */ + if ((ret = wl_cfg_option(argv, val_name, &bsscfg_idx, &consumed)) != 0) + return ret; + + /* handle a bsscfg int with a legacy ioctl */ + if (consumed == 0 && cmd->set != WLC_SET_VAR) { + /* back up to the orig command and run as an ioctl int */ + argv--; + return wl_int(wl, cmd, argv); + } + + argv += consumed; + + if (!*argv) { + /* This is a GET */ + if (cmd->get == -1) + return -1; + + if (consumed == 0) + ret = wlu_iovar_getint(wl, val_name, &val); + else + ret = wl_bssiovar_getint(wl, val_name, bsscfg_idx, &val); + + if (ret < 0) + return ret; + + wl_printint(val); + } else { + /* This is a SET */ + if (cmd->set == -1) + return -1; + + if (!stricmp(*argv, "on")) + val = 1; + else if (!stricmp(*argv, "off")) + val = 0; + else { + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + } + + if (consumed == 0) + ret = wlu_iovar_setint(wl, val_name, val); + else + ret = wl_bssiovar_setint(wl, val_name, bsscfg_idx, val); + } + + return ret; +} + +static int +wl_bsscfg_enable(void *wl, cmd_t *cmd, char **argv) +{ + char *endptr; + const char *val_name = "bss"; + int bsscfg_idx = 0; + int val; + int consumed; + int ret; + + UNUSED_PARAMETER(cmd); + + /* skip the command name */ + argv++; + + /* parse a bsscfg_idx option if present */ + if ((ret = wl_cfg_option(argv, val_name, &bsscfg_idx, &consumed)) != 0) + return ret; + + argv += consumed; + if (consumed == 0) { /* Use the -i parameter if that was present */ + bsscfg_idx = -1; + } + + if (!*argv) { + bsscfg_idx = htod32(bsscfg_idx); + ret = wlu_iovar_getbuf(wl, val_name, &bsscfg_idx, sizeof(bsscfg_idx), + buf, WLC_IOCTL_MAXLEN); + if (ret < 0) + return ret; + val = *(int*)buf; + val = dtoh32(val); + if (val) + printf("up\n"); + else + printf("down\n"); + return 0; + } else { + struct { + int cfg; + int val; + } bss_setbuf; + if (!stricmp(*argv, "ap")) + val = 3; + else if (!stricmp(*argv, "sta")) + val = 2; + else if (!stricmp(*argv, "up")) + val = 1; + else if (!stricmp(*argv, "down")) + val = 0; + else if (!stricmp(*argv, "del")) + val = -1; + else { + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + } + bss_setbuf.cfg = htod32(bsscfg_idx); + bss_setbuf.val = htod32(val); + + return wlu_iovar_set(wl, val_name, &bss_setbuf, sizeof(bss_setbuf)); + } +} + +/* Get/Set the gmode config */ +static int +wl_gmode(void *wl, cmd_t *cmd, char **argv) +{ + char *endptr = NULL; + int ret = 0, val; + + if (!*++argv) { + const char *gconfig; + + /* Get the current G mode */ + if ((ret = wlu_get(wl, cmd->get, &val, sizeof(val))) < 0) + return ret; + + val = dtoh32(val); + switch (val) { + case GMODE_LEGACY_B: + gconfig = "54g Legacy B"; + break; + case GMODE_AUTO: + gconfig = "54g Auto"; + break; + case GMODE_ONLY: + gconfig = "54g Only"; + break; + case GMODE_PERFORMANCE: + gconfig = "54g Performance"; + break; + case GMODE_LRS: + gconfig = "54g LRS"; + break; + default: + gconfig = "unknown"; + break; + } + + printf("%s (%d)\n", gconfig, val); + + } else { + /* Set the new G mode */ + + if (!strnicmp(*argv, "legacy", 6)) + val = GMODE_LEGACY_B; + else if (!strnicmp(*argv, "auto", 4)) + val = GMODE_AUTO; + else if (!strnicmp(*argv, "gonly", 5)) + val = GMODE_ONLY; + else if (!strnicmp(*argv, "perf", 4)) + val = GMODE_PERFORMANCE; + else if (!strnicmp(*argv, "lrs", 3)) + val = GMODE_LRS; + else { + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + } + + /* Set the gmode configration */ + val = htod32(val); + if ((ret = wlu_set(wl, cmd->set, &val, sizeof(val)))) + goto done; + + } + +done: + return (ret); +} + +static dbg_msg_t wl_sd_msgs[] = { + {SDH_ERROR_VAL, "error"}, + {SDH_TRACE_VAL, "trace"}, + {SDH_INFO_VAL, "info"}, + {SDH_DATA_VAL, "data"}, + {SDH_CTRL_VAL, "control"} +}; + +static int +wl_sd_msglevel(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + uint val, last_val = 0, msglevel_add = 0, msglevel_del = 0; + char *endptr = NULL; + int msglevel; + dbg_msg_t *dbg_msg = wl_sd_msgs; + + if ((ret = wlu_iovar_getint(wl, cmd->name, &msglevel)) < 0) + return (ret); + + if (!*++argv) { + printf("0x%x ", msglevel); + for (i = 0; (val = dbg_msg[i].value); i++) { + if ((msglevel & val) && (val != last_val)) + printf(" %s", dbg_msg[i].string); + last_val = val; + } + printf("\n"); + return (0); + } + + while (*argv) { + char *s = *argv; + if (*s == '+' || *s == '-') + s++; + else + msglevel_del = ~0; /* make the whole list absolute */ + val = strtoul(s, &endptr, 0); + /* not a plain integer if not all the string was parsed by strtoul */ + if (*endptr != '\0') { + for (i = 0; (val = dbg_msg[i].value); i++) + if (stricmp(dbg_msg[i].string, s) == 0) + break; + if (!val) + goto usage; + } + if (**argv == '-') + msglevel_del |= val; + else + msglevel_add |= val; + ++argv; + } + + msglevel &= ~msglevel_del; + msglevel |= msglevel_add; + + return (wlu_iovar_setint(wl, cmd->name, msglevel)); + +usage: + fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n"); + fprintf(stderr, "Use a + or - prefix to make an incremental change."); + + for (i = 0; (val = dbg_msg[i].value); i++) { + if (val != last_val) + fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string); + else + fprintf(stderr, ", %s", dbg_msg[i].string); + last_val = val; + } + fprintf(stderr, "\n"); + + return 0; +} + +static int +wl_sd_blocksize(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int argc; + char *endptr = NULL; + void *ptr = NULL; + int func, size; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (argc < 1 || argc > 2) { + printf("required args: function [size] (size 0 means max)\n"); + return BCME_USAGE_ERROR; + } + + func = strtol(argv[1], &endptr, 0); + if (*endptr != '\0') { + printf("Invaild function: %s\n", argv[1]); + return BCME_USAGE_ERROR; + } + + if (argc > 1) { + size = strtol(argv[2], &endptr, 0); + if (*endptr != '\0') { + printf("Invalid size: %s\n", argv[1]); + return BCME_USAGE_ERROR; + } + } + + if (argc == 1) { + func = htod32(func); + if ((ret = wlu_var_getbuf(wl, cmd->name, &func, sizeof(func), &ptr)) >= 0) + printf("Function %d block size: %d\n", func, dtoh32(*(int*)ptr)); + } else { + printf("Setting function %d block size to %d\n", func, size); + size &= 0x0000ffff; size |= (func << 16); + size = htod32(size); + ret = wlu_var_setbuf(wl, cmd->name, &size, sizeof(size)); + } + + return (ret); +} + +static int +wl_sd_mode(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int argc; + int sdmode; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (argv[1]) { + if (!strcmp(argv[1], "spi")) { + strcpy(argv[1], "0"); + } else if (!strcmp(argv[1], "sd1")) { + strcpy(argv[1], "1"); + } else if (!strcmp(argv[1], "sd4")) { + strcpy(argv[1], "2"); + } else { + return BCME_USAGE_ERROR; + } + + ret = wl_var_setint(wl, cmd, argv); + + } else { + if ((ret = wl_var_get(wl, cmd, argv))) { + return (ret); + } else { + sdmode = dtoh32(*(int32*)buf); + + printf("SD Mode is: %s\n", + sdmode == 0 ? "SPI" + : sdmode == 1 ? "SD1" + : sdmode == 2 ? "SD4" : "Unknown"); + } + } + + return (ret); +} + +static int +wl_sd_reg(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + sdreg_t sdreg; + char *endptr = NULL; + uint argc; + void *ptr = NULL; + + memset(&sdreg, 0, sizeof(sdreg)); + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + /* hostreg: offset [value]; devreg: func offset [value] */ + if (!strcmp(cmd->name, "sd_hostreg")) { + argv++; + if (argc < 1) { + printf("required args: offset [value]\n"); + return BCME_USAGE_ERROR; + } + + } else if (!strcmp(cmd->name, "sd_devreg")) { + argv++; + if (argc < 2) { + printf("required args: func offset [value]\n"); + return BCME_USAGE_ERROR; + } + + sdreg.func = htod32(strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') { + printf("Bad func.\n"); + return BCME_USAGE_ERROR; + } + } else { + return BCME_USAGE_ERROR; + } + + sdreg.offset = htod32(strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') { + printf("Bad offset\n"); + return BCME_USAGE_ERROR; + } + + /* third arg: value */ + if (*argv) { + sdreg.value = htod32(strtol(*argv, &endptr, 0)); + if (*endptr != '\0') { + printf("Bad Value\n"); + return BCME_USAGE_ERROR; + } + } + + /* no third arg means get, otherwise set */ + if (!*argv) { + if ((ret = wlu_var_getbuf(wl, cmd->name, &sdreg, sizeof(sdreg), &ptr)) >= 0) + printf("0x%x\n", dtoh32(*(int *)ptr)); + } else { + ret = wlu_var_setbuf(wl, cmd->name, &sdreg, sizeof(sdreg)); + } + + return (ret); +} + +static int +wl_overlay(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int argc; + char *endptr = NULL; + void *ptr = NULL; + int param[3]; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (argc < 1 || argc > 3) { + printf("required args: virt_addr phy_addr size\n"); + return BCME_USAGE_ERROR; + } + + param[0] = strtol(argv[1], &endptr, 0); + if (*endptr != '\0' || (param[0] & ~0x003FFE00) != 0) { + printf("Invaild virtual address: %s\n", argv[1]); + return BCME_BADARG; + } + + if (argc == 1) { + if ((ret = wlu_var_getbuf(wl, cmd->name, param, sizeof(int), &ptr)) >= 0) { + wl_hexdump((uchar *)ptr, 512); + } + return (ret); + } + + param[1] = strtol(argv[2], &endptr, 0); + if (*endptr != '\0' || (param[1] & ~0x003FFE00) != 0) { + printf("Invaild physical Address: %s\n", argv[2]); + return BCME_BADARG; + } + + if (argc == 3) { + param[2] = strtol(argv[3], &endptr, 0); + if (*endptr != '\0' || param[2] < 0 || param[2] > 7) { + printf("Invaild size: %s\n", argv[3]); + return BCME_BADARG; + } + } else { + param[2] = 0; + } + + printf("Setting virtual Address 0x%x to physical Address 0x%x, size is %d\n", + param[0], param[1], param[2]); + ret = wlu_var_setbuf(wl, cmd->name, param, sizeof(param)); + + return (ret); +} + +static int +wl_reg(void *wl, cmd_t *cmd, char **argv) +{ + int reg; + int ret; + struct { + int val; + int band; + } x; + char *endptr = NULL; + uint argc; + bool core_cmd; + wlc_rev_info_t revinfo; + uint32 phytype; + + /* eat command name */ + argv++; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* required arg: reg offset */ + if (argc < 1) + return BCME_USAGE_ERROR; + + reg = strtol(argv[0], &endptr, 0); + + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + x.val = 0; + x.band = WLC_BAND_AUTO; + core_cmd = FALSE; + + memset(&revinfo, 0, sizeof(revinfo)); + ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + if (ret) { + return ret; + } + phytype = dtoh32(revinfo.phytype); + + /* Second arg: value or band or "radio core" */ + if (argc >= 2) { + if (!stricmp(argv[1], "a")) + x.band = WLC_BAND_5G; + else if (!stricmp(argv[1], "b")) + x.band = WLC_BAND_2G; + else { + /* For NPHY Rev >= 3, the 2nd argument can be + the radio core + */ + if (strcmp(cmd->name, "radioreg") == 0) { + if (strcmp(argv[1], "syn") == 0) { + reg |= RADIO_CORE_SYN; + core_cmd = TRUE; + } else if (strcmp(argv[1], "tx0") == 0) { + reg |= RADIO_CORE_TX0; + core_cmd = TRUE; + } else if (strcmp(argv[1], "tx1") == 0) { + reg |= RADIO_CORE_TX1; + core_cmd = TRUE; + } else if (strcmp(argv[1], "rx0") == 0) { + reg |= RADIO_CORE_RX0; + core_cmd = TRUE; + } else if (strcmp(argv[1], "rx1") == 0) { + reg |= RADIO_CORE_RX1; + core_cmd = TRUE; + } + } + /* For HTPHY/ACPHY, the 2nd argument can be + the radio core + */ + if (strcmp(cmd->name, "radioreg") == 0) { + if (phytype == WLC_PHY_TYPE_AC) { + if (strcmp(argv[1], "cr0") == 0) { + reg |= RADIO_2069_CORE_CR0; + core_cmd = TRUE; + } else if (strcmp(argv[1], "cr1") == 0) { + reg |= RADIO_2069_CORE_CR1; + core_cmd = TRUE; + } else if (strcmp(argv[1], "cr2") == 0) { + reg |= RADIO_2069_CORE_CR2; + core_cmd = TRUE; + } else if (strcmp(argv[1], "pll") == 0) { + reg |= RADIO_2069_CORE_PLL; + core_cmd = TRUE; + } + } else { + if (strcmp(argv[1], "cr0") == 0) { + reg |= RADIO_CORE_CR0; + core_cmd = TRUE; + } else if (strcmp(argv[1], "cr1") == 0) { + reg |= RADIO_CORE_CR1; + core_cmd = TRUE; + } else if (strcmp(argv[1], "cr2") == 0) { + reg |= RADIO_CORE_CR2; + core_cmd = TRUE; + } + } + } + /* If the second argument is a value */ + if (!core_cmd) { + x.val = strtol(argv[1], &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + } + } + + /* Third arg: band OR "radio core" */ + if (argc >= 3) { + if (!stricmp(argv[2], "a")) + x.band = WLC_BAND_5G; + else if (!stricmp(argv[2], "b")) + x.band = WLC_BAND_2G; + else { + /* For NPHY Rev >= 3, the 3rd argument can be + the radio core + */ + core_cmd = FALSE; + if (strcmp(cmd->name, "radioreg") == 0) { + if (strcmp(argv[2], "syn") == 0) { + reg |= RADIO_CORE_SYN; + core_cmd = TRUE; + } else if (strcmp(argv[2], "tx0") == 0) { + reg |= RADIO_CORE_TX0; + core_cmd = TRUE; + } else if (strcmp(argv[2], "tx1") == 0) { + reg |= RADIO_CORE_TX1; + core_cmd = TRUE; + } else if (strcmp(argv[2], "rx0") == 0) { + reg |= RADIO_CORE_RX0; + core_cmd = TRUE; + } else if (strcmp(argv[2], "rx1") == 0) { + reg |= RADIO_CORE_RX1; + core_cmd = TRUE; + } + } + /* For HTPHY/ACPHY, the 3rd argument can be + the radio core + */ + if (phytype == WLC_PHY_TYPE_AC) { + if (strcmp(argv[2], "cr0") == 0) { + reg |= RADIO_2069_CORE_CR0; + core_cmd = TRUE; + } else if (strcmp(argv[2], "cr1") == 0) { + reg |= RADIO_2069_CORE_CR1; + core_cmd = TRUE; + } else if (strcmp(argv[2], "cr2") == 0) { + reg |= RADIO_2069_CORE_CR2; + core_cmd = TRUE; + } else if (strcmp(argv[2], "pll") == 0) { + reg |= RADIO_2069_CORE_PLL; + core_cmd = TRUE; + } else if (strcmp(argv[2], "all") == 0) { + reg |= RADIO_2069_CORE_ALL; + core_cmd = TRUE; + } + } else { + if (strcmp(cmd->name, "radioreg") == 0) { + if (strcmp(argv[2], "cr0") == 0) { + reg |= RADIO_CORE_CR0; + core_cmd = TRUE; + } else if (strcmp(argv[2], "cr1") == 0) { + reg |= RADIO_CORE_CR1; + core_cmd = TRUE; + } else if (strcmp(argv[2], "cr2") == 0) { + reg |= RADIO_CORE_CR2; + core_cmd = TRUE; + } else if (strcmp(argv[2], "all") == 0) { + reg |= RADIO_CORE_ALL; + core_cmd = TRUE; + } + } + } + + if (!core_cmd) { + return BCME_USAGE_ERROR; + } + } + } + + x.val = (x.val << 16) | (reg & 0xffff); + + /* issue the get or set ioctl */ + if ((argc == 1) || ((argc == 2) && ((x.band != WLC_BAND_AUTO) || core_cmd))) { + x.band = htod32(x.band); + x.val = htod32(x.val); + if ((ret = wlu_get(wl, cmd->get, &x, sizeof(x))) < 0) + return (ret); + printf("0x%04x\n", (uint16)(dtoh32(x.val))); + } else { + x.band = htod32(x.band); + x.val = htod32(x.val); + ret = wlu_set(wl, cmd->set, &x, sizeof(x)); + } + + return (ret); +} + +static int +wl_gpioout(void *wl, cmd_t *cmd, char **argv) +{ + uint32 mask; + uint32 val; + char *endptr = NULL; + uint argc; + uint32 *int_ptr; + + UNUSED_PARAMETER(cmd); + + val = 0; + + /* eat command name */ + argv++; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* Get and print the values */ + if (argc == 0) { + uint32 gpio_cntrl; + uint32 gpio_out; + uint32 gpio_outen; + int ret; + + if ((ret = wlu_iovar_get(wl, "gpioout", buf, sizeof(uint32) *3)) < 0) + return ret; + gpio_cntrl = dtoh32(((uint32 *)buf)[0]); + gpio_out = dtoh32(((uint32 *)buf)[1]); + gpio_outen = dtoh32(((uint32 *)buf)[2]); + + printf("gpiocontrol 0x%x gpioout 0x%x gpioouten 0x%x\n", gpio_cntrl, + gpio_out, gpio_outen); + + return 0; + } + + /* required arg: mask value */ + if (argc < 2) + return BCME_USAGE_ERROR; + + mask = strtoul(argv[0], &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + val = strtoul(argv[1], &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + if ((~mask & val) != 0) + return BCME_BADARG; + + int_ptr = (uint32 *)buf; + mask = htod32(mask); + memcpy(int_ptr, (const void *)&mask, sizeof(mask)); + int_ptr++; + val = htod32(val); + memcpy(int_ptr, (const void *)&val, sizeof(val)); + + return wlu_iovar_set(wl, "gpioout", buf, sizeof(uint32) *2); +} + +static int +wl_macreg(void *wl, cmd_t *cmd, char **argv) +{ + int reg; + int size; + uint32 val; + int ret; + char *endptr = NULL; + rw_reg_t rwt; + uint argc; + + val = 0; + + /* eat command name */ + argv++; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* required arg: reg offset */ + if (argc < 1) + return BCME_USAGE_ERROR; + + reg = strtol(argv[0], &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + /* required arg: reg size */ + if (argc < 2) + return BCME_USAGE_ERROR; + + size = strtol(argv[1], &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + rwt.band = WLC_BAND_AUTO; + + /* Third arg: new value or band */ + if (argc >= 3) { + if (!stricmp(argv[2], "a")) + rwt.band = WLC_BAND_5G; + else if (!stricmp(argv[2], "b")) + rwt.band = WLC_BAND_2G; + else { + val = strtoul(argv[2], &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + + } + + /* Fourth arg: band */ + if (argc >= 4) { + if (!stricmp(argv[3], "a")) + rwt.band = WLC_BAND_5G; + else if (!stricmp(argv[3], "b")) + rwt.band = WLC_BAND_2G; + else + return BCME_USAGE_ERROR; + } + + if ((argc == 2) || ((argc == 3) && (rwt.band != WLC_BAND_AUTO))) { + rwt.band = htod32(rwt.band); + rwt.byteoff = htod32(reg); + rwt.size = htod32(size); + if ((ret = wlu_get(wl, cmd->get, &rwt, sizeof(rw_reg_t))) < 0) + return (ret); + printf("0x%04x\n", dtoh32(rwt.val)); + } + else { + rwt.band = htod32(rwt.band); + rwt.byteoff = htod32(reg); + rwt.size = htod32(size); + rwt.val = htod32(val); + ret = wlu_set(wl, cmd->set, &rwt, sizeof(rw_reg_t)); + } + + return (ret); +} + +/* + * get or get a band specific variable + * the band can be a/b/all or omitted. "all"(set only) + * means all supported bands. blank means current band + */ +static int +wl_band_elm(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + struct { + int val; + int band; + } x; + char *endptr = NULL; + uint argc; + + /* eat command name */ + argv++; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + x.val = 0; + x.band = WLC_BAND_AUTO; + + /* First arg: value or band */ + if (argc >= 1) { + if (!stricmp(argv[0], "a")) + x.band = WLC_BAND_5G; + else if (!stricmp(argv[0], "b")) + x.band = WLC_BAND_2G; + else if (!stricmp(argv[0], "all")) + x.band = WLC_BAND_ALL; + else { + x.val = strtol(argv[0], &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + } + + /* Second arg: band */ + if (argc >= 2) { + if (!stricmp(argv[1], "a")) + x.band = WLC_BAND_5G; + else if (!stricmp(argv[1], "b")) + x.band = WLC_BAND_2G; + else if (!stricmp(argv[1], "all")) + x.band = WLC_BAND_ALL; + else + return BCME_USAGE_ERROR; + } + + /* issue the get or set ioctl */ + if ((argc == 0) || ((argc == 1) && (x.band != WLC_BAND_AUTO))) { + if (x.band == WLC_BAND_ALL) { + printf("band option \"all\" is for set only, not get\n"); + return BCME_USAGE_ERROR; + } + + x.band = htod32(x.band); + if ((ret = wlu_get(wl, cmd->get, &x, sizeof(x))) < 0) + return (ret); + + printf("%s is 0x%04x(%d)\n", cmd->name, (uint16)(dtoh32(x.val)), dtoh32(x.val)); + } else { + x.band = htod32(x.band); + x.val = htod32(x.val); + ret = wlu_set(wl, cmd->set, &x, sizeof(x)); + } + + return (ret); +} + +/* Command may or may not take a MAC address */ +static int +wl_rssi(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + scb_val_t scb_val; + int32 rssi; + + if (!*++argv) { + if ((ret = wlu_get(wl, cmd->get, &rssi, sizeof(rssi))) < 0) + return ret; + printf("%d\n", dtoh32(rssi)); + return 0; + } else { + if (!wl_ether_atoe(*argv, &scb_val.ea)) + return BCME_USAGE_ERROR; + if ((ret = wlu_get(wl, cmd->get, &scb_val, sizeof(scb_val))) < 0) + return ret; + printf("%d\n", dtoh32(scb_val.val)); + return 0; + } +} + +static int +wl_rssi_event(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + + if (!*++argv) { + /* get */ + void *ptr = NULL; + wl_rssi_event_t rssi; + uint i; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + memcpy(&rssi, ptr, sizeof(rssi)); + rssi.rate_limit_msec = dtoh32(rssi.rate_limit_msec); + + printf("%d", rssi.rate_limit_msec); + for (i = 0; i < rssi.num_rssi_levels; i++) { + printf(" %d", rssi.rssi_levels[i]); + } + printf("\n"); + } else { + /* set */ + wl_rssi_event_t rssi; + + memset(&rssi, 0, sizeof(wl_rssi_event_t)); + rssi.rate_limit_msec = atoi(*argv); + + while (*++argv && rssi.num_rssi_levels < MAX_RSSI_LEVELS) { + rssi.rssi_levels[rssi.num_rssi_levels++] = atoi(*argv); + if (rssi.num_rssi_levels > 1) { + if (rssi.rssi_levels[rssi.num_rssi_levels - 1] <= + rssi.rssi_levels[rssi.num_rssi_levels - 2]) { + /* rssi levels must be in increasing order */ + return BCME_USAGE_ERROR; + } + } + } + + if (*argv) { + /* too many parameters */ + return BCME_USAGE_ERROR; + } + + rssi.rate_limit_msec = htod32(rssi.rate_limit_msec); + ret = wlu_var_setbuf(wl, cmd->name, &rssi, sizeof(rssi)); + } + return ret; +} + +static int +wl_phy_rssi_ant(void *wl, cmd_t *cmd, char **argv) +{ + int ret = 0; + uint i; + wl_rssi_ant_t *rssi_ant_p; + + if (!*++argv) { + /* Get */ + void *ptr = NULL; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + rssi_ant_p = (wl_rssi_ant_t *)ptr; + rssi_ant_p->version = dtoh32(rssi_ant_p->version); + rssi_ant_p->count = dtoh32(rssi_ant_p->count); + + if (rssi_ant_p->count == 0) { + printf("not supported on this chip\n"); + } else { + for (i = 0; i < rssi_ant_p->count; i++) + printf("rssi[%d] %d ", i, rssi_ant_p->rssi_ant[i]); + printf("\n"); + } + } else { + ret = BCME_USAGE_ERROR; + } + return ret; +} + +/* Commands that take a MAC address */ +static int +wl_mac(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + struct ether_addr ea; + + if (!*++argv) { + if ((ret = wlu_get(wl, cmd->get, &ea, ETHER_ADDR_LEN)) < 0) + return ret; + printf("%s\n", wl_ether_etoa(&ea)); + return 0; + } else { + if (!wl_ether_atoe(*argv, &ea)) + return BCME_USAGE_ERROR; + return wlu_set(wl, cmd->set, &ea, ETHER_ADDR_LEN); + } +} + +/* IO variables that take a MAC address */ +static int +wl_iov_mac(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + struct ether_addr ea = {{0, 0, 0, 0, 0, 0}}; + + if (argv[1]) { /* set */ + if (!wl_ether_atoe(argv[1], &ea)) { + printf(" ERROR: no valid ether addr provided\n"); + return BCME_USAGE_ERROR; + } + if ((ret = wlu_iovar_set(wl, cmd->name, &ea, ETHER_ADDR_LEN)) < 0) { + printf("Error setting variable %s\n", argv[0]); + return ret; + } + return 0; + } else { /* get */ + if ((ret = wlu_iovar_get(wl, cmd->name, &ea, ETHER_ADDR_LEN)) < 0) { + printf("Error getting variable %s\n", argv[0]); + return ret; + } + printf("%s %s\n", argv[0], wl_ether_etoa(&ea)); + } + + return 0; +} + +static void +wl_txq_prec_dump(wl_iov_pktq_log_t* iov_pktq_log, bool hide_unknown, bool is_aqm) +{ +#define PREC_DUMPV(v4, v5) ((iov_pktq_log->version == 4) ? (v4) : (v5)) + +#define v4hstubL "prec: rqstd, stored,selfsave, saved,fulldrop, dropped," \ + "sacrficd, retried, rtsfail,rtrydrop, psretry,supprssd, " \ + "acked,utlisatn,q length,Data Mbits/s,Phy Mbits/s,Rate Mbits/s" + +#define v4hstubS "prec: rqstd, stored, dropped, retried, rtsfail,rtrydrop, " \ + "psretry, acked,utlisatn,q length,Data Mbits/s,Phy Mbits/s" + +#define v4fstubL " %02u: %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, " \ + "%7u, %7u, %7u, %7u, %8.2f, %8.2f, %8.2f" + +#define v4fstubS " %02u: %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, %7u, " \ + "%8.2f, %8.2f" + +#define v4fstubL_aqm " %02u: %7u, %7u, %7u, %7u, %7u, %7u, %7u, -, -, " \ + "%7u, %7u, %7u, %7u, %7u, %7u, %8.2f, -, -" + +#define v4fstubS_aqm " %02u: %7u, %7u, %7u, -, -, %7u, %7u, %7u, %7u, " \ + "%7u, %8.2f, -" + + const char* v4headingsL = v4hstubL" (+v%d.)\n"; + const char* v4headingsS = v4hstubS" (+v%d.)\n"; + const char* v5headingsL = v4hstubL", %%air, %%effcy (v%d)\n"; + const char* v5headingsS = v4hstubS", %%air, %%effcy (v%d)\n"; + + const char* v4formL = v4fstubL"\n"; + const char* v4formS = v4fstubS"\n"; + const char* v4formL_aqm = v4fstubL_aqm"\n"; + const char* v4formS_aqm = v4fstubS_aqm"\n"; + + const char* v5formL = v4fstubL", %6.1f, %5.1f\n"; + const char* v5formS = v4fstubS", %6.1f, %5.1f\n"; + const char* v5formL_aqm = v4fstubL_aqm", -, -\n"; + const char* v5formS_aqm = v4fstubS_aqm", -, -\n"; + + char* headings; + uint8 index; + uint8 prec; + uint32 prec_mask = 0; + char marker[4] = "[X]"; + pktq_log_format_v05_t* logv05 = NULL; + pktq_log_format_v04_t* logv04 = NULL; + + if (iov_pktq_log->version == 0x04) { + logv04 = &iov_pktq_log->pktq_log.v04; + } + else if (iov_pktq_log->version == 0x05) { + logv05 = &iov_pktq_log->pktq_log.v05; + } + else { + fprintf(stderr, "Unknown/unsupported binary format (%x)\n", + iov_pktq_log->version); + return; + } + + headings = PREC_DUMPV(&logv04->headings[0], &logv05->headings[0]); + + for (index = 0; index < (uint8)iov_pktq_log->params.num_addrs; index++) { + + char* heading_start; + char* heading_end; + uint32 num_prec = 0; + + prec_mask = PREC_DUMPV(logv04->counter_info[index], + logv05->counter_info[index]); + num_prec = PREC_DUMPV(logv04->num_prec[index], + logv05->num_prec[index]); + + /* test for 'unknown' data; unknown means either that + * the queue is invalid or else that the logging + * is not active at all. + */ + if (((prec_mask & 0xFFFF) == 0) && hide_unknown) { + continue; + } + + if ((num_prec == 0) && hide_unknown) { + continue; + } + + /* search for string marker - the marker is of the form + "[<index>]" where index is a single ascii numeral + */ + marker[1] = '0' + index; + heading_start = strstr(headings, marker); + + /* The driver may pass back an optional character + * string for additional info + */ + if (heading_start != NULL) { + + heading_start += strlen(marker); + heading_end = strstr(heading_start, marker); + + if (heading_end == NULL) { + heading_end = heading_start + strlen(heading_start); + } + while (heading_start < heading_end) { + fputc(*heading_start++, stdout); + } + } + + /* Note that this is zero if the data is invalid */ + if (!num_prec) { + fprintf(stdout, "Parameter %c:%s not valid\n", + iov_pktq_log->params.addr_type[index] != 0 ? + iov_pktq_log->params.addr_type[index] & 0x7F : ' ', + wl_ether_etoa(&iov_pktq_log->params.ea[index])); + continue; + } + + /* check for short form or long form (top bit set) */ + fprintf(stdout, + iov_pktq_log->params.addr_type[index] & 0x80 ? + PREC_DUMPV(v4headingsL, v5headingsL) : + PREC_DUMPV(v4headingsS, v5headingsS), + iov_pktq_log->version); + + for (prec = 0; prec < num_prec; prec++) { + float tput = 0.0; + float txrate_succ = 0.0; + float txrate_main = 0.0; + pktq_log_counters_v05_t counters; + uint32 try_count = 0; + float airuse = 0.0; + float efficiency = 0.0; + + if (!(prec_mask & (1 << prec))) { + continue; + } + + if (iov_pktq_log->version == 5) { + counters = logv05->counters[index][prec]; + } + else { + /* the following is a trick - it is possible because + * V4 and V5 are both common except that V5 has extra fields + * at the end + */ + memcpy(&counters, &logv04->counters[index][prec], + sizeof(pktq_log_counters_v04_t)); + counters.airtime = 0; + } + + txrate_succ = (float)counters.txrate_succ * 0.5; + + if (counters.time_delta != 0) { + /* convert bytes to bits */ + tput = (float)counters.throughput; + tput *= 8.0; + + if (counters.airtime) { + efficiency = 100.0 * tput / (float)counters.airtime; + } + + /* converts to rate of bits per us, + because time_delta is in micro-seconds + */ + tput /= (float)counters.time_delta; + + /* Calculate % airtime */ + airuse = counters.airtime * 100.0 / (float)counters.time_delta; + } + + if (!(is_aqm && (prec & 1))) { + uint32 acked = counters.acked; + + try_count = counters.acked + counters.retry; + + if (is_aqm && (prec_mask & (1 << (prec + 1)))) { + pktq_log_counters_v05_t hi; + + if (iov_pktq_log->version == 5) { + hi = logv05->counters[index][prec + 1]; + } + else { + /* the following is a trick - it is possible + * fields V4 and V5 are both common except + * that V5 has extra fields at the end + */ + memcpy(&hi, &logv04->counters[index][prec + 1], + sizeof(pktq_log_counters_v04_t)); + } + + acked += hi.acked; + try_count += hi.acked + hi.retry; + + if (counters.airtime) { + float t = (float)hi.throughput; + t /= (float)counters.airtime; + efficiency += 100.0 * 8.0 * t; + } + } + if (acked) { + txrate_succ /= (float) acked; + + if (counters.txrate_succ) { + efficiency /= txrate_succ; + } + else { + efficiency = 0; + } + } + else { + txrate_succ = 0; + efficiency = 0; + } + } + + if (try_count) { + txrate_main = (float)counters.txrate_main * 0.5; + txrate_main /= (float)try_count; + } + + if (iov_pktq_log->params.addr_type[index] & 0x80) { + /* long form */ + if (is_aqm && (prec & 1)) { + /* aqm format for hi-prec */ + fprintf(stdout, PREC_DUMPV(v4formL_aqm, v5formL_aqm), + prec, + counters.requested, + counters.stored, + counters.selfsaved, + counters.saved, + counters.full_dropped, + counters.dropped, + counters.sacrificed, + counters.retry_drop, + counters.ps_retry, + counters.suppress, + counters.acked, + counters.max_used, + counters.queue_capacity, + tput); + } + else { + fprintf(stdout, PREC_DUMPV(v4formL, v5formL), + prec, + counters.requested, + counters.stored, + counters.selfsaved, + counters.saved, + counters.full_dropped, + counters.dropped, + counters.sacrificed, + counters.retry, + counters.rtsfail, + counters.retry_drop, + counters.ps_retry, + counters.suppress, + counters.acked, + counters.max_used, + counters.queue_capacity, + tput, txrate_succ, + txrate_main, + airuse, efficiency); + } + } + else { + /* short form */ + if (is_aqm && (prec & 1)) { + /* aqm format for hi-prec */ + fprintf(stdout, PREC_DUMPV(v4formS_aqm, v5formS_aqm), + prec, + counters.requested, + counters.stored, + counters.dropped, + counters.retry_drop, + counters.ps_retry, + counters.acked, + counters.max_used, + counters.queue_capacity, + tput); + } + else { + fprintf(stdout, PREC_DUMPV(v4formS, v5formS), + prec, + counters.requested, + counters.stored, + counters.dropped, + counters.retry, + counters.rtsfail, + counters.retry_drop, + counters.ps_retry, + counters.acked, + counters.max_used, + counters.queue_capacity, + tput, txrate_succ, + airuse, efficiency); + } + } + } + fputs("\n", stdout); + + if (iov_pktq_log->version == 5 && + (logv05->pspretend_time_delta[index] != (uint32)-1)) { + + fprintf(stdout, "Total time in ps pretend state is %d milliseconds\n\n", + (logv05->pspretend_time_delta[index] + 500)/1000); + } + } +} + +static int +wl_scb_bs_data(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int32 flag_bits = 0; + int argn; + enum { DISPLAY_COOKED, DISPLAY_RAW } display_mode = DISPLAY_COOKED; + iov_bs_data_struct_t *data = (iov_bs_data_struct_t *)buf; + char sep = ' '; + bool skip_idle = FALSE; + float total_throughput = 0.0; + + UNUSED_PARAMETER(cmd); /* cmd->name should match argv[0] ? */ + + if (!argv[0]) { + fprintf(stderr, "%s: argv[0] missing\n", __FUNCTION__); + return BCME_BADARG; + } + + for (argn = 1; argv[argn]; ++argn) { + if (!strcmp(argv[argn], "-noreset")) { /* do not reset counters after reading */ + flag_bits |= SCB_BS_DATA_FLAG_NO_RESET; + } else + if (!strcmp(argv[argn], "-raw")) { /* Display raw counters */ + display_mode = DISPLAY_RAW; + } else + if (!strcmp(argv[argn], "-tab")) { /* Tab separator */ + sep = '\t'; + } else + if (!strcmp(argv[argn], "-comma")) { /* Comma separator */ + sep = ','; + } else + if (!strcmp(argv[argn], "-noidle")) { /* Skip idle stations */ + skip_idle = TRUE; + } else + if (!strcmp(argv[argn], "-help") || !strcmp(argv[argn], "-h")) { + /* Display usage, do not complain about unknown option. */ + return BCME_USAGE_ERROR; + } else { + fprintf(stderr, "%s: unknown option: %s\n", argv[0], argv[argn]); + return BCME_USAGE_ERROR; + } + } + + flag_bits = htod32(flag_bits); + err = wlu_iovar_getbuf(wl, argv[0], &flag_bits, sizeof(flag_bits), buf, WLC_IOCTL_MAXLEN); + if (err) { + return (err); + } + + data->structure_version = dtoh16(data->structure_version); + if (data->structure_version != SCB_BS_DATA_STRUCT_VERSION) { + fprintf(stderr, "wlu / wl driver mismatch, expect V%d format, got %d.\n", + SCB_BS_DATA_STRUCT_VERSION, data->structure_version); + return BCME_IOCTL_ERROR; + } + + data->structure_count = dtoh16(data->structure_count); + if (data->structure_count == 0) { + printf("No stations are currently associated.\n"); + return BCME_OK; + } + + /* Display Column headers - mac address always, then, depending on display mode */ + + printf("%17s%c", "Station Address", sep); + switch (display_mode) { + case DISPLAY_RAW: + printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", + "retry_drop", "rtsfail", "retry", "txrate_main", + "txrate_succ", "acked", "throughput", "time_delta", "airtime"); + break; + case DISPLAY_COOKED: + printf("%10s%c%10s%c%10s%c%10s%c%10s\n", "PHY Mbps", sep, "Data Mbps", sep, + "Air Use", sep, "Data Use", sep, "Retries"); + break; + } + + /* Convert returned counters to host byte order, and sum up total throughput */ + + for (argn = 0; argn < data->structure_count; ++argn) { + + iov_bs_data_record_t *rec; + iov_bs_data_counters_t *ctr; + float data_rate; + + rec = &data->structure_record[argn]; + ctr = &rec->station_counters; + +#define DEVICE_TO_HOST(xyzzy) ctr->xyzzy = dtoh32(ctr->xyzzy) + DEVICE_TO_HOST(retry_drop); + DEVICE_TO_HOST(rtsfail); + DEVICE_TO_HOST(retry); + DEVICE_TO_HOST(txrate_main); + DEVICE_TO_HOST(txrate_succ); + DEVICE_TO_HOST(acked); + DEVICE_TO_HOST(throughput); + DEVICE_TO_HOST(time_delta); + DEVICE_TO_HOST(airtime); +#undef DEVICE_TO_HOST + + /* Calculate data rate in bits per second, rather than bytes per second */ + data_rate = (ctr->time_delta) ? + (float)ctr->throughput * 8.0 / (float)ctr->time_delta : 0.0; + + total_throughput += data_rate; + } + + for (argn = 0; argn < data->structure_count; ++argn) { + iov_bs_data_record_t *rec; + iov_bs_data_counters_t *ctr; + rec = &data->structure_record[argn]; + ctr = &rec->station_counters; + + if (skip_idle && (ctr->acked == 0)) continue; + + printf("%17s%c", wl_ether_etoa(&rec->station_address), sep); + switch (display_mode) { + case DISPLAY_RAW: + printf("%9d %9d %9d %9d %9d %9d %9d %9d %9d\n", + ctr->retry_drop, ctr->rtsfail, ctr->retry, + ctr->txrate_main, ctr->txrate_succ, ctr->acked, + ctr->throughput, ctr->time_delta, ctr->airtime); + break; + case DISPLAY_COOKED: + { + float data_rate; + float phy_rate; + float use, air, rtr; + + /* Calculate PHY rate */ + phy_rate = (ctr->acked) ? + (float)ctr->txrate_succ * 0.5 / (float)ctr->acked : 0.0; + + /* Calculate Data rate */ + data_rate = (ctr->time_delta) ? + (float)ctr->throughput * 8.0 / (float)ctr->time_delta : 0.0; + + /* Calculate use percentage amongst throughput from all stations */ + use = (total_throughput) ? data_rate / total_throughput * 100 : 0.0; + + /* Calculate % airtime */ + air = (ctr->time_delta) ? ((float)ctr->airtime * 100.0 / + (float) ctr->time_delta) : 0.0; + + /* Calculate retry percentage */ + rtr = (ctr->acked) ? (float)ctr->retry / (float)ctr->acked * 100 : 0.0; + + printf("%10.1f%c%10.1f%c%9.1f%%%c%9.1f%%%c%9.1f%%\n", + phy_rate, sep, data_rate, sep, air, sep, use, sep, rtr); + } + break; + } + } + return BCME_OK; +} + +/* IO variables that take MAC addresses (with optional single letter prefix) + * and output a string buffer + */ +static int +wl_iov_pktqlog_params(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + char** macaddrs = argv + 1; + + wl_iov_mac_full_params_t* full_params = (wl_iov_mac_full_params_t*)buf; + wl_iov_mac_params_t* params = &full_params->params; + wl_iov_mac_extra_params_t* extra_params = &full_params->extra_params; + + wl_iov_mac_params_t loop_params; + wl_iov_mac_extra_params_t loop_extra_params; + uint32 index; + bool loop_assoclist = FALSE; + struct maclist* maclist = NULL; + + wlc_rev_info_t revinfo; + uint32 corerev; + + if (cmd->get < 0) + return -1; + + memset(&revinfo, 0, sizeof(revinfo)); + + ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + + if (ret) { + return ret; + } + corerev = dtoh32(revinfo.corerev); + + memset(full_params, 0, sizeof(*full_params)); + memset(&loop_params, 0, sizeof(loop_params)); + memset(&loop_extra_params, 0, sizeof(loop_extra_params)); + + /* only pass up to WL_IOV_MAC_PARAM_LEN parameters */ + while (params->num_addrs < WL_IOV_MAC_PARAM_LEN && *macaddrs) { + bool full_auto = FALSE; + char* ptr = *macaddrs; + uint32 bitmask; + + /* is there a prefix character? */ + if (ptr[1] == ':') { + params->addr_type[params->num_addrs] = toupper((int)(ptr[0])); + + /* move ptr to skip over prefix */ + ptr += 2; + + /* is there the 'long form' option ? */ + if (ptr[0] == '+') { + /* check for + additional info option, set top bit */ + params->addr_type[params->num_addrs] |= 0x80; + ptr++; + } + if ((ptr[0] == 0) || (ptr[0] == '/' || ptr[0] == ',')) { + /* this is the fully automatic mode */ + full_auto = TRUE; + } + } + + /* the prefix C: denotes no given MAC address (to refer to "common") */ + if ((params->addr_type[params->num_addrs] & 0x7F) == 'C') { + full_auto = FALSE; + } + else if (full_auto) { + loop_assoclist = TRUE; + loop_params.addr_type[loop_params.num_addrs] = + params->addr_type[params->num_addrs]; + } + else if (wl_ether_atoe(ptr, ¶ms->ea[params->num_addrs])) { + /* length of MAC addr string excl end char */ + ptr += (ETHER_ADDR_STR_LEN - 1); + } + else { + params->addr_type[params->num_addrs] = 0; + printf("Bad parameter '%s'\n", *macaddrs); + ++macaddrs; + continue; + } + + + bitmask = 0; + + while (ptr && (ptr[0] == ',' || ptr[0] == '/') && + ((ptr[1] >= '0' && ptr[1] <= '9') || + ptr[1] == '/' || ptr[1] == ',')) { + + uint8 prec; + char* endptr = 0; + + if (ptr[1] == '/' || ptr[1] == ',') { + /* this is the 'auto' setting */ + bitmask |= PKTQ_LOG_AUTO; + ptr += 2; + } + else { + ptr++; + + prec = (uint8)strtoul(ptr, &endptr, 10); + + if (prec <= 15) { + bitmask |= (1 << prec); + } + else { + printf("Bad precedence %d (will be ignored)\n", + prec); + } + ptr = endptr; + } + + } + + if (bitmask == 0) { + /* PKTQ_LOG_DEF_PREC is ignored in V4, it is used to indicate no prec was + * selected + */ + bitmask = 0xFFFF | PKTQ_LOG_DEF_PREC; + } + + if (full_auto) { + loop_extra_params.addr_info[loop_params.num_addrs] = bitmask; + loop_params.num_addrs++; + } + else { + extra_params->addr_info[params->num_addrs] = bitmask; + params->num_addrs ++; + } + ++macaddrs; + } + + while (*macaddrs) { + printf("Ignoring excess parameter '%s' (maximum number of params is %d)\n", + *macaddrs, WL_IOV_MAC_PARAM_LEN); + ++macaddrs; + } + + /* if no valid params found, pass default prefix 'C' with no mac address */ + if (params->num_addrs == 0 && !loop_assoclist) + { + params->addr_type[0] = 'C'; + extra_params->addr_info[0] = 0xFFFF; + params->num_addrs = 1; + } + + if (params->num_addrs) { + /* set a "version" indication (ie extra_params present) */ + params->num_addrs |= (4 << 8); + + + if ((ret = wlu_iovar_getbuf(wl, cmd->name, params, + sizeof(*params) + sizeof(*extra_params), + buf, WLC_IOCTL_MAXLEN)) < 0) { + + fprintf(stderr, "Error getting variable %s\n", argv[0]); + return ret; + } + + wl_txq_prec_dump((wl_iov_pktq_log_t*)buf, FALSE, corerev >= 40); + + } + if (!loop_assoclist) { + return 0; + } + + maclist = malloc(WLC_IOCTL_MEDLEN); + + if (!maclist) { + fprintf(stderr, "unable to allocate memory\n"); + return -ENOMEM; + } + maclist->count = htod32((WLC_IOCTL_MEDLEN - sizeof(int)) / ETHER_ADDR_LEN); + + if ((ret = wlu_get(wl, WLC_GET_ASSOCLIST, maclist, WLC_IOCTL_MEDLEN)) < 0) { + fprintf(stderr, "Cannot get assoclist\n"); + free(maclist); + return ret; + } + maclist->count = dtoh32(maclist->count); + + if (maclist->count == 0) { + fprintf(stderr, "No available addresses in assoclist for automatic operation\n"); + free(maclist); + return 0; + } + + for (index = 0; index < loop_params.num_addrs; index++) { + uint32 ea_index = 0; + + while (ea_index < maclist->count) { + + memset(full_params, 0, sizeof(*full_params)); + + while ((params->num_addrs < WL_IOV_MAC_PARAM_LEN) && + (ea_index < maclist->count)) { + + params->addr_type[params->num_addrs] = loop_params.addr_type[index]; + params->ea[params->num_addrs] = maclist->ea[ea_index]; + extra_params->addr_info[params->num_addrs] = + loop_extra_params.addr_info[index] | PKTQ_LOG_AUTO; + + params->num_addrs++; + ea_index++; + } + + /* set a "version" indication (ie extra_params present) */ + params->num_addrs |= (4 << 8); + + if ((ret = wlu_iovar_getbuf(wl, cmd->name, params, + sizeof(*params) + sizeof(*extra_params), + buf, WLC_IOCTL_MAXLEN)) < 0) { + fprintf(stderr, "Error getting %s\n", argv[0]); + free(maclist); + return ret; + } + + wl_txq_prec_dump((wl_iov_pktq_log_t*)buf, TRUE, corerev >= 40); + } + } + free(maclist); + return 0; +} + +static int +wlu_dump(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + char *dump_buf; + int bcmerr; + + if (cmd->get < 0) + return -1; + + dump_buf = malloc(WL_DUMP_BUF_LEN); + if (dump_buf == NULL) { + fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WL_DUMP_BUF_LEN); + return BCME_NOMEM; + } + memset(dump_buf, 0, WL_DUMP_BUF_LEN); + + /* skip the command name */ + argv++; + + /* If no args given, get the subset of 'wl dump all' + * Otherwise, if args are given, they are the dump section names. + */ + if (*argv == NULL) { + /* query for the 'dump' without any argument */ + ret = wlu_iovar_getbuf(wl, "dump", NULL, 0, dump_buf, WL_DUMP_BUF_LEN); + + /* if the query is successful, continue on and print the result. */ + + /* if the query fails, check for a legacy driver that does not support + * the "dump" iovar, and instead issue a WLC_DUMP ioctl. + */ + if (ret) { + wlu_iovar_getint(wl, "bcmerror", &bcmerr); + if (bcmerr == BCME_UNSUPPORTED) { + ret = wlu_get(wl, WLC_DUMP, dump_buf, WL_DUMP_BUF_LEN); + if (ret) { + fprintf(stderr, "dump: error on query of WLC_DUMP\n"); + } + } else { + fprintf(stderr, "dump: error on query of dump list\n"); + } + } + } else { + /* create the dump section name list */ + while (*argv) { + /* add space delimiter if this is not the first section name */ + if (dump_buf[0] != '\0') + strcat(dump_buf, " "); + + strcat(dump_buf, *argv); + + argv++; + } + + /* This is a "space" added at end of last argument */ + strcat(dump_buf, " "); + + ret = wlu_iovar_getbuf(wl, "dump", dump_buf, strlen(dump_buf), + dump_buf, WL_DUMP_BUF_LEN); + } + + if (!ret) { + fputs(dump_buf, stdout); + } + + free(dump_buf); + + return ret; +} + +static int +wlu_offloads_stats(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + char *dump_buf; + int bufsz = WL_DUMP_BUF_LEN; + bool cons_cmd = FALSE; + + if (cmd->get < 0) + return -1; + + if (!strcmp(cmd->name, "ol_clr")) + { + ret = wlu_iovar_get(wl, cmd->name, NULL, 0); + return ret; + } + + if (!strcmp(cmd->name, "ol_cons")) { + /* Check for command */ + if (*(argv + 1)) { + argv++; + cons_cmd = TRUE; + bufsz = CMDLINESZ; + } + } + + dump_buf = malloc(bufsz); + if (dump_buf == NULL) { + fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", bufsz); + return -1; + } + memset(dump_buf, 0, bufsz); + + while (*argv) { + /* add space delimiter if this is not the first section name */ + if (dump_buf[0] != '\0') + strcat(dump_buf, " "); + + strcat(dump_buf, *argv); + + argv++; + } + + if (cons_cmd) { + ret = wlu_iovar_set(wl, cmd->name, dump_buf, bufsz); + } else { + ret = wlu_iovar_get(wl, cmd->name, dump_buf, bufsz); + if (!ret) + fputs(dump_buf, stdout); + } + + free(dump_buf); + + return ret; +} + + +static int +wl_staprio(void *wl, cmd_t *cmd, char **argv) +{ + int ret = BCME_USAGE_ERROR; + wl_staprio_cfg_t staprio_cfg; + char *endptr = NULL; + + if (!*++argv) return -1; + + /* get link mac address */ + if (!wl_ether_atoe(*argv++, &staprio_cfg.ea)) + goto error; + + if (argv[0]) { + staprio_cfg.prio = (uint8)strtol(argv[0], &endptr, 0); + if (*endptr != '\0') + goto error; + + if (staprio_cfg.prio > 3) { + printf("prio %d out of range [0, 3]\n", staprio_cfg.prio); + goto error; + } + else { + printf("Set SCB prio: 0x%x\n", staprio_cfg.prio); + ret = wlu_iovar_setbuf(wl, cmd->name, (void *) &staprio_cfg, + sizeof(wl_staprio_cfg_t), buf, WLC_IOCTL_MEDLEN); + } + } + else { + if ((ret = wlu_iovar_getbuf(wl, cmd->name, (void *) &staprio_cfg, + sizeof(wl_staprio_cfg_t), buf, WLC_IOCTL_MEDLEN)) >= 0) { + printf("SCB prio: 0x%x\n", ((wl_staprio_cfg_t *)buf)->prio); + } + } + +error: + return ret; +} + +static int +wl_aibss_bcn_force_config(void *wl, cmd_t *cmd, char **argv) +{ + int ret = BCME_USAGE_ERROR; + aibss_bcn_force_config_t bcn_config; + + if (!*++argv) { + /* Get */ + memset(&bcn_config, 0, sizeof(aibss_bcn_force_config_t)); + /* get current rateset */ + if ((ret = wlu_iovar_get(wl, cmd->name, &bcn_config, + sizeof(aibss_bcn_force_config_t))) < 0) + goto error; + + printf("AIBSS Initial beacon check duration: %d \r\n" + "AIBSS beacon check duration:%d \r\n" + "AIBSS beacon flood duration:%d\r\n", + bcn_config.initial_min_bcn_dur, bcn_config.min_bcn_dur, + bcn_config.bcn_flood_dur); + } + else { + char *p = argv[0]; + char *endptr = NULL; + + /* Extract the content */ + if (!p || *p == '\0') + goto error; + + bcn_config.initial_min_bcn_dur = strtoul(p, &endptr, 0); + + p = endptr; + /* check and skip , */ + if (*p == '\0' || *++p == '\0') + goto error; + + bcn_config.min_bcn_dur = strtoul(p, &endptr, 0); + + p = endptr; + /* check and skip , */ + if (*p == '\0' || *++p == '\0') + goto error; + + bcn_config.bcn_flood_dur = strtoul(p, &endptr, 0); + + if (*endptr != '\0') + goto error; + bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0; + bcn_config.len = sizeof(aibss_bcn_force_config_t); + ret = wlu_iovar_set(wl, cmd->name, (void *) &bcn_config, + sizeof(aibss_bcn_force_config_t)); + } + +error: + return ret; +} + + +static int +wlu_srdump(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i, nw, nb = 0; + uint16 *words = (uint16 *)&buf[8]; + + srom_rw_t *srt; + + /* srom has been expanded a few times, at the moment sromrev11 are the largest */ + nw = SROM11_WORDS; + + /* allow reading a larger (or any other-size one) if specified */ + if (*++argv != NULL) { + nb = (int)strtol(*argv, NULL, 0); + if (nb & 1) { + printf("Byte count %d is odd\n", nb); + return BCME_BADARG; + } + nw = nb / 2; + } + + srt = (srom_rw_t *)buf; + srt->byteoff = htod32(0); + srt->nbytes = htod32(2 * nw); + + if (cmd->get < 0) + return -1; + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return ret; + + if (words[SROM11_SIGN] == SROM11_SIGNATURE) { + nw = SROM11_WORDS; + } else if (words[SROM10_SIGN] == SROM4_SIGNATURE) { + nw = SROM10_WORDS; + } else { + nw = SROM4_WORDS; + if ((words[SROM4_SIGN] != SROM4_SIGNATURE) && + (words[SROM8_SIGN] != SROM4_SIGNATURE)) + nw = nb ? nw : SROM_WORDS; + } + for (i = 0; i < nw; i++) { + if ((i % 8) == 0) + printf("\n srom[%03d]: ", i); + printf("0x%04x ", words[i]); + } + printf("\n"); + + return 0; +} + +static int +wlu_srwrite(void *wl, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv); + return (-1); +#else + char *arg; + char *endptr; + FILE *fp = NULL; + int ret = 0, erase, srcrc; + uint i, len; + srom_rw_t *srt = (srom_rw_t *)buf; + + erase = !strcmp(*argv, "srclear"); + srcrc = !strcmp(*argv, "srcrc"); + + /* We need at least one arg */ + if (!*++argv) + return BCME_USAGE_ERROR; + + arg = *argv++; + + if (erase) { + if (*argv) + return BCME_USAGE_ERROR; + len = strtoul(arg, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "error parsing value \"%s\" as an integer for byte count\n", + arg); + return BCME_USAGE_ERROR; + } + srt->byteoff = 0x55aa; + } else if (!*argv) { /* srwrite or srcrc */ + /* Only one arg, it better be a file name */ + if (!(fp = fopen(arg, "rb"))) { + fprintf(stderr, "%s: No such file or directory\n", arg); + return BCME_BADARG; + } + + len = fread(srt->buf, 1, SROM_MAX + 1, fp); + if ((ret = ferror(fp))) { + printf("\nerror %d reading %s\n", ret, arg); + ret = BCME_ERROR; + goto out; + } + + if (!feof(fp)) { + printf("\nFile %s is too large\n", arg); + ret = BCME_ERROR; + goto out; + } + + if (len == SROM4_WORDS * 2) { + if ((srt->buf[SROM4_SIGN] != SROM4_SIGNATURE) && + (srt->buf[SROM8_SIGN] != SROM4_SIGNATURE)) { + printf("\nFile %s is %d bytes but lacks a REV4/ signature\n", + arg, SROM4_WORDS * 2); + ret = BCME_ERROR; + goto out; + } + } else if (len == SROM11_WORDS * 2) { + if (srt->buf[SROM11_SIGN] != SROM11_SIGNATURE) { + printf("\nFile %s is %d bytes but lacks a REV11/ signature\n", + arg, SROM11_WORDS * 2); + ret = BCME_ERROR; + goto out; + } + } else if ((len != SROM_WORDS * 2) && (len != SROM10_WORDS * 2) && + (len != SROM_MAX)) { + printf("\nFile %s is %d bytes, not %d or %d or %d or %d bytes\n", arg, len, + SROM_WORDS * 2, SROM4_WORDS * 2, SROM10_WORDS, SROM_MAX); + ret = BCME_ERROR; + goto out; + } + + srt->byteoff = 0; + } else { + if (srcrc) { + printf("srcrc only takes one arg\n"); + ret = BCME_USAGE_ERROR; + goto out; + } + + /* More than 1 arg, first is offset, rest are data. */ + srt->byteoff = strtoul(arg, &endptr, 0); + if (*endptr != '\0') + goto nout; + + i = 0; + while ((arg = *argv++) != NULL) { + srt->buf[i++] = (uint16)strtoul(arg, &endptr, 0); + if (*endptr != '\0') { +nout: + printf("\n%s is not an integer\n", arg); + ret = BCME_USAGE_ERROR; + goto out; + } + } + + if (srt->byteoff & 1) { + printf("Byte offset (%d) is odd or negative\n", srt->byteoff); + ret = BCME_BADARG; + goto out; + } + + len = 2 * i; + if ((srt->byteoff + len) > SROM_MAX) { + printf("Data extends past %d bytes\n", SROM_MAX); + ret = BCME_BUFTOOLONG; + goto out; + } + } + srt->nbytes = len; + + if (srcrc) { + srt->byteoff = 0x55ab; /* Hack for srcrc */ + if ((ret = wlu_get(wl, cmd->get, buf, len + 8)) == 0) + printf("0x%x\n", (uint8)buf[0]); + } else { + printf("Writing srom. ioctl %d, iolen %d, sroff %d, len %d\n", + cmd->set, len + 8, srt->byteoff, srt->nbytes); + + ret = wlu_set(wl, cmd->set, buf, len + 8); + } + +out: + fflush(stdout); + if (fp) + fclose(fp); + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +static int +wlu_ciswrite(void *wl, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv); + return (-1); +#else + char *arg, *bufp; + FILE *fp = NULL; + int ret = 0; + uint32 len; + + cis_rw_t cish; + char *cisp, *cisdata; + + UNUSED_PARAMETER(cmd); + + /* We need extacly one arg */ + if (!*++argv || argv[1]) + return BCME_USAGE_ERROR; + + /* initialize buffer with iovar */ + bufp = buf; + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(bufp, "ciswrite"); + bufp += strlen("ciswrite") + 1; + cisp = bufp; + cisdata = cisp + sizeof(cish); + + cish.source = htod32(0); + + /* grab the filename arg */ + arg = *argv; + if (!(fp = fopen(arg, "rb"))) { + fprintf(stderr, "%s: No such file or directory\n", arg); + return BCME_BADARG; + } + + len = fread(cisdata, 1, SROM_MAX + 1, fp); + if ((ret = ferror(fp))) { + printf("\nerror %d reading %s\n", ret, arg); + ret = BCME_ERROR; + goto out; + } + + if (!feof(fp)) { + printf("\nFile %s is too large\n", arg); + ret = BCME_ERROR; + goto out; + } + + /* fill in offset and length */ + cish.byteoff = htod32(0); + cish.nbytes = htod32(len); + memcpy(cisp, (char*)&cish, sizeof(cish)); + + printf("len %d sizeof(cish) %d total %d\n", len, (int)sizeof(cish), + (int)(len + sizeof(cish))); + ret = wl_set(wl, WLC_SET_VAR, buf, (cisp - buf) + sizeof(cish) + len); + if (ret < 0) { + fprintf(stderr, "ciswrite failed: %d\n", ret); + } + +out: + if (fp) + fclose(fp); + + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +static int +wlu_cisupdate(void *wl, cmd_t *cmd, char **argv) +{ + char *bufp, *endptr; + int ret = 0; + int preview = 0; + uint32 off; + uint32 len; + uint32 updatelen; + uint32 i; + char hexstr[3]; + char bytes[SROM_MAX]; + + cis_rw_t cish; + char *cisp; + + UNUSED_PARAMETER(cmd); + + /* validate arg count */ + if (!*++argv || !argv[1]) + return BCME_USAGE_ERROR; + + if (argv[2] && !strcmp(argv[2], "--preview")) + preview = 1; + + /* grab byte offset */ + off = (uint32)strtol(argv[0], &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + + bufp = argv[1]; + updatelen = strlen(bufp); + if (updatelen % 2) { + fprintf(stderr, "cisupdate hex string must contain an even number of digits\n"); + goto done; + } + updatelen /= 2; + + /* convert and store hex byte values */ + for (i = 0; i < updatelen; i++) { + hexstr[0] = *bufp; + hexstr[1] = *(bufp + 1); + if (!isxdigit((int)hexstr[0]) || !isxdigit((int)hexstr[1])) { + fprintf(stderr, "cisupdate invalid hex digit(s) in %s\n", argv[1]); + goto done; + } + hexstr[2] = '\0'; + bytes[i] = (char) strtol(hexstr, NULL, 16); + bufp += 2; + } + + /* Prepare the read info */ + cish.source = 0; + cish.byteoff = 0; + cish.nbytes = 0; + + /* set up the buffer and do the get (+9 allows space for "ciswrite" string later) */ + memset(buf + 9, 0, WLC_IOCTL_MAXLEN); + strcpy(buf + 9, "cisdump"); + bufp = buf + strlen("cisdump") + 1 + 9; + memcpy(bufp, (char*)&cish, sizeof(cish)); + bufp += sizeof(cish); + ret = wl_get(wl, WLC_GET_VAR, buf + 9, (bufp - (buf + 9)) + SROM_MAX); + if (ret < 0) { + fprintf(stderr, "cisupdate failed to read cis: %d\n", ret); + goto done; + } + + /* pull off the cis_rw_t */ + bufp = buf + 9; + memcpy((char*)&cish, bufp, sizeof(cish)); + len = dtoh32(cish.nbytes); + + if ((off + updatelen) > len) { + fprintf(stderr, "cisupdate offset %d plus update len %d exceeds CIS len %d\n", + off, updatelen, len); + goto done; + } + + /* move past to the data */ + bufp += sizeof(cish); + + /* update the bytes */ + if (cish.source == WLC_CIS_SROM) { + for (i = 0; i < updatelen; ++i) + bufp[off + i] = bytes[i] & 0xff; + } else { + for (i = 0; i < updatelen; ++i) { + if (~bytes[i] & bufp[off + i]) { + fprintf(stderr, "cisupdate: OTP update incompatible:" + " update[%d](0x%02x)->cis[%d](0x%02x)\n", + i, bytes[i], off + i, bufp[off + i]); + goto done; + } + bufp[off + i] |= bytes[i]; + } + } + + /* initialize buffer with iovar */ + bufp = buf; + strcpy(bufp, "ciswrite"); + bufp += strlen("ciswrite") + 1; + cisp = bufp; + + /* fill in cis_rw_t fields */ + cish.source = 0; + cish.byteoff = 0; + cish.nbytes = htod32(len); + memcpy(cisp, (char*)&cish, sizeof(cish)); + + /* write the data back to the device */ + printf("offset %d data %s cislen %d\n", off, argv[1], len); + if (preview) { + bufp += sizeof(cish); + for (i = 0; i < len; i++) { + if ((i % 8) == 0) + printf("\nByte %3d: ", i); + printf("0x%02x ", (uint8)bufp[i]); + } + printf("\n"); + } else { + ret = wl_set(wl, WLC_SET_VAR, buf, (cisp - buf) + sizeof(cish) + len); + if (ret < 0) { + fprintf(stderr, "cisupdate cis write failed: %d\n", ret); + } + } + +done: + return ret; +} + +static int +wlu_cisdump(void *wl, cmd_t *cmd, char **argv) +{ + char *bufp; + int i, ret = 0; + cis_rw_t cish; + uint nbytes = 0; + char *fname = NULL; + + UNUSED_PARAMETER(cmd); + + /* Grab and move past optional output file argument */ + if ((argv[1] != NULL) && (strcmp(argv[1], "-b") == 0)) { + fname = argv[2]; + argv += 2; + } + + /* check for a length argument */ + if (*++argv != NULL) { + nbytes = (int)strtol(*argv, NULL, 0); + if (nbytes & 1) { + printf("Invalid byte count %d, must be even\n", nbytes); + ret = BCME_BADARG; + goto done; + } + if (nbytes > SROM_MAX) { + printf("Count %d too large\n", nbytes); + ret = BCME_BUFTOOLONG; + goto done; + } + } + + /* Prepare the read info */ + cish.source = 0; + cish.byteoff = 0; + cish.nbytes = htod32(nbytes); + + /* set up the buffer and do the get */ + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(buf, "cisdump"); + bufp = buf + strlen("cisdump") + 1; + memcpy(bufp, (char*)&cish, sizeof(cish)); + bufp += sizeof(cish); + ret = wl_get(wl, WLC_GET_VAR, buf, (bufp - buf) + (nbytes ? nbytes : SROM_MAX)); + if (ret < 0) { + fprintf(stderr, "Failed cisdump request: %d\n", ret); + goto done; + } + + /* pull off the cis_rw_t */ + bufp = buf; + memcpy((char*)&cish, bufp, sizeof(cish)); + cish.source = dtoh32(cish.source); + cish.byteoff = dtoh32(cish.byteoff); + cish.nbytes = dtoh32(cish.nbytes); + + /* move past to the data */ + bufp += sizeof(cish); + + printf("Source: %d (%s)", cish.source, + (cish.source == WLC_CIS_DEFAULT) ? "Built-in default" : + (cish.source == WLC_CIS_SROM) ? "External SPROM" : + (cish.source == WLC_CIS_OTP) ? "Internal OTP" : "Unknown?"); + if (!nbytes) + printf("\nMaximum length: %d bytes", cish.nbytes); + for (i = 0; i < (int)cish.nbytes; i++) { + if ((i % 8) == 0) + printf("\nByte %3d: ", i); + printf("0x%02x ", (uint8)bufp[i]); + } + printf("\n"); + +#if defined(BWL_FILESYSTEM_SUPPORT) + if (fname != NULL) { + FILE *fp; + + if (!nbytes) + nbytes = cish.nbytes; + + fp = fopen(fname, "wb"); + if (fp != NULL) { + ret = fwrite(bufp, 1, nbytes, fp); + if (ret != (int)nbytes) { + fprintf(stderr, "Error writing %d bytes to file, rc %d!\n", + (int)nbytes, ret); + ret = BCME_ERROR; + } else { + printf("Wrote %d bytes to %s\n", ret, fname); + ret = 0; + } + fclose(fp); + } else { + fprintf(stderr, "Problem opening file %s\n", fname); + ret = BCME_BADARG; + } + } +#endif /* BWL_FILESYSTEM_SUPPORT */ + +done: + return ret; +} + +/* linux, MacOS, NetBSD: ffs is in the standard C library */ +/* CFE, HNDRTE & IOPOS: Not needed, the code below is ifdef out */ + + +/* VX wants prototypes even for static functions. */ +static char* find_pattern(char **argv, const char *pattern, uint *val); +static char* find_pattern2(char **argv, const char *pattern, uint *val, int vnum); +static int newtuple(char *b, int *cnt, uint8 tag, const cis_tuple_t *srv); +static int parsecis(char *b, char **argv, int sromrev); +static const sromvar_t *srvlookup(const sromvar_t *tab, char *name, int nlen, int sromrev); + +/* Find an entry in argv[][] in this form + * name=value, could be pattern=(0x)1234 or pattern=ABC + * + * If *val is NULL, return the pointer to value. + * If *val is not NULL, fill the value into val, return the pointer to name if found, + * return NULL if no match found. + */ +static char* +find_pattern(char **argv, const char *pattern, uint *val) +{ + char *ret = NULL, *name = NULL, **pargv = argv; + + /* clear val first */ + if (val) *val = 0; + + while ((name = *pargv++)) { + if ((ret = strstr(name, pattern))) { + char *p = ret, *q = NULL; + + /* Extracting the content */ + p += strlen(pattern); + + /* var name could have same prefix */ + if (*p++ != '=') { + ret = NULL; + continue; + } + if (!val) + return (ret+strlen(pattern)+1); + + *val = strtoul(p, &q, 0); + if (p == q) { + printf("Bad value: %s\n", ret); + return NULL; + } + + break; + } + } + return ret; +} + +/* Find an entry in argv[][] in this form + * name=value1,value2,...,value(n) + * n is indicated by vnum + * could be pattern=(0x)1234,... or pattern=ABC,... + * + * If *val is NULL, return the pointer to value. + * If *val is not NULL, fill the value into val, return the pointer to name if found, + * return NULL if no match found. + */ +static char* +find_pattern2(char **argv, const char *pattern, uint *val, int vnum) +{ + char *ret = NULL, *name = NULL, **pargv = argv; + int i; + + while ((name = *pargv++)) { + if ((ret = strstr(name, pattern))) { + char *p = ret, *q = NULL; + + /* Extracting the content */ + p += strlen(pattern); + + /* var name could have same prefix */ + if (*p++ != '=') { + ret = NULL; + continue; + } + if (!val) + return (ret+strlen(pattern)+1); + + for (i = 0; i < vnum; i ++) + { + val[i] = strtoul(p, &q, 0); + + if (p == q) { + printf("Bad value: %s\n", ret); + return NULL; + } + p = q + 1; /* skip ',' */ + } + break; + } + } + return ret; +} + +static int +newtuple(char *b, int *cnt, uint8 tag, const cis_tuple_t *srv) +{ + memset(b, 0, srv->len + 2); + + b[0] = tag; + b[1] = (char)srv->len; + b[2] = (char)srv->tag; + + if (cnt) + *cnt += 3; + return 0; +} + +/** + * When programming OTP or SROM, driver expects to receive a CIS from the wl utility. + * This function converts a caller supplied string (in **argv) containing nvram variables pairs into + * a CIS (in *b). Caller can dictate the binary CIS contents by using nvram string 'RAW=...' or + * 'RAW1=...'. Function will only create tuples for values in caller supplied nvram string. + */ +static int +parsecis(char *b, char **argv, int sromrev) +{ + /* built-in list of known tuples and nvram var(s) associated with a specific tuple */ + const cis_tuple_t *srv = cis_hnbuvars; + char *cpar = NULL, *p = NULL; + char *par; + char delimit[2] = " \0"; + int cnt = 0, i = 0; + uint sromrev_mask = 0xffffffff; + + if (sromrev > 0 && sromrev <= 31) { + sromrev_mask = 1 << sromrev; + } else { + printf("Invalid sromrev %d.\n", sromrev); + return BCME_BADARG; + } + + /* Walk through built-in list of tuples, create append buffer */ + while (srv->tag != 0xFF) { + uint val = 0; + + /* Skip srv if not supported in sromrev */ + if (!(sromrev_mask & srv->revmask)) { + srv++; + continue; + } + + /* Special cases (Raw Data / macaddr / ccode / fem) */ + if (srv->tag == OTP_RAW) { + if ((p = find_pattern(argv, "RAW", &val))) { + p += (strlen("RAW") + 1); /* RAW= */ + for (;;) { + b[cnt++] = (unsigned char) strtoul(p, &p, 16); + if (!*p++) + break; + } + } + } else if (srv->tag == OTP_RAW1) { + if ((p = find_pattern(argv, "RAW1", NULL))) { + for (;;) { + b[cnt++] = (unsigned char) strtoul(p, &p, 16); + if (!*p++) + break; + } + } + } else if (srv->tag == OTP_VERS_1) { + uint l1 = 1, l2 = 1; + char *p2 = NULL; + + if ((p = find_pattern(argv, "manf", NULL))) + l1 += strlen(p); + + if ((p2 = find_pattern(argv, "productname", NULL))) + l2 += strlen(p2); + + if ((p != NULL) | (p2 != NULL)) { + b[cnt++] = CISTPL_VERS_1; + b[cnt++] = 2 + l1 + l2; + b[cnt++] = 8; + b[cnt++] = 0; + if (p) { + char *q = p; + /* Replace '_' by space */ + while ((q = strchr(q, '_'))) + *q = ' '; + memcpy(&b[cnt], p, l1); + } else + b[cnt] = '\0'; + cnt += l1; + + if (p2) { + char *q = p2; + /* Replace '_' by space */ + while ((q = strchr(q, '_'))) + *q = ' '; + memcpy(&b[cnt], p2, l2); + } else + b[cnt] = '\0'; + cnt += l2; + } + } else if (srv->tag == OTP_MANFID) { + bool found = FALSE; + uint manfid = 0, prodid = 0; + + if ((p = find_pattern(argv, "manfid", &manfid))) + found = TRUE; + + if ((p = find_pattern(argv, "prodid", &prodid))) + found = TRUE; + + if (found) { + b[cnt++] = CISTPL_MANFID; + b[cnt++] = srv->len; + b[cnt++] = (uint8)(manfid & 0xff); + b[cnt++] = (uint8)((manfid >> 8) & 0xff); + b[cnt++] = (uint8)(prodid & 0xff); + b[cnt++] = (uint8)((prodid >> 8) & 0xff); + } + } else if (srv->tag == HNBU_MACADDR) { + if ((p = find_pattern(argv, "macaddr", NULL))) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + if (!wl_ether_atoe(p, (struct ether_addr*)&b[cnt])) + printf("Argument does not look like a MAC " + "address: %s\n", p); + cnt += sizeof(struct ether_addr); + } + } else if (srv->tag == HNBU_CCODE) { + bool found = FALSE; + char tmp[3] = "\0\0\0"; + + if ((p = find_pattern(argv, "ccode", NULL))) { + found = TRUE; + tmp[0] = *p++; + tmp[1] = *p++; + } + if ((p = find_pattern(argv, "cctl", &val))) { + found = TRUE; + tmp[2] = (uint8)val; + } + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + memcpy(&b[cnt], tmp, 3); + cnt += 3; /* contents filled already */ + } + } else if (srv->tag == HNBU_RSSISMBXA2G) { + bool found = FALSE; + char tmp[2] = "\0\0"; + + if ((p = find_pattern(argv, "rssismf2g", &val))) { + found = TRUE; + tmp[0] |= val & 0xf; + } + if ((p = find_pattern(argv, "rssismc2g", &val))) { + found = TRUE; + tmp[0] |= (val & 0xf) << 4; + } + if ((p = find_pattern(argv, "rssisav2g", &val))) { + found = TRUE; + tmp[1] |= val & 0x7; + } + if ((p = find_pattern(argv, "bxa2g", &val))) { + found = TRUE; + tmp[1] |= (val & 0x3) << 3; + } + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + memcpy(&b[cnt], tmp, 2); + cnt += 2; /* contents filled already */ + } + } else if (srv->tag == HNBU_RSSISMBXA5G) { + bool found = FALSE; + char tmp[2] = "\0\0"; + + if ((p = find_pattern(argv, "rssismf5g", &val))) { + found = TRUE; + tmp[0] |= val & 0xf; + } + if ((p = find_pattern(argv, "rssismc5g", &val))) { + found = TRUE; + tmp[0] |= (val & 0xf) << 4; + } + if ((p = find_pattern(argv, "rssisav5g", &val))) { + found = TRUE; + tmp[1] |= val & 0x7; + } + if ((p = find_pattern(argv, "bxa5g", &val))) { + found = TRUE; + tmp[1] |= (val & 0x3) << 3; + } + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + memcpy(&b[cnt], tmp, 2); + cnt += 2; /* contents filled already */ + } + } else if (srv->tag == HNBU_FEM) { + bool found = FALSE; + uint16 tmp2g = 0, tmp5g = 0; + + if ((p = find_pattern(argv, "antswctl2g", &val))) { + found = TRUE; + tmp2g |= ((val << SROM8_FEM_ANTSWLUT_SHIFT) & + SROM8_FEM_ANTSWLUT_MASK); + } + if ((p = find_pattern(argv, "triso2g", &val))) { + found = TRUE; + tmp2g |= ((val << SROM8_FEM_TR_ISO_SHIFT) & + SROM8_FEM_TR_ISO_MASK); + } + if ((p = find_pattern(argv, "pdetrange2g", &val))) { + found = TRUE; + tmp2g |= ((val << SROM8_FEM_PDET_RANGE_SHIFT) & + SROM8_FEM_PDET_RANGE_MASK); + } + if ((p = find_pattern(argv, "extpagain2g", &val))) { + found = TRUE; + tmp2g |= ((val << SROM8_FEM_EXTPA_GAIN_SHIFT) & + SROM8_FEM_EXTPA_GAIN_MASK); + } + if ((p = find_pattern(argv, "tssipos2g", &val))) { + found = TRUE; + tmp2g |= ((val << SROM8_FEM_TSSIPOS_SHIFT) & + SROM8_FEM_TSSIPOS_MASK); + } + if ((p = find_pattern(argv, "antswctl5g", &val))) { + found = TRUE; + tmp5g |= ((val << SROM8_FEM_ANTSWLUT_SHIFT) & + SROM8_FEM_ANTSWLUT_MASK); + } + if ((p = find_pattern(argv, "triso5g", &val))) { + found = TRUE; + tmp5g |= ((val << SROM8_FEM_TR_ISO_SHIFT) & + SROM8_FEM_TR_ISO_MASK); + } + if ((p = find_pattern(argv, "pdetrange5g", &val))) { + found = TRUE; + tmp5g |= ((val << SROM8_FEM_PDET_RANGE_SHIFT) & + SROM8_FEM_PDET_RANGE_MASK); + } + if ((p = find_pattern(argv, "extpagain5g", &val))) { + found = TRUE; + tmp5g |= ((val << SROM8_FEM_EXTPA_GAIN_SHIFT) & + SROM8_FEM_EXTPA_GAIN_MASK); + } + if ((p = find_pattern(argv, "tssipos5g", &val))) { + found = TRUE; + tmp5g |= ((val << SROM8_FEM_TSSIPOS_SHIFT) & + SROM8_FEM_TSSIPOS_MASK); + } + + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + b[cnt++] = (uint8)(tmp2g & 0xff); + b[cnt++] = (uint8)((tmp2g >> 8) & 0xff); + b[cnt++] = (uint8)(tmp5g & 0xff); + b[cnt++] = (uint8)((tmp5g >> 8) & 0xff); + } + } else if (srv->tag == HNBU_UUID) { + + char *uuidstr = NULL; + char nibble[3] = {0, 0, 0}; + + if ((uuidstr = find_pattern(argv, "uuid", NULL)) != NULL) { + + /* uuid format 12345678-1234-5678-1234-567812345678 */ + + if (strlen(uuidstr) == 36) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + while (*uuidstr != '\0') { + if (*uuidstr == '-') { + uuidstr++; + continue; + } + nibble[0] = *uuidstr++; + nibble[1] = *uuidstr++; + b[cnt ++] = (char)strtoul(nibble, NULL, 16); + } + } + } + + } else if (srv->tag == HNBU_TEMPTHRESH) { + bool found = FALSE; + char tmp[6] = "\0\0\0\0\0\0"; + + if ((p = find_pattern(argv, "tempthresh", &val))) { + found = TRUE; + tmp[0] = val; + } + if ((p = find_pattern(argv, "temps_period", &val))) { + found = TRUE; + tmp[1] |= ((val << SROM11_TEMPS_PERIOD_SHIFT) & + SROM11_TEMPS_PERIOD_MASK); + } + if ((p = find_pattern(argv, "temps_hysteresis", &val))) { + found = TRUE; + tmp[1] |= ((val << SROM11_TEMPS_HYSTERESIS_SHIFT) & + SROM11_TEMPS_HYSTERESIS_MASK); + } + if ((p = find_pattern(argv, "tempoffset", &val))) { + found = TRUE; + tmp[2] = val; + } + if ((p = find_pattern(argv, "tempsense_slope", &val))) { + found = TRUE; + tmp[3] = val; + } + if ((p = find_pattern(argv, "tempcorrx", &val))) { + found = TRUE; + tmp[4] |= ((val << SROM11_TEMPCORRX_SHIFT) & + SROM11_TEMPCORRX_MASK); + } + if ((p = find_pattern(argv, "tempsense_option", &val))) { + found = TRUE; + tmp[4] |= ((val << SROM11_TEMPSENSE_OPTION_SHIFT) & + SROM11_TEMPSENSE_OPTION_MASK); + } + if ((p = find_pattern(argv, "phycal_tempdelta", &val))) { + found = TRUE; + tmp[5] = val; + } + + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + memcpy(&b[cnt], tmp, 6); + cnt += 6; /* contents filled already */ + } + } else if (srv->tag == HNBU_FEM_CFG) { + bool found = FALSE; + uint16 fem_cfg1 = 0, fem_cfg2 = 0; + + if ((p = find_pattern(argv, "femctrl", &val))) { + found = TRUE; + fem_cfg1 |= ((val << SROM11_FEMCTRL_SHIFT) & + SROM11_FEMCTRL_MASK); + } + if ((p = find_pattern(argv, "papdcap2g", &val))) { + found = TRUE; + fem_cfg1 |= ((val << SROM11_PAPDCAP_SHIFT) & + SROM11_PAPDCAP_MASK); + } + if ((p = find_pattern(argv, "tworangetssi2g", &val))) { + found = TRUE; + fem_cfg1 |= ((val << SROM11_TWORANGETSSI_SHIFT) & + SROM11_TWORANGETSSI_MASK); + } + if ((p = find_pattern(argv, "pdgain2g", &val))) { + found = TRUE; + fem_cfg1 |= ((val << SROM11_PDGAIN_SHIFT) & + SROM11_PDGAIN_MASK); + } + if ((p = find_pattern(argv, "epagain2g", &val))) { + found = TRUE; + fem_cfg1 |= ((val << SROM11_EPAGAIN_SHIFT) & + SROM11_EPAGAIN_MASK); + } + if ((p = find_pattern(argv, "tssiposslope2g", &val))) { + found = TRUE; + fem_cfg1 |= ((val << SROM11_TSSIPOSSLOPE_SHIFT) & + SROM11_TSSIPOSSLOPE_MASK); + } + if ((p = find_pattern(argv, "gainctrlsph", &val))) { + found = TRUE; + fem_cfg2 |= ((val << SROM11_GAINCTRLSPH_SHIFT) & + SROM11_GAINCTRLSPH_MASK); + } + if ((p = find_pattern(argv, "papdcap5g", &val))) { + found = TRUE; + fem_cfg2 |= ((val << SROM11_PAPDCAP_SHIFT) & + SROM11_PAPDCAP_MASK); + } + if ((p = find_pattern(argv, "tworangetssi5g", &val))) { + found = TRUE; + fem_cfg2 |= ((val << SROM11_TWORANGETSSI_SHIFT) & + SROM11_TWORANGETSSI_MASK); + } + if ((p = find_pattern(argv, "pdgain5g", &val))) { + found = TRUE; + fem_cfg2 |= ((val << SROM11_PDGAIN_SHIFT) & + SROM11_PDGAIN_MASK); + } + if ((p = find_pattern(argv, "epagain5g", &val))) { + found = TRUE; + fem_cfg2 |= ((val << SROM11_EPAGAIN_SHIFT) & + SROM11_EPAGAIN_MASK); + } + if ((p = find_pattern(argv, "tssiposslope5g", &val))) { + found = TRUE; + fem_cfg2 |= ((val << SROM11_TSSIPOSSLOPE_SHIFT) & + SROM11_TSSIPOSSLOPE_MASK); + } + + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + b[cnt++] = (uint8)(fem_cfg1 & 0xff); + b[cnt++] = (uint8)((fem_cfg1 >> 8) & 0xff); + b[cnt++] = (uint8)(fem_cfg2 & 0xff); + b[cnt++] = (uint8)((fem_cfg2 >> 8) & 0xff); + } + } else if (srv->tag == HNBU_ACRXGAINS_C0) { + bool found = FALSE; + uint16 rxgains = 0, rxgains1 = 0; + + if ((p = find_pattern(argv, "rxgains5gtrelnabypa0", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gtrisoa0", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GTRISOA_SHIFT) & + SROM11_RXGAINS5GTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gelnagaina0", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GELNAGAINA_SHIFT) & + SROM11_RXGAINS5GELNAGAINA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gtrelnabypa0", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GTRELNABYPA_SHIFT) & + SROM11_RXGAINS2GTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gtrisoa0", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GTRISOA_SHIFT) & + SROM11_RXGAINS2GTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gelnagaina0", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GELNAGAINA_SHIFT) & + SROM11_RXGAINS2GELNAGAINA_MASK); + } + + if ((p = find_pattern(argv, "rxgains5ghtrelnabypa0", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GHTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5ghtrisoa0", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHTRISOA_SHIFT) & + SROM11_RXGAINS5GHTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5ghelnagaina0", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHELNAGAINA_SHIFT) & + SROM11_RXGAINS5GHELNAGAINA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmtrelnabypa0", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GMTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmtrisoa0", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMTRISOA_SHIFT) & + SROM11_RXGAINS5GMTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmelnagaina0", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMELNAGAINA_SHIFT) & + SROM11_RXGAINS5GMELNAGAINA_MASK); + } + + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + b[cnt++] = (uint8)(rxgains & 0xff); + b[cnt++] = (uint8)((rxgains >> 8) & 0xff); + b[cnt++] = (uint8)(rxgains1 & 0xff); + b[cnt++] = (uint8)((rxgains1 >> 8) & 0xff); + } + } else if (srv->tag == HNBU_ACRXGAINS_C1) { + bool found = FALSE; + uint16 rxgains = 0, rxgains1 = 0; + + if ((p = find_pattern(argv, "rxgains5gtrelnabypa1", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gtrisoa1", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GTRISOA_SHIFT) & + SROM11_RXGAINS5GTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gelnagaina1", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GELNAGAINA_SHIFT) & + SROM11_RXGAINS5GELNAGAINA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gtrelnabypa1", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GTRELNABYPA_SHIFT) & + SROM11_RXGAINS2GTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gtrisoa1", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GTRISOA_SHIFT) & + SROM11_RXGAINS2GTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gelnagaina1", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GELNAGAINA_SHIFT) & + SROM11_RXGAINS2GELNAGAINA_MASK); + } + + if ((p = find_pattern(argv, "rxgains5ghtrelnabypa1", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GHTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5ghtrisoa1", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHTRISOA_SHIFT) & + SROM11_RXGAINS5GHTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5ghelnagaina1", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHELNAGAINA_SHIFT) & + SROM11_RXGAINS5GHELNAGAINA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmtrelnabypa1", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GMTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmtrisoa1", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMTRISOA_SHIFT) & + SROM11_RXGAINS5GMTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmelnagaina1", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMELNAGAINA_SHIFT) & + SROM11_RXGAINS5GMELNAGAINA_MASK); + } + + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + b[cnt++] = (uint8)(rxgains & 0xff); + b[cnt++] = (uint8)((rxgains >> 8) & 0xff); + b[cnt++] = (uint8)(rxgains1 & 0xff); + b[cnt++] = (uint8)((rxgains1 >> 8) & 0xff); + } + } else if (srv->tag == HNBU_ACRXGAINS_C2) { + bool found = FALSE; + uint16 rxgains = 0, rxgains1 = 0; + + if ((p = find_pattern(argv, "rxgains5gtrelnabypa2", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gtrisoa2", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GTRISOA_SHIFT) & + SROM11_RXGAINS5GTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gelnagaina2", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS5GELNAGAINA_SHIFT) & + SROM11_RXGAINS5GELNAGAINA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gtrelnabypa2", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GTRELNABYPA_SHIFT) & + SROM11_RXGAINS2GTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gtrisoa2", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GTRISOA_SHIFT) & + SROM11_RXGAINS2GTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains2gelnagaina2", &val))) { + found = TRUE; + rxgains |= ((val << SROM11_RXGAINS2GELNAGAINA_SHIFT) & + SROM11_RXGAINS2GELNAGAINA_MASK); + } + + if ((p = find_pattern(argv, "rxgains5ghtrelnabypa2", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GHTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5ghtrisoa2", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHTRISOA_SHIFT) & + SROM11_RXGAINS5GHTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5ghelnagaina2", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GHELNAGAINA_SHIFT) & + SROM11_RXGAINS5GHELNAGAINA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmtrelnabypa2", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMTRELNABYPA_SHIFT) & + SROM11_RXGAINS5GMTRELNABYPA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmtrisoa2", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMTRISOA_SHIFT) & + SROM11_RXGAINS5GMTRISOA_MASK); + } + if ((p = find_pattern(argv, "rxgains5gmelnagaina2", &val))) { + found = TRUE; + rxgains1 |= ((val << SROM11_RXGAINS5GMELNAGAINA_SHIFT) & + SROM11_RXGAINS5GMELNAGAINA_MASK); + } + + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + b[cnt++] = (uint8)(rxgains & 0xff); + b[cnt++] = (uint8)((rxgains >> 8) & 0xff); + b[cnt++] = (uint8)(rxgains1 & 0xff); + b[cnt++] = (uint8)((rxgains1 >> 8) & 0xff); + } + } else if (srv->tag == HNBU_PDOFF_2G) { + bool found = FALSE; + uint16 tmppdoff2g = 0; + + if ((p = find_pattern(argv, "pdoffset2g40ma0", &val))) { + found = TRUE; + tmppdoff2g |= ((val << SROM11_PDOFF_2G_40M_A0_SHIFT) & + SROM11_PDOFF_2G_40M_A0_MASK); + } + + if ((p = find_pattern(argv, "pdoffset2g40ma1", &val))) { + found = TRUE; + tmppdoff2g |= ((val << SROM11_PDOFF_2G_40M_A1_SHIFT) & + SROM11_PDOFF_2G_40M_A1_MASK); + } + + if ((p = find_pattern(argv, "pdoffset2g40ma2", &val))) { + found = TRUE; + tmppdoff2g |= ((val << SROM11_PDOFF_2G_40M_A2_SHIFT) & + SROM11_PDOFF_2G_40M_A2_MASK); + } + + if ((p = find_pattern(argv, "pdoffset2g40mvalid", &val))) { + found = TRUE; + tmppdoff2g |= ((val << SROM11_PDOFF_2G_40M_VALID_SHIFT) & + SROM11_PDOFF_2G_40M_VALID_MASK); + } + + if (found) { + newtuple(&b[cnt], &cnt, CISTPL_BRCM_HNBU, srv); + b[cnt++] = (uint8)(tmppdoff2g & 0xff); + b[cnt++] = (uint8)((tmppdoff2g >> 8) & 0xff); + } + } else { /* All other tuples */ + int found = FALSE, varlen = 0; + char *cur = &b[cnt]; + uint newtp = TRUE; + + /* example srv->params contents: "1aa2g 1aa5g" */ + par = malloc(strlen(srv->params)+1); + if (!par) + return BCME_NOMEM; + + /* Walk through each parameters in one tuple */ + strcpy(par, srv->params); + + cpar = strtok (par, delimit); /* current param */ + while (cpar) { + int array_sz = 1; + val = 0; + + /* Fill the CIS tuple to b but don't commit cnt yet */ + if (newtp) { + newtuple(cur, NULL, CISTPL_BRCM_HNBU, srv); + cur += 3; + newtp = FALSE; + } + + /* the first byte of each parameter indicates its length */ + varlen = (*cpar++) - '0'; + + /* parse array size if any */ + if (*cpar == '*') { + array_sz = 0; + while (((*++cpar) >= '0') && (*cpar <= '9')) + array_sz = (array_sz * 10) + *cpar - '0'; + } + + /* Find the parameter in the input argument list */ + if ((p = find_pattern(argv, cpar, &val))) + found = TRUE; + else + val = 0; + + while (found && array_sz--) { + *cur++ = (uint8)(val & 0xff); + if (varlen >= 2) + *cur++ = (uint8)((val >> 8) & 0xff); + if (varlen >= 4) { + *cur++ = (uint8)((val >> 16) & 0xff); + *cur++ = (uint8)((val >> 24) & 0xff); + } + + /* skip the "," if more array elements */ + if (p && array_sz) { + char *q = NULL; + + p = strstr (p, ","); /* current param */ + if (p) { + p++; + val = strtoul(p, &q, strncmp(p, "0x", 2) ? + 10 : 16); + } else { + printf("Input array size error!"); + free(par); + return BCME_BADARG; + } + } + } + + /* move to the next parameter string */ + cpar = strtok(NULL, delimit); + } + free(par); + + /* commit the tuple if its valid */ + if (found) + cnt += (cur - &b[cnt]); + } + + srv++; + } + + printf("sromrev %d buffer size %d bytes:\n", sromrev, cnt); + for (i = 0; i < cnt; i++) { + printf("0x%.02x ", b[i] & 0xff); + if (i%8 == 7) printf("\n"); + } + printf("\n"); + + return cnt; +} + +static const sromvar_t * +srvlookup(const sromvar_t *tab, char *name, int nlen, int sromrev) +{ + uint32 srrmask; + const sromvar_t *srv = tab; + + srrmask = 1 << sromrev; + + while (srv->name) { + if ((strncmp(name, srv->name, nlen) == 0) && + ((srrmask & srv->revmask) != 0)) + break; + while (srv->flags & SRFL_MORE) + srv++; + srv++; + } + + return srv; +} + +static int +wl_nvsource(void *wl, cmd_t *cmd, char **argv) +{ + int32 val, err; + + if ((err = wl_var_get(wl, cmd, argv))) + return (err); + + val = dtoh32(*(int32*)buf); + + switch (val) { + case 0: + printf("SROM\n"); + break; + case 1: + printf("OTP\n"); + break; + case 2: + printf("NVRAM\n"); + break; + default: + printf("Unrecognized source %d\n", val); + break; + } + + return 0; +} + +/** read/write caller supplied NVRAM variables in OTP or SROM */ +static int +wlu_srvar(void *wl, cmd_t *cmd, char **argv) +{ + int ret, nw, nlen, ro, co, wr, sromrev, shift = 0; + bool otp = FALSE; + uint32 val32 = 0; + char *name, *p, *newval; + const sromvar_t *srv; + uint16 w, *words = (uint16 *)&buf[8]; + srom_rw_t *srt; + struct ether_addr ea; + + ro = !strcmp(*argv, "rdvar"); + wr = !strcmp(*argv, "wrvar"); + co = !strcmp(*argv, "cisconvert"); + + if (!*++argv) + return BCME_USAGE_ERROR; + + /* Query the driver on where the cis comes from: OTP or SROM */ + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(buf, "cis_source"); + ret = wl_get(wl, WLC_GET_VAR, buf, strlen(buf)+1); + if (ret < 0) { + ; /* printf("Error %x: cannot get cis_source\n", ret); */ + } + + if (buf[0] == WLC_CIS_OTP) + otp = TRUE; + if (otp && ro) { + /* read caller supplied nvram variable from driver */ + wl_nvget(wl, cmd, --argv); + return ret; + } + + /* + * Before OTP can be written, the caller supplied nvram string has to be converted into a + * list of CIS tuples. This CIS format is SROM rev dependent. + */ + if ((otp && wr) || co) { + int cnt = 0, err = 0; + uint sromrev = 8; + void *p = NULL; + + /* Read all nvram variables from driver and retrieve srom revision from that */ + if ((err = wlu_var_getbuf(wl, "nvram_dump", NULL, 0, &p)) < 0) { + err = wlu_get(wl, WLC_NVRAM_DUMP, &buf[0], WLC_IOCTL_MAXLEN); + } + + if (err) { + printf("Fail to get sromrev from nvram file!\n"); + return err; + } + + if ((p = strstr(p, "sromrev"))) { + char *q = NULL; + + p = (void*)((char*)p + 8); + /* for OTP, its either srom rev 10 or 16 */ + sromrev = strtoul(p, &q, strncmp(p, "0x", 2) ? 10 : 16); + } else { + printf("sromrev not defined in nvram file!\n"); + return BCME_ERROR; + } + + /* convert caller supplied nvram string (in argv) into a list of tuples (in buf) */ + if ((cnt = parsecis(buf, argv, sromrev)) <= 0) { + printf("CIS parse failure!\n"); + return BCME_ERROR; + } + + /* leave an empty srom_rw_t at the front for backward + * compatibility + */ + if (!co) { + /* + * Pass the CIS containing caller supplied nvram vars to driver so driver + * can write OTP. Driver decides which OTP region (hardware,software) will + * be written, depending on chip type and bus type. + */ + ret = wlu_iovar_set(wl, "cisvar", buf, cnt); /* IOV_BMAC_CISVAR */ + } + return ret; + } + + /* First read the srom and find out the sromrev */ + srt = (srom_rw_t *)buf; + srt->byteoff = htod32(0); + srt->nbytes = htod32(2 * SROM4_WORDS); + + if (cmd->get < 0) + return -1; + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return ret; + + if (words[SROM11_SIGN] == SROM11_SIGNATURE) { + sromrev = 11; + + srt->byteoff = htod32(0); + srt->nbytes = htod32(2 * SROM11_WORDS); + + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return ret; + + } else { + if ((words[SROM4_SIGN] != SROM4_SIGNATURE) && + (words[SROM8_SIGN] != SROM4_SIGNATURE)) + nw = SROM_CRCREV; + else + nw = SROM4_CRCREV; + sromrev = words[nw] & 0xff; + } + + if ((sromrev < 2) || (sromrev > SROM_MAXREV)) { + return BCME_ERROR; + } + + nw = 0; + while ((name = *argv++) != NULL) { + int off, off_base; + + newval = strchr(name, '='); + if (newval) + *newval++ = '\0'; + nlen = strlen(name); + if ((nlen == 0) || (nlen > 16)) { + printf("Bad variable name: %s\n", name); + continue; + } + off = 0; + srv = srvlookup(pci_sromvars, name, nlen + 1, sromrev); + if (srv->name == NULL) { + int path; + + srv = srvlookup(perpath_pci_sromvars, name, nlen - 1, sromrev); + path = name[nlen - 1] - '0'; + if ((srv->name == NULL) || (path < 0) || (path >= MAX_PATH_SROM)) { + printf("Variable %s does not exist in sromrev %d\n", + name, sromrev); + continue; + } + if (sromrev >= 11) { + if (path == 0) { + off = SROM11_PATH0; + } else if (path == 1) { + off = SROM11_PATH1; + } else if (path == 2) { + off = SROM11_PATH2; + } + } else if (sromrev >= 8) { + if (path == 0) { + off = SROM8_PATH0; + } else if (path == 1) { + off = SROM8_PATH1; + } else if (path == 2) { + off = SROM8_PATH2; + } else if (path == 3) { + off = SROM8_PATH3; + } + } else + off = (path == 0) ? SROM4_PATH0 : SROM4_PATH1; + } + off_base = off; + off += srv->off; + + if (ro) { + /* This code is cheating a bit: it knows that SRFL_ETHADDR means three + * whole words, and SRFL_MORE means 2 whole words (i.e. the masks for + * them are all 0xffff). + */ + if (srv->flags & SRFL_ETHADDR) { + w = words[off]; + ea.octet[0] = w >> 8; + ea.octet[1] = w & 0xff; + w = words[off + 1]; + ea.octet[2] = w >> 8; + ea.octet[3] = w & 0xff; + w = words[off + 2]; + ea.octet[4] = w >> 8; + ea.octet[5] = w & 0xff; + } else if (srv->flags & SRFL_MORE) { + val32 = words[off]; + val32 |= words[srv[1].off] << 16; + } else { + shift = ffs(srv->mask) - 1; + val32 = (words[off] & srv->mask) >> shift; + } + + /* OK, print it */ + if (srv->flags & SRFL_ETHADDR) + printf("%s=%s", name, wl_ether_etoa(&ea)); + else if (srv->flags & SRFL_PRHEX) + printf("%s=0x%x", name, val32); + else if (srv->flags & SRFL_PRSIGN) + printf("%s=%d", name, val32); + else + printf("%s=%u", name, val32); + + if (srv->flags & SRFL_ARRAY) { + do { + srv ++; + off = off_base + srv->off; + + if (srv->name == NULL) + break; + + shift = ffs(srv->mask) - 1; + val32 = (words[off] & srv->mask) >> shift; + + if (srv->flags & SRFL_PRHEX) + printf(",0x%x", val32); + else if (srv->flags & SRFL_PRSIGN) + printf(",%d", val32); + else + printf(",%u", val32); + } while (srv->flags & SRFL_ARRAY); + } + printf("\n"); + + } else { /* wr */ + + /* Make the change in the image we read */ + if (!newval) { + printf("wrvar missing value to write for variable %s\n", name); + ro = 1; + break; + } + + /* Cheating again as above */ + if (srv->flags & SRFL_ETHADDR) { + if (!wl_ether_atoe(newval, &ea)) { + printf("Argument does not look like a MAC address: %s\n", + newval); + ret = BCME_USAGE_ERROR; + ro = 1; + break; + } + words[off] = (ea.octet[0] << 8) | ea.octet[1]; + words[off + 1] = (ea.octet[2] << 8) | ea.octet[3]; + words[off + 2] = (ea.octet[4] << 8) | ea.octet[5]; + off += 2; + } else { + val32 = strtoul(newval, &p, 0); + if (p == newval) { + printf("Bad value: %s for variable %s\n", newval, name); + ro = 1; + break; + } + + if (srv->flags & SRFL_MORE) { + words[off] = val32 & 0xffff; + words[off + 1] = val32 >> 16; + off++; + } else { + shift = ffs(srv->mask) - 1; + words[off] = (((val32 << shift) & srv->mask) | + (words[off] & ~srv->mask)); + + if (srv->flags & SRFL_ARRAY) { + do { + srv ++; + off = off_base + srv->off; + + if (srv->name == NULL) + break; + + newval = p + 1; + val32 = strtoul(newval, &p, 0); + if (p == newval) { + printf( + "Bad value: %s for variable %s\n", + newval, name); + ro = 1; + break; + } + + shift = ffs(srv->mask) - 1; + words[off] = + (((val32 << shift) & srv->mask) | + (words[off] & ~srv->mask)); + } while (srv->flags & SRFL_ARRAY); + } + } + } + + if (off > nw) + nw = off; + } + } + + if (!ro) { + /* Now write all the changes */ + nw++; + srt->byteoff = 0; + srt->nbytes = htod32(2 * nw); + ret = wlu_set(wl, cmd->set, buf, (2 * nw) + 8); + if (ret < 0) + printf("Error %d writing the srom\n", ret); + } + + return ret; +} + +/* All 32bits are used. Please populate wl_msgs2[] with further entries */ +static dbg_msg_t wl_msgs[] = { + {WL_ERROR_VAL, "error"}, + {WL_ERROR_VAL, "err"}, + {WL_TRACE_VAL, "trace"}, + {WL_PRHDRS_VAL, "prhdrs"}, + {WL_PRPKT_VAL, "prpkt"}, + {WL_INFORM_VAL, "inform"}, + {WL_INFORM_VAL, "info"}, + {WL_INFORM_VAL, "inf"}, + {WL_TMP_VAL, "tmp"}, + {WL_OID_VAL, "oid"}, + {WL_RATE_VAL, "rate"}, + {WL_ASSOC_VAL, "assoc"}, + {WL_ASSOC_VAL, "as"}, + {WL_PRUSR_VAL, "prusr"}, + {WL_PS_VAL, "ps"}, + {WL_TXPWR_VAL, "txpwr"}, + {WL_TXPWR_VAL, "pwr"}, + {WL_PORT_VAL, "port"}, + {WL_DUAL_VAL, "dual"}, + {WL_WSEC_VAL, "wsec"}, + {WL_WSEC_DUMP_VAL, "wsec_dump"}, + {WL_LOG_VAL, "log"}, + {WL_NRSSI_VAL, "nrssi"}, + {WL_LOFT_VAL, "loft"}, + {WL_REGULATORY_VAL, "regulatory"}, + {WL_RADAR_VAL, "radar"}, + {WL_MPC_VAL, "mpc"}, + {WL_APSTA_VAL, "apsta"}, + {WL_DFS_VAL, "dfs"}, + {WL_MBSS_VAL, "mbss"}, + {WL_CAC_VAL, "cac"}, + {WL_AMSDU_VAL, "amsdu"}, + {WL_AMPDU_VAL, "ampdu"}, + {WL_FFPLD_VAL, "ffpld"}, + {0, NULL} +}; + +/* msglevels which use wl_msg_level2 should go here */ +static dbg_msg_t wl_msgs2[] = { + {WL_DPT_VAL, "dpt"}, + {WL_SCAN_VAL, "scan"}, + {WL_WOWL_VAL, "wowl"}, + {WL_COEX_VAL, "coex"}, + {WL_RTDC_VAL, "rtdc"}, + {WL_PROTO_VAL, "proto"}, +#ifdef WLBTAMP + {WL_BTA_VAL, "bta"}, +#endif + {WL_CHANINT_VAL, "chanim"}, + {WL_WMF_VAL, "wmf"}, +#ifdef WLP2P + {WL_P2P_VAL, "p2p"}, +#endif + {WL_ITFR_VAL, "itfr"}, +#ifdef WLMCHAN + {WL_MCHAN_VAL, "mchan"}, +#endif +#ifdef WLTDLS + {WL_TDLS_VAL, "tdls"}, +#endif + {WL_PSTA_VAL, "psta"}, + {WL_MCNX_VAL, "mcnx"}, + {WL_PROT_VAL, "prot"}, + {WL_TBTT_VAL, "tbtt"}, + {WL_NIC_VAL, "nic"}, + {WL_TIMESTAMP_VAL, "time"}, + {WL_PWRSEL_VAL, "lpc"}, + {WL_TSO_VAL, "tso"}, + {WL_MQ_VAL, "mq"}, +#ifdef WLP2PO + {WL_P2PO_VAL, "p2po"}, +#endif + {WL_WNM_VAL, "wnm"}, + {0, NULL} +}; + +static int +wl_msglevel(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + uint hval = 0, len, val = 0, found, last_val = 0, msglevel = 0, msglevel2_add = 0; + uint msglevel2_del = 0, msglevel_add = 0, msglevel_del = 0, supported = 1; + char *endptr = NULL; + dbg_msg_t *dbg_msg = wl_msgs, *dbg_msg2 = wl_msgs2; + void *ptr = NULL; + struct wl_msglevel2 msglevel64, *reply; + const char *cmdname = "msglevel"; + + UNUSED_PARAMETER(cmd); + + /* but preseve older IOCTL call for older drivers */ + if ((ret = wlu_var_getbuf_sm(wl, cmdname, &msglevel64, sizeof(msglevel64), &ptr) < 0)) { + if ((ret = wlu_get(wl, WLC_GET_MSGLEVEL, &msglevel, sizeof(int))) < 0) + return (ret); + supported = 0; + msglevel = dtoh32(msglevel); + if (!*++argv) { + printf("0x%x ", msglevel); + for (i = 0; (val = dbg_msg[i].value); i++) { + if ((msglevel & val) && (val != last_val)) + printf(" %s", dbg_msg[i].string); + last_val = val; + } + printf("\n"); + return (0); + } + while (*argv) { + char *s = *argv; + if (*s == '+' || *s == '-') + s++; + else + msglevel_del = ~0; /* make the whole list absolute */ + val = strtoul(s, &endptr, 0); + if (val == 0xFFFFFFFF) { + fprintf(stderr, + "Bits >32 are not supported on this driver version\n"); + val = 1; + } + /* not an integer if not all the string was parsed by strtoul */ + if (*endptr != '\0') { + for (i = 0; (val = dbg_msg[i].value); i++) + if (stricmp(dbg_msg[i].string, s) == 0) + break; + if (!val) + goto usage; + } + if (**argv == '-') + msglevel_del |= val; + else + msglevel_add |= val; + ++argv; + } + msglevel &= ~msglevel_del; + msglevel |= msglevel_add; + msglevel = htod32(msglevel); + return (wlu_set(wl, WLC_SET_MSGLEVEL, &msglevel, sizeof(int))); + } else { /* 64bit message level */ + reply = (struct wl_msglevel2 *)ptr; + reply->low = dtoh32(reply->low); + reply->high = dtoh32(reply->high); + if (!*++argv) { + if (reply->high != 0) + printf("0x%x%08x", reply->high, reply->low); + else + printf("0x%x ", reply->low); + for (i = 0; (val = dbg_msg2[i].value); i++) { + if (((reply->high & val)) && (val != last_val)) + printf(" %s", dbg_msg2[i].string); + last_val = val; + } + last_val = 0; + for (i = 0; (val = dbg_msg[i].value); i++) { + if (((reply->low & val)) && (val != last_val)) + printf(" %s", dbg_msg[i].string); + last_val = val; + } + printf("\n"); + return (0); + } + while (*argv) { + char* s = *argv; + char t[32]; + found = 0; + if (*s == '+' || *s == '-') + s++; + else { + msglevel_del = ~0; /* make the whole list absolute */ + msglevel2_del = ~0; + } + val = strtoul(s, &endptr, 0); + if (val == 0xFFFFFFFF){ /* Assume >32 bit hex passed in */ + if (!(*s == '0' && *(s+1) == 'x')) { + fprintf(stderr, + "Msg bits >32 take only numerical input in hex\n"); + val = 0; + } else { + char c[32] = "0x"; + len = strlen(s); + hval = strtoul(strncpy(t, s, len-8), &endptr, 0); + *endptr = 0; + s = s+strlen(t); + s = strcat(c, s); + val = strtoul(s, &endptr, 0); + if (hval == 0xFFFFFFFF) { + fprintf(stderr, "Invalid entry for msglevel\n"); + hval = 0; + val = 0; + } + } + } + if (*endptr != '\0') { + for (i = 0; (val = dbg_msg[i].value); i++) { + if (stricmp(dbg_msg[i].string, s) == 0) { + found = 1; + break; + } + } + if (!found) { + for (i = 0; (hval = dbg_msg2[i].value); i++) + if (stricmp(dbg_msg2[i].string, s) == 0) + break; + } + if (!val && !hval) + goto usage; + } + if (**argv == '-') { + msglevel_del |= val; + if (!found) + msglevel2_del |= hval; + } + else { + msglevel_add |= val; + if (!found) + msglevel2_add |= hval; + } + ++argv; + } + reply->low &= ~msglevel_del; + reply->high &= ~msglevel2_del; + reply->low |= msglevel_add; + reply->high |= msglevel2_add; + reply->low = htod32(reply->low); + reply->high = htod32(reply->high); + msglevel64.low = reply->low; + msglevel64.high = reply->high; + return (wlu_var_setbuf(wl, cmdname, &msglevel64, sizeof(msglevel64))); + } + +usage: + fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n"); + fprintf(stderr, "Use a + or - prefix to make an incremental change."); + + for (i = 0; (val = dbg_msg[i].value); i++) { + if (val != last_val) + fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string); + else + fprintf(stderr, ", %s", dbg_msg[i].string); + last_val = val; + } + if (supported) { + for (i = 0; (val = dbg_msg2[i].value); i++) { + if (val != last_val) + fprintf(stderr, "\n0x%x00000000 %s", val, dbg_msg2[i].string); + else + fprintf(stderr, ", %s", dbg_msg2[i].string); + last_val = val; + } + } + fprintf(stderr, "\n"); + return 0; +} + +#include <phy_dbg_api.h> + +static phy_msg_t wl_phy_msgs[] = { + {PHYHAL_ERROR, "error"}, + {PHYHAL_ERROR, "err"}, + {PHYHAL_TRACE, "trace"}, + {PHYHAL_INFORM, "inform"}, + {PHYHAL_TMP, "tmp"}, + {PHYHAL_TXPWR, "txpwr"}, + {PHYHAL_CAL, "cal"}, + {PHYHAL_RADAR, "radar"}, + {PHYHAL_THERMAL, "thermal"}, + {PHYHAL_PAPD, "papd"}, + {PHYHAL_RXIQ, "rxiq"}, + {PHYHAL_FCBS, "fcbs"}, + {0, NULL} + }; + +static int +wl_phymsglevel(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + uint val = 0, last_val = 0; + uint phymsglevel = 0, phymsglevel_add = 0, phymsglevel_del = 0; + char *endptr; + phy_msg_t *phy_msg = wl_phy_msgs; + const char *cmdname = "phymsglevel"; + + UNUSED_PARAMETER(cmd); + if ((ret = wlu_iovar_getint(wl, cmdname, (int *)&phymsglevel) < 0)) { + return ret; + } + phymsglevel = dtoh32(phymsglevel); + if (!*++argv) { + printf("0x%x ", phymsglevel); + for (i = 0; (val = phy_msg[i].value); i++) { + if ((phymsglevel & val) && (val != last_val)) + printf(" %s", phy_msg[i].string); + last_val = val; + } + printf("\n"); + return (0); + } + while (*argv) { + char *s = *argv; + if (*s == '+' || *s == '-') + s++; + else + phymsglevel_del = ~0; /* make the whole list absolute */ + val = strtoul(s, &endptr, 0); + if (val == 0xFFFFFFFF) { + fprintf(stderr, + "Bits >32 are not supported on this driver version\n"); + val = 1; + } + /* not an integer if not all the string was parsed by strtoul */ + if (*endptr != '\0') { + for (i = 0; (val = phy_msg[i].value); i++) + if (stricmp(phy_msg[i].string, s) == 0) + break; + if (!val) + goto usage; + } + if (**argv == '-') + phymsglevel_del |= val; + else + phymsglevel_add |= val; + ++argv; + } + phymsglevel &= ~phymsglevel_del; + phymsglevel |= phymsglevel_add; + phymsglevel = htod32(phymsglevel); + return (wlu_iovar_setint(wl, cmdname, (int)phymsglevel)); + +usage: + fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n"); + fprintf(stderr, "Use a + or - prefix to make an incremental change."); + for (i = 0; (val = phy_msg[i].value); i++) { + if (val != last_val) + fprintf(stderr, "\n0x%04x %s", val, phy_msg[i].string); + else + fprintf(stderr, ", %s", phy_msg[i].string); + last_val = val; + } + return 0; +} + +struct d11_mcs_rate_info { + uint8 constellation_bits; + uint8 coding_q; + uint8 coding_d; +}; + +static const struct d11_mcs_rate_info wlu_mcs_info[] = { + { 1, 1, 2 }, /* MCS 0: MOD: BPSK, CR 1/2 */ + { 2, 1, 2 }, /* MCS 1: MOD: QPSK, CR 1/2 */ + { 2, 3, 4 }, /* MCS 2: MOD: QPSK, CR 3/4 */ + { 4, 1, 2 }, /* MCS 3: MOD: 16QAM, CR 1/2 */ + { 4, 3, 4 }, /* MCS 4: MOD: 16QAM, CR 3/4 */ + { 6, 2, 3 }, /* MCS 5: MOD: 64QAM, CR 2/3 */ + { 6, 3, 4 }, /* MCS 6: MOD: 64QAM, CR 3/4 */ + { 6, 5, 6 }, /* MCS 7: MOD: 64QAM, CR 5/6 */ + { 8, 3, 4 }, /* MCS 8: MOD: 256QAM, CR 3/4 */ + { 8, 5, 6 } /* MCS 9: MOD: 256QAM, CR 5/6 */ +}; + +static uint +wl_mcs2rate(uint mcs, uint nss, uint bw, int sgi) +{ + const int ksps = 250; /* kilo symbols per sec, 4 us sym */ + const int Nsd_20MHz = 52; + const int Nsd_40MHz = 108; + const int Nsd_80MHz = 234; + const int Nsd_160MHz = 468; + uint rate; + + if (mcs == 32) { + /* just return fixed values for mcs32 instead of trying to parametrize */ + rate = (sgi == 0) ? 6000 : 6700; + } else if (mcs <= 9) { + /* This calculation works for 11n HT and 11ac VHT if the HT mcs values + * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. + * That is, HT MCS 23 is a base MCS = 7, Nss = 3 + */ + + /* find the number of complex numbers per symbol */ + if (bw == 20) { + rate = Nsd_20MHz; + } else if (bw == 40) { + rate = Nsd_40MHz; + } else if (bw == 80) { + rate = Nsd_80MHz; + } else if (bw == 160) { + rate = Nsd_160MHz; + } else { + rate = 1; + } + + /* multiply by bits per number from the constellation in use */ + rate = rate * wlu_mcs_info[mcs].constellation_bits; + + /* adjust for the number of spatial streams */ + rate = rate * nss; + + /* adjust for the coding rate given as a quotient and divisor */ + rate = (rate * wlu_mcs_info[mcs].coding_q) / wlu_mcs_info[mcs].coding_d; + + /* multiply by Kilo symbols per sec to get Kbps */ + rate = rate * ksps; + + /* adjust the symbols per sec for SGI + * symbol duration is 4 us without SGI, and 3.6 us with SGI, + * so ratio is 10 / 9 + */ + if (sgi) { + /* add 4 for rounding of division by 9 */ + rate = ((rate * 10) + 4) / 9; + } + } else { + rate = 0; + } + + return rate; +} + +/* take a wl_ratespec arg and return phy rate in 500Kbps units */ +static int +wl_ratespec2rate(uint32 rspec) +{ + const char* fn_name = "wl_ratespec2rate"; + int rate = -1; + int sgi = ((rspec & WL_RSPEC_SGI) != 0); + + if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { + rate = (rspec & WL_RSPEC_RATE_MASK); + } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { + uint mcs = (rspec & WL_RSPEC_RATE_MASK); + + if (mcs > 32) { + fprintf(stderr, "%s: MCS %u out of range (>32) in ratespec 0x%X\n", + fn_name, mcs, rspec); + } else if (mcs == 32) { + rate = wl_mcs2rate(mcs, 1, 40, sgi) / 500; + } else { + uint nss = 1 + (mcs / 8); + mcs = mcs % 8; + + rate = wl_mcs2rate(mcs, nss, 20, sgi) / 500; + } + } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { + uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); + uint nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; + + rate = wl_mcs2rate(mcs, nss, 20, sgi) / 500; + } else { + fprintf(stderr, "%s: expected rate encoding in ratespec 0x%X\n", + fn_name, (uint)rspec); + } + + return rate; +} + +/* take rate arg in units of 500Kbits/s and print it in units of Mbit/s */ +static void +wl_printrate(int val) +{ + char rate_buf[32]; + + printf("%s\n", rate_int2string(rate_buf, val)); +} + +/* convert rate string in Mbit/s format, like "11", "5.5", to internal 500 Kbit/s units */ +static int +rate_string2int(char *s) +{ + if (!stricmp(s, "-1")) + return (0); + if (!stricmp(s, "5.5")) + return (11); + return (atoi(s) * 2); +} + +/* convert rate internal 500 Kbits/s units to string in Mbits/s format, like "11", "5.5" */ +static char* +rate_int2string(char *rate_buf, int val) +{ + if ((val == -1) || (val == 0)) + sprintf(rate_buf, "auto"); + else + sprintf(rate_buf, "%d%s Mbps", (val / 2), (val & 1) ? ".5" : ""); + return (rate_buf); +} + +/* Format a ratespec for "nrate" output + * Will handle both current wl_ratespec and legacy (ioctl_version 1) nrate ratespec + */ +static void +wl_nrate_print(uint32 rspec) +{ + const char * rspec_auto = "auto"; + uint encode, rate, txexp = 0, bw_val; + const char* stbc = ""; + const char* ldpc = ""; + const char* sgi = ""; + const char* bw = ""; + int stf; + + if (rspec == 0) { + encode = WL_RSPEC_ENCODE_RATE; + } else if (ioctl_version == 1) { + encode = (rspec & OLD_NRATE_MCS_INUSE) ? WL_RSPEC_ENCODE_HT : WL_RSPEC_ENCODE_RATE; + stf = (int)((rspec & OLD_NRATE_STF_MASK) >> OLD_NRATE_STF_SHIFT); + rate = (rspec & OLD_NRATE_RATE_MASK); + + if (rspec & OLD_NRATE_OVERRIDE) { + if (rspec & OLD_NRATE_OVERRIDE_MCS_ONLY) + rspec_auto = "fixed mcs only"; + else + rspec_auto = "fixed"; + } + } else { + int siso; + encode = (rspec & WL_RSPEC_ENCODING_MASK); + rate = (rspec & WL_RSPEC_RATE_MASK); + txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT; + stbc = ((rspec & WL_RSPEC_STBC) != 0) ? " stbc" : ""; + ldpc = ((rspec & WL_RSPEC_LDPC) != 0) ? " ldpc" : ""; + sgi = ((rspec & WL_RSPEC_SGI) != 0) ? " sgi" : ""; + bw_val = (rspec & WL_RSPEC_BW_MASK); + + if (bw_val == WL_RSPEC_BW_20MHZ) { + bw = "bw20"; + } else if (bw_val == WL_RSPEC_BW_40MHZ) { + bw = "bw40"; + } else if (bw_val == WL_RSPEC_BW_80MHZ) { + bw = "bw80"; + } else if (bw_val == WL_RSPEC_BW_160MHZ) { + bw = "bw160"; + } + + /* initialize stf mode to an illegal value and + * fix to a backward compatable value if possible + */ + stf = -1; + /* for stf calculation, determine if the rate is single stream. + * Legacy rates WL_RSPEC_ENCODE_RATE are single stream, and + * HT rates for mcs 0-7 are single stream + */ + siso = (encode == WL_RSPEC_ENCODE_RATE) || + ((encode == WL_RSPEC_ENCODE_HT) && rate < 8); + + /* calc a value for nrate stf mode */ + if (txexp == 0) { + if ((rspec & WL_RSPEC_STBC) && siso) { + /* STF mode STBC */ + stf = OLD_NRATE_STF_STBC; + } else { + /* STF mode SISO or SDM */ + stf = (siso) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM; + } + } else if (txexp == 1 && siso) { + /* STF mode CDD */ + stf = OLD_NRATE_STF_CDD; + } + + if (rspec & WL_RSPEC_OVERRIDE_RATE) { + rspec_auto = "fixed"; + } + } + + if (encode == WL_RSPEC_ENCODE_RATE) { + if (rspec == 0) { + printf("auto\n"); + } else { + printf("legacy rate %d%s Mbps stf mode %d %s\n", + rate/2, (rate % 2)?".5":"", stf, rspec_auto); + } + } else if (encode == WL_RSPEC_ENCODE_HT) { + printf("mcs index %d stf mode %d %s\n", + rate, stf, rspec_auto); + } else { + uint vht = (rspec & WL_RSPEC_VHT_MCS_MASK); + uint Nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; + printf("vht mcs %d Nss %d Tx Exp %d %s%s%s%s %s\n", + vht, Nss, txexp, bw, stbc, ldpc, sgi, rspec_auto); + } +} + +/* + * Format a ratespec for output of any of the wl_rate() iovars + */ +static char* +wl_rate_print(char *rate_buf, uint32 rspec) +{ + uint encode, rate, txexp, bw_val; + const char* stbc; + const char* ldpc; + const char* sgi; + const char* bw; + + encode = (rspec & WL_RSPEC_ENCODING_MASK); + rate = (rspec & WL_RSPEC_RATE_MASK); + txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT; + bw_val = (rspec & WL_RSPEC_BW_MASK); + stbc = ((rspec & WL_RSPEC_STBC) != 0) ? " stbc" : ""; + ldpc = ((rspec & WL_RSPEC_LDPC) != 0) ? " ldpc" : ""; + sgi = ((rspec & WL_RSPEC_SGI) != 0) ? " sgi" : ""; + + if (bw_val == WL_RSPEC_BW_UNSPECIFIED) { + bw = "auto"; + } else if (bw_val == WL_RSPEC_BW_20MHZ) { + bw = "20"; + } else if (bw_val == WL_RSPEC_BW_40MHZ) { + bw = "40"; + } else if (bw_val == WL_RSPEC_BW_80MHZ) { + bw = "80"; + } else if (bw_val == WL_RSPEC_BW_160MHZ) { + bw = "160"; + } else { + bw = "???"; + } + + if ((rspec & ~WL_RSPEC_TXEXP_MASK) == 0) { /* Ignore TxExpansion for NULL rspec check */ + sprintf(rate_buf, "auto"); + } else if (encode == WL_RSPEC_ENCODE_RATE) { + sprintf(rate_buf, "rate %d%s Mbps Tx Exp %d", + rate/2, (rate % 2)?".5":"", txexp); + } else if (encode == WL_RSPEC_ENCODE_HT) { + sprintf(rate_buf, "ht mcs %d Tx Exp %d BW %s%s%s%s", + rate, txexp, bw, stbc, ldpc, sgi); + } else if (encode == WL_RSPEC_ENCODE_VHT) { + uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); + uint Nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; + sprintf(rate_buf, "vht mcs %d Nss %d Tx Exp %d BW %s%s%s%s", + mcs, Nss, txexp, bw, stbc, ldpc, sgi); + } else { + sprintf(rate_buf, "<unknown encoding for ratespec 0x%08X>", rspec); + } + + return rate_buf; +} + +/* handles both "rate" and "mrate", which makes the flow a bit complex */ +static int +wl_rate_mrate(void *wl, cmd_t *cmd, char **argv) +{ + const char* fn_name = "wl_rate_mrate"; + int error; + int val; + int band; + int list[3]; + char aname[sizeof("5g_mrate") + 1]; + char bgname[sizeof("2g_mrate") + 1]; + char *name; + + sprintf(aname, "5g_%s", cmd->name); + sprintf(bgname, "2g_%s", cmd->name); + + if ((error = wlu_get(wl, WLC_GET_BAND, &band, sizeof(uint))) < 0) + return error; + band = dtoh32(band); + + if ((error = wlu_get(wl, WLC_GET_BANDLIST, list, sizeof(list))) < 0) + return error; + list[0] = dtoh32(list[0]); + list[1] = dtoh32(list[1]); + list[2] = dtoh32(list[2]); + + if (!list[0]) + return BCME_ERROR; + else if (list[0] > 2) + list[0] = 2; + + /* toss the command name from the args */ + argv++; + + if ((!strcmp(cmd->name, "rate"))) { + /* it is "rate" */ + if (!*argv) { + /* it is "rate" get. handle it here */ + /* WLC_GET_RATE processing */ + if ((error = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0) + return error; + + val = dtoh32(val); + wl_printrate(val); + return 0; + } + } + + switch (band) { + case WLC_BAND_AUTO : + if (list[0] > 1) { + fprintf(stderr, + "%s: driver band must be locked to %s %s, use %s/%s instead\n", + fn_name, (*argv ? "set" : "get"), cmd->name, + bgname, aname); + return BCME_BADARG; + } else if (list[1] == WLC_BAND_5G) + name = (char *)aname; + else if (list[1] == WLC_BAND_2G) + name = (char *)bgname; + else + return BCME_ERROR; + + break; + + case WLC_BAND_5G : + name = (char *)aname; + break; + + case WLC_BAND_2G : + name = (char *)bgname; + break; + + default : + return BCME_ERROR; + } + + if (!*argv) { + /* it is "mrate" get */ + if ((error = wlu_iovar_getint(wl, name, &val) < 0)) + return error; + + val = dtoh32(val); + + if (ioctl_version == 1) { + wl_printrate(val); + } else { + wl_printrate(wl_ratespec2rate((uint32)val)); + } + } else { + /* create the ioctl value based on the major ioctl version */ + if (ioctl_version == 1) { + /* for ver=1 ioctl interfaces, override values for 2g_(m)rate/5g_(m)rate + * are just given as 500 Kbps units + */ + val = rate_string2int(*argv); + } else { + /* for ver>1 ioctl interfaces, override values for 2g_(m)rate/5g_(m)rate + * are a wl_ratespec of a legacy rate. + */ + val = WL_RSPEC_ENCODE_RATE | rate_string2int(*argv); + } + + val = htod32(val); + + error = wlu_iovar_setint(wl, name, val); + } + + return error; +} + +/* parse the -v/--vht or -c argument for the wl_rate() command. + * return FALSE if the arg does not look like MxS or cMsS, where M and S are single digits + * return TRUE if the arg does look like MxS or cMsS, setting mcsp to M, and nssp to S + */ +static int +wl_parse_vht_spec(const char* cp, int* mcsp, int* nssp) +{ + char *startp, *endp; + char c; + int mcs, nss; + char sx; + + if (cp == NULL || cp[0] == '\0') { + return FALSE; + } + + if (cp[0] == 'c') { + startp = (char*)cp + 1; + sx = 's'; + } + else { + startp = (char*)cp; + sx = 'x'; + } + + mcs = (int)strtol(startp, &endp, 10); + /* verify MCS 0-9, and next char is 's' or 'x' */ + if (mcs < 0 || mcs > 9 || endp[0] != sx) { + return FALSE; + } + + /* grab the char after the 'x'/'s' and convert to value */ + c = endp[1]; + nss = 0; + if (isdigit((int)c)) { + nss = c - '0'; + } + + /* consume trailing space after digit */ + cp = &endp[2]; + while (isspace((int)(*cp))) { + cp++; + } + + /* check for trailing garbage after digit */ + if (cp[0] != '\0') { + return FALSE; + } + + if (nss < 1 || nss > 8) { + return FALSE; + } + + *mcsp = mcs; + *nssp = nss; + + return TRUE; +} + +static int +wl_rate(void *wl, cmd_t *cmd, char **argv) +{ + miniopt_t mo; + char *option_name = NULL; + char* endp; + const int option_name_len = 64; + const char* iov_name; + const char* fn_name = "wl_rate"; + bool options = FALSE; + bool auto_set = FALSE; + bool legacy_set = FALSE, ht_set = FALSE, vht_set = FALSE; + int rate, mcs, Nss, tx_exp, bw; + bool stbc, ldpc, sgi; + int err, opt_err; + uint32 rspec = 0; + + /* set default values */ + rate = 0; + mcs = 0; + Nss = 0; + tx_exp = 0; + stbc = FALSE; + ldpc = FALSE; + sgi = FALSE; + bw = 0; + + /* save the command name */ + iov_name = *argv++; + + if (ioctl_version == 1) { + fprintf(stderr, + "cmd %s not supported in this version of the driver, ioctl version 1.\n", + iov_name); + return BCME_USAGE_ERROR; + } + + /* process a GET */ + if (!*argv) { + uint32 val = 0; + char * rate_str; + const int rate_str_len = 64; + + if (cmd->get < 0) + return -1; + if ((err = wlu_iovar_getint(wl, iov_name, (int*)&val)) < 0) + return err; + + rate_str = malloc(rate_str_len); + if (rate_str == NULL) { + fprintf(stderr, "%s: malloc failure for rate string buffer.\n", fn_name); + return BCME_NOMEM; + } + memset(rate_str, 0, rate_str_len); + + wl_rate_print(rate_str, val); + + printf("%s\n", rate_str); + + free(rate_str); + + return 0; + } + + /* process a SET */ + + /* initialze to common error for the miniopt processing */ + err = BCME_USAGE_ERROR; + + /* alloc option name for error messages */ + option_name = malloc(option_name_len); + if (option_name == NULL) { + fprintf(stderr, "%s: malloc failure for option_name buffer.\n", fn_name); + return BCME_NOMEM; + } + memset(option_name, 0, option_name_len); + + miniopt_init(&mo, fn_name, "lg", TRUE); + while ((opt_err = miniopt(&mo, argv)) != -1) { + if (opt_err == 1) { + err = BCME_USAGE_ERROR; + goto exit; + } + argv += mo.consumed; + + /* track whether or not the command line is just a single positional + * parameter of "auto" or a legacy rate, or is using options + */ + if (!mo.positional) { + options = TRUE; /* command line is using options */ + } + if (mo.positional) { + /* command line is using a positional parameter, + * complain if options are also being used + */ + if (options) { + fprintf(stderr, + "%s: cannot mix positional args and options. " + "Got positional arg \"%s\" after options.\n", + fn_name, mo.valstr); + goto exit; + } + /* complain if there are any more parameters since there should only + * be one positional param, "auto" or a legacy rate. + */ + if (*argv != NULL) { + fprintf(stderr, + "%s: unexpected parameter \"%s\" after rate value.\n", + fn_name, *argv); + goto exit; + } + /* test for "auto" to clear the rate override */ + if (!strcmp(mo.valstr, "auto")) { + auto_set = TRUE; + } else { + /* pretend there was a '-r' option */ + mo.opt = 'r'; + } + } + + /* format the option name for error messages */ + if (mo.key[0] != '\0') { + /* would like to do the following, but snprintf() is not availble in + * all target builds. Fails in win_mfgtest_wl build. + * + * snprintf(option_name, option_name_len, "--%s", mo.key); + * option_name[option_name_len - 1] = '\0'; + */ + size_t key_len; + + key_len = strlen(mo.key); + /* limit key_len to space in str buffer minus the '--' and null */ + key_len = MIN((uint)(option_name_len - 3), key_len); + + memcpy(option_name, "--", 2); + memcpy(option_name + 2, mo.key, key_len); + option_name[2 + key_len] = '\0'; + } else { + sprintf(option_name, "-%c", mo.opt); + } + + /* Option: -r or --rate */ + if (mo.opt == 'r' || + !strcmp(mo.key, "rate")) { + if (mo.valstr == NULL) { + fprintf(stderr, + "%s: expected a value for %s option\n", + fn_name, option_name); + goto exit; + } + + /* special case check for "-r 5.5" */ + if (!strcmp(mo.valstr, "5.5")) { + rate = 11; + } else if (!mo.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as a value for %s option\n", + fn_name, mo.valstr, option_name); + goto exit; + } else { + rate = mo.val*2; + } + + legacy_set = TRUE; + } + /* Option: -h or --ht */ + if (mo.opt == 'h' || + !strcmp(mo.key, "ht")) { + if (mo.valstr == NULL) { + fprintf(stderr, + "%s: expected a value for %s option\n", + fn_name, option_name); + goto exit; + } + + if (!mo.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as a value for %s option\n", + fn_name, mo.valstr, option_name); + goto exit; + } + + mcs = mo.val; + ht_set = TRUE; + } + /* Option: -v or --vht */ + if (mo.opt == 'v' || + !strcmp(mo.key, "vht")) { + if (mo.valstr == NULL || mo.valstr[0] == 'c') { + fprintf(stderr, + "%s: expected a value for %s option\n", + fn_name, option_name); + goto exit; + } + + mcs = (int)strtol(mo.valstr, &endp, 10); + if (*endp == '\0') { + mcs = mo.val; + vht_set = TRUE; + } else if (wl_parse_vht_spec(mo.valstr, &mcs, &Nss)) { + vht_set = TRUE; + } else { + fprintf(stderr, + "%s: could not parse \"%s\" as a value for %s option\n", + fn_name, mo.valstr, option_name); + goto exit; + } + } + /* Option: -c (system team's c notiation: c<MCS>s<Nss>) */ + if (mo.opt == 'c') { + if (mo.valstr == NULL || mo.valstr[0] != 'c') { + fprintf(stderr, + "%s: expected a value start with c for %s option\n", + fn_name, option_name); + goto exit; + } + + mcs = (int)strtol(mo.valstr + 1, &endp, 10); + if (*endp == '\0') { + vht_set = TRUE; + } else if (wl_parse_vht_spec(mo.valstr, &mcs, &Nss)) { + vht_set = TRUE; + } else { + fprintf(stderr, + "%s: could not parse \"%s\" as a value for %s option\n", + fn_name, mo.valstr, option_name); + goto exit; + } + } + /* Option: -s or --ss */ + if (mo.opt == 's' || + !strcmp(mo.key, "ss")) { + if (mo.valstr == NULL) { + fprintf(stderr, + "%s: expected a value for %s option\n", + fn_name, option_name); + goto exit; + } + + if (!mo.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as a value for %s option\n", + fn_name, mo.valstr, option_name); + goto exit; + } + Nss = mo.val; + } + /* Option: -x or --exp */ + if (mo.opt == 'x' || + !strcmp(mo.key, "exp")) { + if (mo.valstr == NULL) { + fprintf(stderr, + "%s: expected a value for %s option\n", + fn_name, option_name); + goto exit; + } + + if (!mo.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as a value for %s option\n", + fn_name, mo.valstr, option_name); + goto exit; + } + tx_exp = mo.val; + if (tx_exp < 0 || tx_exp > 3) { + fprintf(stderr, + "%s: tx expansion %d out of range [0-3]\n", + fn_name, tx_exp); + err = BCME_RANGE; + goto exit; + } + } + /* Option: --stbc */ + if (!strcmp(mo.key, "stbc")) { + if (mo.valstr != NULL) { + fprintf(stderr, + "%s: unexpected a value for %s option\n", + fn_name, option_name); + goto exit; + } + stbc = TRUE; + } + /* Option: -l or --ldpc */ + if (mo.opt == 'l' || + !strcmp(mo.key, "ldpc")) { + if (mo.valstr != NULL) { + fprintf(stderr, + "%s: unexpected a value for %s option\n", + fn_name, option_name); + goto exit; + } + ldpc = TRUE; + } + /* Option: -g or --sgi */ + if (mo.opt == 'g' || + !strcmp(mo.key, "sgi")) { + if (mo.valstr != NULL) { + fprintf(stderr, + "%s: unexpected a value for %s option\n", + fn_name, option_name); + goto exit; + } + sgi = TRUE; + } + /* Option: -b or --bandwidth */ + if (mo.opt == 'b' || + !strcmp(mo.key, "bandwidth")) { + if (mo.valstr == NULL) { + fprintf(stderr, + "%s: expected a value for %s option\n", + fn_name, option_name); + goto exit; + } + + if (!mo.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as a value for %s option\n", + fn_name, mo.valstr, option_name); + goto exit; + } + if (mo.val == 20) { + bw = WL_RSPEC_BW_20MHZ; + } else if (mo.val == 40) { + bw = WL_RSPEC_BW_40MHZ; + } else if (mo.val == 80) { + bw = WL_RSPEC_BW_80MHZ; + } else if (mo.val == 160) { + bw = WL_RSPEC_BW_160MHZ; + } else { + fprintf(stderr, + "%s: unexpected bandwidth specified \"%s\", " + "expected 20, 40, 80, or 160\n", + fn_name, mo.valstr); + goto exit; + } + } + } + + /* + * check for necessary use of one of -r/-h/-v or auto + */ + + if (!auto_set && !legacy_set && !ht_set && !vht_set) { + fprintf(stderr, "%s: must specify one of \"auto\", legacy rate -r/--rate, " + "HT (11n) rate -h/--ht, or VHT (11ac) rate -v/--vht\n", + fn_name); + goto exit; + } + + /* + * check for incompatible use of -r/-h/-v + */ + + if (legacy_set && ht_set) { + fprintf(stderr, "%s: cannot use legacy rate -r/--rate and " + "HT rate -h/--ht at the same time\n", + fn_name); + goto exit; + } + + if (legacy_set && vht_set) { + fprintf(stderr, "%s: cannot use legacy rate -r/--rate and " + "HT rate -v/--vht at the same time\n", + fn_name); + goto exit; + } + + if (ht_set && vht_set) { + fprintf(stderr, "%s: cannot use HT rate -h/--ht and " + "HT rate -v/--vht at the same time\n", + fn_name); + goto exit; + } + + /* Nss can only be used with VHT */ + if (!vht_set && Nss != 0) { + fprintf(stderr, "%s: cannot use -s/--ss option with non VHT rate\n", + fn_name); + goto exit; + } + + /* STBC, LDPC, SGI can only be used with HT/VHT rates */ + if ((stbc || ldpc || sgi) && !(ht_set || vht_set)) { + fprintf(stderr, "%s: cannot use STBC/LDPC/SGI options with non HT/VHT rates\n", + fn_name); + goto exit; + } + + /* set the ratespec encoding type and basic rate value */ + if (auto_set) { + rspec = 0; + } else if (legacy_set) { + rspec = WL_RSPEC_ENCODE_RATE; /* 11abg */ + rspec |= rate; + } else if (ht_set) { + rspec = WL_RSPEC_ENCODE_HT; /* 11n HT */ + rspec |= mcs; + } else { + rspec = WL_RSPEC_ENCODE_VHT; /* 11ac VHT */ + if (Nss == 0) { + Nss = 1; /* default Nss = 1 if --ss option not given */ + } + rspec |= (Nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs; + } + + /* set the other rspec fields */ + rspec |= (tx_exp << WL_RSPEC_TXEXP_SHIFT); + rspec |= bw; + rspec |= (stbc ? WL_RSPEC_STBC : 0); + rspec |= (ldpc ? WL_RSPEC_LDPC : 0); + rspec |= (sgi ? WL_RSPEC_SGI : 0); + + err = wlu_iovar_setint(wl, iov_name, (int)rspec); + +exit: + if (option_name != NULL) { + free(option_name); + } + + return err; +} + +static int +wl_wepstatus(void *wl, cmd_t *cmd, char **argv) +{ + int val, error; + const char *name = "wsec"; + int wsec; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) { + if ((error = wlu_iovar_getint(wl, name, &val) < 0)) + return error; + + printf("%d\n", val); + return 0; + } else { + val = atoi(*argv); + if ((error = wlu_iovar_getint(wl, name, &wsec) < 0)) + return error; + + if (val) + wsec |= WEP_ENABLED; + else + wsec &= ~WEP_ENABLED; + + return wlu_iovar_setint(wl, name, wsec); + } +} + +static int +wl_bss_max(void *wl, cmd_t *cmd, char **argv) +{ + int val = 1; + int error; + + UNUSED_PARAMETER(argv); + + /* Get the CAP variable; search for mbss4 or mbss16 */ + strcpy(buf, "cap"); + if ((error = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MEDLEN)) < 0) + return (error); + + buf[WLC_IOCTL_MEDLEN] = '\0'; + if (strstr(buf, "mbss16")) + val = 16; + else if (strstr(buf, "mbss4")) + val = 4; + + printf("%d\n", val); + return (0); +} + +static int +wl_phy_rate(void *wl, cmd_t *cmd, char **argv) +{ + int val, error; + const char *name = cmd->name; + static const struct { + const char* orig; + const char* new; + } aliases[] = { + {"bg_rate", "2g_rate"}, + {"bg_mrate", "2g_mrate"}, + {"a_rate", "5g_rate"}, + {"a_mrate", "5g_mrate"}, + }; + + /* toss the command name from the args */ + argv++; + + /* if we are not using the legacy ioctl driver, translate the + * bg_* prefix to 2g_* and a_* to 5g_* iovars + */ + if (ioctl_version > 1) { + int i; + for (i = 0; i < 4; i++) { + if (!strcmp(name, aliases[i].orig)) { + name = aliases[i].new; + break; + } + } + } + + if (!*argv) { + error = wlu_iovar_getint(wl, name, &val); + if (error < 0) + return (error); + + val = dtoh32(val); + if (ioctl_version > 1) { + wl_printrate(wl_ratespec2rate((uint32)val)); + } else { + wl_printrate(val); + } + } else { + /* create the ioctl value based on the major ioctl version */ + if (ioctl_version == 1) { + /* for ver=1 ioctl interfaces, override values for 2g_(m)rate/5g_(m)rate + * are just given as 500 Kbps units + */ + val = rate_string2int(*argv); + } else { + /* for ver>1 ioctl interfaces, override values for 2g_(m)rate/5g_(m)rate + * are a wl_ratespec of a legacy rate. + */ + val = WL_RSPEC_ENCODE_RATE | rate_string2int(*argv); + } + + + val = htod32(val); + error = wlu_iovar_setint(wl, name, val); + } + + return error; +} + +static int +wl_nrate(void *wl, cmd_t *cmd, char **argv) +{ + miniopt_t to; + const char* fn_name = "wl_nrate"; + bool mcs_set = FALSE, legacy_set = FALSE, stf_set = FALSE; + bool mcs_only = FALSE; + int err, opt_err; + uint32 val = 0; + uint32 rate = 0; + uint32 nrate = 0; + uint32 mcs = 0; + uint stf = 0; + + /* toss the command name */ + argv++; + + if (!*argv) { + if (cmd->get < 0) + return -1; + if ((err = wlu_iovar_getint(wl, "nrate", (int*)&val)) < 0) + return err; + + /* print a user readable line for the nrate rspec */ + wl_nrate_print(val); + + return 0; + } + + /* check for a single argument of "auto" or -1 */ + if ((!strcmp(argv[0], "auto") || !strcmp(argv[0], "-1")) && + argv[1] == NULL) { + /* clear the nrate override */ + err = wlu_iovar_setint(wl, "nrate", 0); + goto exit; + } + + miniopt_init(&to, fn_name, "w", FALSE); + while ((opt_err = miniopt(&to, argv)) != -1) { + if (opt_err == 1) { + err = BCME_USAGE_ERROR; + goto exit; + } + argv += to.consumed; + + if (to.opt == 'r') { + if (!to.good_int) { + /* special case check for "-r 5.5" */ + if (!strcmp(to.valstr, "5.5")) { + to.val = 11; + } else { + fprintf(stderr, + "%s: could not parse \"%s\" as a rate value\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + } else + to.val = to.val*2; + if (mcs_set) { + fprintf(stderr, "%s: cannot use -r and -m\n", fn_name); + err = BCME_USAGE_ERROR; + goto exit; + } + + legacy_set = TRUE; + rate = to.val; + } + if (to.opt == 'm') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for mcs\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if (legacy_set) { + fprintf(stderr, "%s: cannot use -r and -m\n", fn_name); + err = BCME_USAGE_ERROR; + goto exit; + } + mcs_set = TRUE; + mcs = to.val; + } + if (to.opt == 's') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for stf mode\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + stf = to.val; + stf_set = TRUE; + } + if (to.opt == 'w') { + mcs_only = TRUE; + } + } + + if ((mcs_only && !mcs_set) || (mcs_only && (stf_set || legacy_set))) { + fprintf(stderr, "%s: can use -w only with -m\n", fn_name); + err = BCME_USAGE_ERROR; + goto exit; + } + + if (!stf_set) { + if (legacy_set) + stf = OLD_NRATE_STF_SISO; /* SISO */ + else if (mcs_set) { + if ((nrate & OLD_NRATE_RATE_MASK) <= HIGHEST_SINGLE_STREAM_MCS || + (nrate & OLD_NRATE_RATE_MASK) == 32) + stf = OLD_NRATE_STF_SISO; /* SISO */ + else + stf = OLD_NRATE_STF_SDM; /* SDM */ + } + } + + if (!legacy_set && !mcs_set) { + fprintf(stderr, "%s: you need to set a legacy or mcs rate\n", fn_name); + err = BCME_USAGE_ERROR; + goto exit; + } + + if (ioctl_version == 1) { + if (legacy_set) { + nrate = rate; + } else { + nrate = mcs; + nrate |= OLD_NRATE_MCS_INUSE; + if (mcs_only) { + nrate |= OLD_NRATE_OVERRIDE_MCS_ONLY; + } + } + + nrate |= (stf << OLD_NRATE_STF_SHIFT) & OLD_NRATE_STF_MASK; + } else { + uint tx_exp = 0; + + /* set the ratespec encoding type and basic rate value */ + if (legacy_set) { + nrate = WL_RSPEC_ENCODE_RATE; /* 11abg */ + nrate |= rate; + } else { + nrate = WL_RSPEC_ENCODE_HT; /* 11n HT */ + nrate |= mcs; + } + + /* decode nrate stf value into tx expansion and STBC */ + if (stf == OLD_NRATE_STF_CDD) { + tx_exp = 1; + } else if (stf == OLD_NRATE_STF_STBC) { + nrate |= WL_RSPEC_STBC; + } + + nrate |= (tx_exp << WL_RSPEC_TXEXP_SHIFT); + } + + err = wlu_iovar_setint(wl, "nrate", (int)nrate); + +exit: + return err; +} + +static int +wl_assoc_info(void *wl, cmd_t *cmd, char **argv) +{ + uint i, req_ies_len = 0, resp_ies_len = 0; + wl_assoc_info_t assoc_info; + int ret; + uint8 *pbuf; + + UNUSED_PARAMETER(argv); + + /* get the generic association information */ + strcpy(buf, cmd->name); + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0) + return ret; + + memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t)); + assoc_info.req_len = htod32(assoc_info.req_len); + assoc_info.resp_len = htod32(assoc_info.resp_len); + assoc_info.flags = htod32(assoc_info.flags); + + printf("Assoc req:\n"); + printf("\tlen 0x%x\n", assoc_info.req_len); + if (assoc_info.req_len) { + printf("\tcapab 0x%x\n", ltoh16(assoc_info.req.capability)); + printf("\tlisten 0x%x\n", ltoh16(assoc_info.req.listen)); + req_ies_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { + printf("\treassoc bssid %s\n", + wl_ether_etoa(&assoc_info.reassoc_bssid)); + req_ies_len -= ETHER_ADDR_LEN; + } + } + + /* get the association req IE's if there are any */ + if (req_ies_len) { + strcpy(buf, "assoc_req_ies"); + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0) + return ret; + + printf("assoc req IEs:\n\t"); + for (i = 1, pbuf = (uint8*)buf; i <= req_ies_len; i++) { + printf("0x%02x ", *pbuf++); + if (!(i%8)) + printf("\n\t"); + } + } + + printf("\nAssoc resp:\n"); + printf("\tlen 0x%x\n", assoc_info.resp_len); + if (assoc_info.resp_len) { + printf("\tcapab 0x%x\n", ltoh16(assoc_info.resp.capability)); + printf("\tstatus 0x%x\n", ltoh16(assoc_info.resp.status)); + printf("\taid 0x%x\n", ltoh16(assoc_info.resp.aid)); + resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + } + + /* get the association resp IE's if there are any */ + if (resp_ies_len) { + strcpy(buf, "assoc_resp_ies"); + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0) + return ret; + + printf("assoc resp IEs:\n\t"); + for (i = 1, pbuf = (uint8*)buf; i <= resp_ies_len; i++) { + printf(" 0x%02x ", *pbuf++); + if (!(i%8)) + printf("\n\t"); + + } + } + printf("\n"); + + return 0; +} + +static void dump_management_fields(uint8 *data, int len) +{ + int i, tag_len; + uint8 tag; + char temp[64]; + uint8 *p; + + while (len > 0) { + /* Get the tag */ + tag = *data; + data++; len--; + + /* Get the tag length */ + tag_len = (int) *data; + data++; len--; + + printf("Tag:%d Len:%d - ", tag, tag_len); + + switch (tag) { + case DOT11_MNG_SSID_ID: + for (i = 0; i < tag_len; i++) { + temp[i] = data[i]; + } + if (i < 64) { + temp[i] = '\0'; + } + printf("SSID: '%s'\n", temp); + break; + case DOT11_MNG_FH_PARMS_ID: + printf("FH Parameter Set\n"); + break; + case DOT11_MNG_DS_PARMS_ID: + printf("DS Parameter Set\n"); + break; + case DOT11_MNG_CF_PARMS_ID: + printf("CF Parameter Set\n"); + break; + case DOT11_MNG_RATES_ID: + printf("Supported Rates\n"); + break; + case DOT11_MNG_TIM_ID: + printf("Traffic Indication Map (TIM)\n"); + break; + case DOT11_MNG_IBSS_PARMS_ID: + printf("IBSS Parameter Set\n"); + break; + case DOT11_MNG_COUNTRY_ID: + p = data; + printf("Country '%c%c%c'\n", + data[0], data[1], data[2]); + p += DOT11_MNG_COUNTRY_ID_LEN; + while (((data+tag_len) - p) >= DOT11_MNG_COUNTRY_ID_LEN) { + printf("Start Channel: %d, Channels: %d, " + "Max TX Power: %d dBm\n", + p[0], p[1], p[2]); + p += DOT11_MNG_COUNTRY_ID_LEN; + } + break; + case DOT11_MNG_HOPPING_PARMS_ID: + printf("Hopping Pattern Parameters\n"); + break; + case DOT11_MNG_HOPPING_TABLE_ID: + printf("Hopping Pattern Table\n"); + break; + case DOT11_MNG_REQUEST_ID: + printf("Request\n"); + break; + case DOT11_MNG_QBSS_LOAD_ID: + printf("QBSS Load\n"); + break; + case DOT11_MNG_EDCA_PARAM_ID: + printf("EDCA Parameter\n"); + break; + case DOT11_MNG_CHALLENGE_ID: + printf("Challenge text\n"); + break; + case DOT11_MNG_PWR_CONSTRAINT_ID: + printf("Power Constraint\n"); + break; + case DOT11_MNG_PWR_CAP_ID: + printf("Power Capability\n"); + break; + case DOT11_MNG_TPC_REQUEST_ID: + printf("Transmit Power Control (TPC) Request\n"); + break; + case DOT11_MNG_TPC_REPORT_ID: + printf("Transmit Power Control (TPC) Report\n"); + break; + case DOT11_MNG_SUPP_CHANNELS_ID: + printf("Supported Channels\n"); + break; + case DOT11_MNG_CHANNEL_SWITCH_ID: + printf("Channel Switch Announcement\n"); + break; + case DOT11_MNG_MEASURE_REQUEST_ID: + printf("Measurement Request\n"); + break; + case DOT11_MNG_MEASURE_REPORT_ID: + printf("Measurement Report\n"); + break; + case DOT11_MNG_QUIET_ID: + printf("Quiet\n"); + break; + case DOT11_MNG_IBSS_DFS_ID: + printf("IBSS DFS\n"); + break; + case DOT11_MNG_ERP_ID: + printf("ERP Information\n"); + break; + case DOT11_MNG_TS_DELAY_ID: + printf("TS Delay\n"); + break; + case DOT11_MNG_HT_CAP: + printf("HT Capabilities\n"); + break; + case DOT11_MNG_QOS_CAP_ID: + printf("QoS Capability\n"); + break; + case DOT11_MNG_NONERP_ID: + printf("NON-ERP\n"); + break; + case DOT11_MNG_RSN_ID: + printf("RSN\n"); + break; + case DOT11_MNG_EXT_RATES_ID: + printf("Extended Supported Rates\n"); + break; + case DOT11_MNG_AP_CHREP_ID: + printf("AP Channel Report\n"); + break; + case DOT11_MNG_NEIGHBOR_REP_ID: + printf("Neighbor Report\n"); + break; + case DOT11_MNG_MDIE_ID: + printf("Mobility Domain\n"); + break; + case DOT11_MNG_FTIE_ID: + printf("Fast BSS Transition\n"); + break; + case DOT11_MNG_FT_TI_ID: + printf("802.11R Timeout Interval\n"); + break; + case DOT11_MNG_REGCLASS_ID: + printf("Regulatory Class\n"); + break; + case DOT11_MNG_EXT_CSA_ID: + printf("Extended CSA\n"); + break; + case DOT11_MNG_HT_ADD: + printf("HT Information\n"); + break; + case DOT11_MNG_EXT_CHANNEL_OFFSET: + printf("Ext Channel\n"); + break; +#ifdef BCMWAPI_WAI + case DOT11_MNG_WAPI_ID: + printf("WAPI\n"); + break; +#endif + case DOT11_MNG_RRM_CAP_ID: + printf("Radio Measurement\n"); + break; + case DOT11_MNG_HT_BSS_COEXINFO_ID: + printf("OBSS Coexistence INFO\n"); + break; + case DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID: + printf("OBSS Intolerant Channel List\n"); + break; + case DOT11_MNG_HT_OBSS_ID: + printf("OBSS HT Info\n"); + break; +#ifdef DOT11_MNG_CHANNEL_USAGE + case DOT11_MNG_CHANNEL_USAGE: + printf("Channel Usage\n"); + break; +#endif + case DOT11_MNG_LINK_IDENTIFIER_ID: + printf("TDLS Link Identifier\n"); + break; + case DOT11_MNG_WAKEUP_SCHEDULE_ID: + printf("TDLS Wakeup Schedule\n"); + break; + case DOT11_MNG_CHANNEL_SWITCH_TIMING_ID: + printf("TDLS Channel Switch Timing\n"); + break; + case DOT11_MNG_PTI_CONTROL_ID: + printf("TDLS PTI Control\n"); + break; + case DOT11_MNG_PU_BUFFER_STATUS_ID: + printf("TDLS PU Buffer Status\n"); + break; + case DOT11_MNG_EXT_CAP_ID: + printf("Management Ext Capability\n"); + break; + case DOT11_MNG_PROPR_ID: + printf("Proprietary\n"); + break; + default: + if (tag_len <= len) { + printf("Unsupported tag\n"); + } else { + /* Just dump the remaining data */ + printf("Unsupported tag error/malformed\n"); + tag_len = len; + } + break; + } /* switch */ + + wl_hexdump(data, tag_len); + + data += tag_len; + len -= tag_len; + } /* while */ +} + +static void dump_management_info(uint8 *data, int len) +{ + struct dot11_management_header hdr; + struct dot11_bcn_prb parms; + + if (len <= (int) (sizeof(hdr)+sizeof(parms))) { + /* Management packet invalid */ + return; + } + + memcpy(&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + + memcpy(&parms, data, sizeof(parms)); + data += sizeof(parms); + len -= sizeof(parms); + + /* 802.11 MAC header */ + printf("Frame Ctl: 0x%04x\n", ltoh16(hdr.fc)); + printf("Duration : 0x%04x\n", ltoh16(hdr.durid)); + printf("Dest addr: %02x:%02x:%02x:%02x:%02x:%02x\n", + hdr.da.octet[0], + hdr.da.octet[1], + hdr.da.octet[2], + hdr.da.octet[3], + hdr.da.octet[4], + hdr.da.octet[5]); + printf("Src addr : %02x:%02x:%02x:%02x:%02x:%02x\n", + hdr.sa.octet[0], + hdr.sa.octet[1], + hdr.sa.octet[2], + hdr.sa.octet[3], + hdr.sa.octet[4], + hdr.sa.octet[5]); + printf("BSSID : %02x:%02x:%02x:%02x:%02x:%02x\n", + hdr.bssid.octet[0], + hdr.bssid.octet[1], + hdr.bssid.octet[2], + hdr.bssid.octet[3], + hdr.bssid.octet[4], + hdr.bssid.octet[5]); + printf("Seq ctl : 0x%04x\n", hdr.seq); + + /* 802.11 management frame */ + printf("Timestamp: 0x%08x%08x\n", + ltoh32(parms.timestamp[0]), ltoh32(parms.timestamp[1])); + printf("Beacon Interval: 0x%04x\n", ltoh16(parms.beacon_interval)); + printf("Capabilities: 0x%04x\n", ltoh32(parms.capability)); + + dump_management_fields(data, len); +} + +static int +wl_management_info(void *wl, cmd_t *cmd, char**argv) +{ + int ret = 0; + int len; + uint8 *data; + FILE *fp = NULL; + char *fname = NULL; + int raw = 0; + + /* Skip the command name */ + argv++; + + while (*argv) { + char *s = *argv; + + if (!strcmp(s, "-f") && argv[1] != NULL) { + /* Write packet to a file */ + fname = argv[1]; + argv += 2; + } else if (!strcmp(s, "-r")) { + /* Do a hex dump to console */ + raw = 1; + argv++; + } else + return BCME_USAGE_ERROR; + } + + /* Get the beacon information */ + strcpy(buf, cmd->name); + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return ret; + + /* + * Dump out the beacon data. The first word (4 bytes) is the + * length of the management packet followed by the data itself. + */ + len = dtoh32(*(int *)buf); + + if (len <= 0) { + /* Nothing to do */ + return ret; + } + + data = (uint8 *) (buf + sizeof(int)); + printf("Data: %p Len: %d bytes\n", data, len); + + if (fname != NULL) { + /* Write the packet to a file */ + if ((fp = fopen(fname, "wb")) == NULL) { + fprintf(stderr, "Failed to open file %s\n", + fname); + ret = BCME_BADARG; + } else { + ret = fwrite(data, 1, len, fp); + + if (ret != len) { + fprintf(stderr, + "Error write %d bytes to file %s, rc %d!\n", + len, fname, ret); + ret = -1; + } + } + } else if (raw) { + /* Hex dump */ + wl_hexdump(data, len); + } else { + /* Print management (w/some decode) */ + dump_management_info(data, len); + } + + if (fp) + fclose(fp); + + return ret; +} + +static int +wl_pmkid_info(void *wl, cmd_t *cmd, char**argv) +{ + int i, j, ret; + pmkid_list_t *pmkid_info; + + if (!*++argv) { + strcpy(buf, cmd->name); + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_SMLEN)) < 0) + return ret; + + pmkid_info = (pmkid_list_t *)buf; + pmkid_info->npmkid = dtoh32(pmkid_info->npmkid); + printf("\npmkid entries : %d\n", pmkid_info->npmkid); + + for (i = 0; i < (int)pmkid_info->npmkid; i++) { + printf("\tPMKID[%d]: %s =", + i, wl_ether_etoa(&pmkid_info->pmkid[i].BSSID)); + for (j = 0; j < WPA2_PMKID_LEN; j++) + printf("%02x ", pmkid_info->pmkid[i].PMKID[j]); + printf("\n"); + } + } + else { +#ifdef test_pmkid_info + char eaddr[6] = {0x0, 0x0, 0x1, 0x2, 0x3, 0x5}; + char eaddr1[6] = {0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; + char id[WPA2_PMKID_LEN], id1[WPA2_PMKID_LEN]; + int i, len = (sizeof(uint32) + 2*(sizeof(pmkid_t))); + + /* check that the set uses to "test" cmd */ + if (strcmp(*argv, "test")) { + printf("\t wl pmkid_info only supports `test` a test specific set\n"); + return BCME_USAGE_ERROR; + } + if ((pmkid_info = (pmkid_list_t *)malloc(len)) == NULL) { + printf("\tfailed to allocate buffer\n"); + return BCME_NOMEM; + } + + printf("\toverwriting pmkid table with test pattern\n"); + for (i = 0; i < (int)sizeof(id); i++) { + id[i] = i; + id1[i] = (i*2); + } + + /* "test" - creates two PMKID entries and sets the table to that */ + pmkid_info->npmkid = htod32(2); + memcpy(&pmkid_info->pmkid[0].BSSID.octet[0], &eaddr[0], ETHER_ADDR_LEN); + memcpy(&pmkid_info->pmkid[0].PMKID[0], &id[0], WPA2_PMKID_LEN); + memcpy(&pmkid_info->pmkid[1].BSSID.octet[0], &eaddr1[0], ETHER_ADDR_LEN); + memcpy(&pmkid_info->pmkid[1].PMKID[0], &id1[0], WPA2_PMKID_LEN); + + ret = wlu_var_setbuf(wl, cmd->name, pmkid_info, len); + + free(pmkid_info); + + return ret; +#else + printf("\tset cmd ignored\n"); +#endif /* test_pmkid_info */ + } + + return 0; +} + +static int +wl_rateset(void *wl, cmd_t *cmd, char **argv) +{ + wl_rateset_args_t rs, defrs; + int error; + uint i; + + UNUSED_PARAMETER(cmd); + + error = 0; + + argv++; + + if (*argv == NULL) { + /* get current rateset */ + if ((error = wlu_iovar_get(wl, "cur_rateset", &rs, sizeof(rs))) < 0) + return (error); + + dump_rateset(rs.rates, dtoh32(rs.count)); + printf("\n"); + wl_print_mcsset((char *)rs.mcs); + wl_print_vhtmcsset((uint16 *)rs.vht_mcs); + } else { + /* get default rateset and mcsset */ + if ((error = wlu_iovar_get(wl, "rateset", &defrs, + sizeof(wl_rateset_args_t))) < 0) + return (error); + defrs.count = dtoh32(defrs.count); + + if (!stricmp(*argv, "all")) { + for (i = 0; i < defrs.count; i++) + defrs.rates[i] |= 0x80; + defrs.count = htod32(defrs.count); + error = wlu_iovar_set(wl, "rateset", &defrs, + sizeof(wl_rateset_args_t)); + } + else if (!stricmp(*argv, "default")) { + defrs.count = htod32(defrs.count); + error = wlu_iovar_set(wl, "rateset", &defrs, + sizeof(wl_rateset_args_t)); + } + else { /* arbitrary list */ + error = wl_parse_rateset(wl, &defrs, argv); + if (!error) { + + /* check for common error of no basic rates */ + for (i = 0; i < defrs.count; i++) { + if (defrs.rates[i] & 0x80) + break; + } + if (i < defrs.count) { + defrs.count = htod32(defrs.count); + error = wlu_iovar_set(wl, "rateset", &defrs, + sizeof(wl_rateset_args_t)); + } else { + error = BCME_BADARG; + fprintf(stderr, + "Bad Args: at least one rate must be marked Basic\n"); + } + } + } + + } + return (error); +} + +static int +wl_default_rateset(void *wl, cmd_t *cmd, char **argv) +{ + int error = 0; + wl_rates_info_t rates_info; + + UNUSED_PARAMETER(cmd); + + memset((char*)&rates_info.rs_tgt, 0, sizeof(wl_rateset_t)); + + argv++; + /* not enough params */ + if (*argv == NULL) { + fprintf(stderr, "Can't parse phy type\n"); + return BCME_USAGE_ERROR; + } + + /* phy_type */ + if (!stricmp(*argv, "a")) + rates_info.phy_type = 0; + else if (!stricmp(*argv, "b")) + rates_info.phy_type = 2; + else if (!stricmp(*argv, "g")) + rates_info.phy_type = 2; + else if (!stricmp(*argv, "n")) + rates_info.phy_type = 4; + else if (!stricmp(*argv, "lp")) + rates_info.phy_type = 5; + else if (!stricmp(*argv, "ssn")) + rates_info.phy_type = 6; + else if (!stricmp(*argv, "ht")) + rates_info.phy_type = 7; + else if (!stricmp(*argv, "lcn")) + rates_info.phy_type = 8; + else if (!stricmp(*argv, "lcn40")) + rates_info.phy_type = 10; + else if (!stricmp(*argv, "ac")) + rates_info.phy_type = 11; + else { + fprintf(stderr, "Wrong phy type: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + argv++; + /* not enough params */ + if (*argv == NULL) { + fprintf(stderr, "Can't parse band type\n"); + return BCME_USAGE_ERROR; + } + + /* band type */ + if (!stricmp(*argv, "5")) + rates_info.bandtype = WLC_BAND_5G; + else if (!stricmp(*argv, "2")) + rates_info.bandtype = WLC_BAND_2G; + else { + fprintf(stderr, "Wrong band type: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + argv++; + /* not enough params */ + if (*argv == NULL) { + fprintf(stderr, "Can't parse cck\n"); + return BCME_USAGE_ERROR; + } + + /* cck only */ + if (!stricmp(*argv, "0")) + rates_info.cck_only = FALSE; + else if (!stricmp(*argv, "1")) + rates_info.cck_only = TRUE; + else { + fprintf(stderr, "Wrong cck: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + argv++; + /* not enough params */ + if (*argv == NULL) { + fprintf(stderr, "Can't parse basic rates\n"); + return BCME_USAGE_ERROR; + } + + /* rate_mask */ + if (!stricmp(*argv, "0")) + rates_info.rate_mask = 0x7f; + else if (!stricmp(*argv, "1")) + rates_info.rate_mask = 0xff; + else { + fprintf(stderr, "Wrong basic rates: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + argv++; + /* not enough params */ + if (*argv == NULL) { + fprintf(stderr, "Can't parse mcs\n"); + return BCME_USAGE_ERROR; + } + + /* mcs */ + if (!stricmp(*argv, "0")) + rates_info.mcsallow = FALSE; + else if (!stricmp(*argv, "1")) + rates_info.mcsallow = TRUE; + else { + fprintf(stderr, "Wrong mcs: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + argv++; + /* not enough params */ + if (*argv == NULL) { + fprintf(stderr, "Can't parse bandwidth\n"); + return BCME_USAGE_ERROR; + } + + /* channel bandwidth */ + if (!stricmp(*argv, "10")) + rates_info.bw = 10; + else if (!stricmp(*argv, "20")) + rates_info.bw = 20; + else if (!stricmp(*argv, "40")) + rates_info.bw = 40; + else if (!stricmp(*argv, "80")) + rates_info.bw = 80; + else if (!stricmp(*argv, "160")) + rates_info.bw = 160; + else { + fprintf(stderr, "Wrong bandwidth: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + argv++; + /* not enough params */ + if (*argv == NULL) { + fprintf(stderr, "Can't parse tx/rx streams\n"); + return BCME_USAGE_ERROR; + } + + /* mcs */ + if (!stricmp(*argv, "tx")) { + int txstreams; + if ((error = wlu_iovar_getint(wl, "txstreams", &txstreams)) < 0) { + fprintf(stderr, "Can't get tx streams\n"); + return BCME_USAGE_ERROR; + } + rates_info.txstreams = txstreams; + } + else if (!stricmp(*argv, "rx")) { + int rxstreams; + if ((error = wlu_iovar_getint(wl, "rxstreams", &rxstreams)) < 0) { + fprintf(stderr, "Can't get rx streams\n"); + return BCME_USAGE_ERROR; + } + rates_info.txstreams = rxstreams; + } + else { + fprintf(stderr, "Wrong tx/rx streams: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + /* get default rates */ + if ((error = wlu_iovar_getbuf(wl, "default_rateset", NULL, 0, &rates_info, + sizeof(wl_rates_info_t)))) { + fprintf(stderr, "default_rateset failed\n"); + return (error); + } + + dump_rateset(rates_info.rs_tgt.rates, dtoh32(rates_info.rs_tgt.count)); + + return (error); +} + +static int +wl_sup_rateset(void *wl, cmd_t *cmd, char **argv) +{ + wl_rateset_args_t rs; + bool got_basic; + int error; + uint i; + + error = 0; + memset((char*)&rs, 0, sizeof(wl_rateset_args_t)); + + argv++; + + if (*argv == NULL) { + /* get rateset */ + if ((error = wlu_get(wl, cmd->get, &rs, sizeof(wl_rateset_t))) < 0) + return (error); + + dump_rateset(rs.rates, dtoh32(rs.count)); + printf("\n"); + } else { + if (!stricmp(*argv, "-1") || !stricmp(*argv, "0")) { + /* set an empty rateset */ + error = wlu_set(wl, cmd->set, &rs, sizeof(wl_rateset_t)); + } + else { /* set the specified rateset */ + wl_parse_rateset(wl, &rs, argv); + /* check for common error of including a basic rate */ + got_basic = FALSE; + for (i = 0; i < rs.count; i++) { + if (rs.rates[i] & 0x80) { + rs.rates[i] &= 0x7F; + got_basic = TRUE; + } + } + if (got_basic) { + fprintf(stderr, + "Warning: Basic rate attribute ignored for \"%s\" command\n", + cmd->name); + } + rs.count = htod32(rs.count); + error = wlu_set(wl, cmd->set, &rs, sizeof(wl_rateset_t)); + } + + } + return (error); +} + +/* + * Parse the rateset command arguments into the passed wl_rateset_args_t structure. + * + * Returns 0 on success, or an appropriate error code (BCME_USAGE_ERROR, BCME_BADARG). + * + */ +static int +wl_parse_rateset(void *wl, wl_rateset_args_t* rs, char **argv) +{ + char* endp = NULL; + char* arg; + int r; + int mcs_index = 0; + uint32 mcs_mask; + int error = 0; + wl_rateset_args_t cur_rs; + bool mcs_args, vht_args; + + mcs_args = vht_args = FALSE; + + memset(rs, 0, sizeof(*rs)); + + while ((arg = *argv++) != NULL) { + /* mcs rates */ + if (!stricmp(arg, "-m")) { + mcs_args = TRUE; + break; + } + + /* vht rates */ + if (!stricmp(arg, "-v")) { + vht_args = TRUE; + break; + } + + /* Parse legacy rates */ + + if (rs->count >= WL_MAXRATES_IN_SET) { + fprintf(stderr, + "parsing \"%s\", too many rates specified, max is %d rates\n", + arg, WL_MAXRATES_IN_SET); + error = BCME_USAGE_ERROR; + break; + } + + /* convert the rate number to a 500kbps rate by multiplying by 2 */ + r = (int)(strtoul(arg, &endp, 0) * 2); + if (endp == arg) { + fprintf(stderr, "unable to convert the rate parameter \"%s\"\n", arg); + error = BCME_USAGE_ERROR; + break; + } + + /* parse a .5 specially */ + if (!strncmp(endp, ".5", 2)) { + r += 1; + endp += 2; + } + + /* strip trailing space */ + while (isspace((int)endp[0])) + endp++; + + /* check for a basic rate specifier */ + if (!stricmp(endp, "b") || !stricmp(endp, "(b)")) { + r |= 0x80; + } else if (endp[0] != '\0') { + fprintf(stderr, + "unable to convert trailing characters" + " \"%s\" in the rate parameter \"%s\"\n", + endp, arg); + error = BCME_USAGE_ERROR; + break; + } + + /* no legacy rates specified */ + if ((rs->count == 0) && (r == 0)) { + fprintf(stderr, "empty legacy rateset not supported\n"); + error = BCME_USAGE_ERROR; + break; + } + + rs->rates[rs->count++] = r; + } + + if (error) + return error; + + if (!mcs_args && !vht_args && !rs->count) + return BCME_USAGE_ERROR; /* Cannot happen, really */ + + /* + * If one of the rate sets was not specified, keep its current setting. + */ + + error = wlu_iovar_get(wl, "cur_rateset", &cur_rs, sizeof(cur_rs)); + if (error) + return error; + + if (!rs->count) { /* No legacy rates specified -- keep what we have */ + rs->count = cur_rs.count; + memcpy(&rs->rates, &cur_rs.rates, rs->count); + } + + if (!mcs_args) { /* No MCS rates specified */ + memcpy(rs->mcs, cur_rs.mcs, MCSSET_LEN); + } + + if (!vht_args) { /* No VHT rates specified, keep current values */ + memcpy(rs->vht_mcs, cur_rs.vht_mcs, + VHT_CAP_MCS_MAP_NSS_MAX * sizeof(rs->vht_mcs[0])); + } + + /* If no more args, return. */ + + if (!arg) { + return error; + } + + /* Parse mcs or VHT rateset values */ + + while ((arg = *argv++) != NULL) { + + if (mcs_args) { + + if (mcs_index >= MCSSET_LEN) { + fprintf(stderr, "parsing \"%s\", too many mcs rates " + "specified, max is %d rates\n", arg, MCSSET_LEN); + error = BCME_USAGE_ERROR; + break; + } + + mcs_mask = strtoul(arg, &endp, 16); + + if (endp == arg) { + fprintf(stderr, "unable to convert the mcs parameter \"%s\"\n", arg); + error = BCME_BADARG; + break; + } + + /* clear the mcs rates */ + if (mcs_mask == 0) { + memset(rs->mcs, 0, MCSSET_LEN); + break; + } + + /* copy the mcs rates bitmap octets */ + rs->mcs[mcs_index++] = mcs_mask; + + } else { /* vht_args */ + + /* + * Specified as rate masks for Nss=0, Nss=1, etc. + */ + if (mcs_index >= VHT_CAP_MCS_MAP_NSS_MAX) { + fprintf(stderr, + "Error: Too many VHT rate masks specified, max %d\n", + VHT_CAP_MCS_MAP_NSS_MAX); + error = BCME_USAGE_ERROR; + break; + } + + mcs_mask = strtoul( arg, &endp, 16 ); /* Base 16 for consistency with -m */ + + if ((*arg == '\0') || (*endp != '\0')) { + fprintf(stderr, "Error converting VHT rate mask value '%s'\n", arg); + error = BCME_USAGE_ERROR; + break; + } + + /* + * Can only specify 0, 0xff, 0x1ff, 0x3ff because of the way the rates + * are encoded in the driver (0-3). + */ + if ((mcs_mask != 0x0000) && /* vht disabled */ + (mcs_mask != 0x00ff) && /* vht mcs0-7 */ + (mcs_mask != 0x01ff) && /* vht mcs0-8 */ + (mcs_mask != 0x03ff)) { /* vht mcs0-9 */ + fprintf(stderr, "Error: VHT rate mask must be 0 (disabled)," + " 0xff (MCS0-7), 0x1ff (MCS0-8), or 0x3ff (MCS0-9).\n"); + error = BCME_BADARG; + break; + } + + rs->vht_mcs[mcs_index++] = mcs_mask; + } + } + + return error; +} + +/* + * Get or Set Pwr Sel Params + * wl powersel_params \ + * <tp_ratio_thresh> <rate_stab_thresh> <pwr_stab_thresh> <pwr_sel_exp_time> + */ +static int +wl_power_sel_params(void *wl, cmd_t *cmd, char **argv) +{ + int err, argc; + powersel_params_t pwrsel_params; + + UNUSED_PARAMETER(cmd); + + argv++; + + if (*argv == NULL) { + /* get current powersel params */ + if ((err = wlu_iovar_get(wl, cmd->name, (void *) &pwrsel_params, + (sizeof(powersel_params_t)))) < 0) + return (err); + + printf("- Link Power Control parameters -\n"); + printf("tp_ratio_thresh\t\t= %d\nrate_stab_thresh\t= %d\n", + pwrsel_params.tp_ratio_thresh, pwrsel_params.rate_stab_thresh); + printf("pwr_stab_thresh\t\t= %d\npwr_sel_exp_time\t= %d\n", + pwrsel_params.pwr_stab_thresh, pwrsel_params.pwr_sel_exp_time); + } else { + char *endptr; + /* Validate num of entries */ + for (argc = 0; argv[argc]; argc++); + if (argc != 4) + return BCME_USAGE_ERROR; + + argc = 0; + pwrsel_params.tp_ratio_thresh = strtol(argv[argc], &endptr, 0); + argc++; + pwrsel_params.rate_stab_thresh = strtol(argv[argc], &endptr, 0); + argc++; + pwrsel_params.pwr_stab_thresh = strtol(argv[argc], &endptr, 0); + argc++; + pwrsel_params.pwr_sel_exp_time = strtol(argv[argc], &endptr, 0); + + /* Set powersel params */ + err = wlu_iovar_set(wl, cmd->name, (void *) &pwrsel_params, + (sizeof(powersel_params_t))); + } + + return err; +} + +/* Set per-band bandwidth */ +static int wl_bw_cap(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + struct { + uint32 band; + uint32 bw_cap; + } param = { 0, 0 }; + char *s = NULL; + void *ptr = NULL; + + /* Skip the command name */ + argv++; + + if (*argv) { + if (!strcmp(*argv, "a") || !strcmp(*argv, "5") || !strcmp(*argv, "5g")) { + param.band = WLC_BAND_5G; + } else if (!strcmp(*argv, "b") || !strcmp(*argv, "2") || !strcmp(*argv, "2g")) { + param.band = WLC_BAND_2G; + } else { + fprintf(stderr, + "%s: invalid band %s\n", + cmd->name, *argv); + err = BCME_USAGE_ERROR; + goto exit; + } + + argv++; + + if (*argv) { + /* Optional 2nd arg is used to set the bandwidth cap */ + s = NULL; + + param.bw_cap = (uint32) strtoul(*argv, &s, 0); + if (s && *s != '\0') { + fprintf(stderr, "%s: invalid bandwidth '%s'\n", + cmd->name, *argv); + err = BCME_USAGE_ERROR; + goto exit; + } + } + } else { + fprintf(stderr, "%s: band unspecified\n", cmd->name); + err = BCME_USAGE_ERROR; + goto exit; + } + + if (param.bw_cap == 0) { + if ((err = wlu_var_getbuf(wl, cmd->name, ¶m, sizeof(param), &ptr)) < 0) + return err; + + printf("0x%x\n", *((uint32 *)ptr)); + } else { + err = wlu_var_setbuf(wl, cmd->name, ¶m, sizeof(param)); + } + +exit: + return err; +} + +static int +wl_channel(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + channel_info_t ci; + + if (!*++argv) { + memset(&ci, 0, sizeof(ci)); + if ((ret = wlu_get(wl, cmd->get, &ci, sizeof(channel_info_t))) < 0) + return ret; + ci.hw_channel = dtoh32(ci.hw_channel); + ci.scan_channel = dtoh32(ci.scan_channel); + ci.target_channel = dtoh32(ci.target_channel); + if (ci.scan_channel) { + printf("Scan in progress.\n"); + printf("current scan channel\t%d\n", ci.scan_channel); + } else { + printf("No scan in progress.\n"); + } + printf("current mac channel\t%d\n", ci.hw_channel); + printf("target channel\t%d\n", ci.target_channel); + return 0; + } else { + ci.target_channel = htod32(atoi(*argv)); + ret = wlu_set(wl, cmd->set, &ci.target_channel, sizeof(int)); + return ret; + } +} + +static int +wl_chanspec(void *wl, cmd_t *cmd, char **argv) +{ + miniopt_t to; + const char* fn_name = "wl_chanspec"; + bool band_set = FALSE, ch_set = FALSE, bw_set = FALSE, ctl_sb_set = FALSE; + int err, opt_err; + uint32 val = 0; + chanspec_t chanspec = 0; + + /* toss the command name */ + argv++; + + if (!*argv) { + if (cmd->get < 0) + return -1; + if ((err = wlu_iovar_getint(wl, cmd->name, (int*)&val)) < 0) + return err; + + chanspec = wl_chspec32_from_driver(val); + wf_chspec_ntoa(chanspec, buf); + printf("%s (0x%x)\n", buf, chanspec); + return 0; + } + + + chanspec = wf_chspec_aton(*argv); + if (chanspec != 0) { + val = wl_chspec32_to_driver(chanspec); + if (val != INVCHANSPEC) { + err = wlu_iovar_setint(wl, cmd->name, val); + } else { + err = BCME_USAGE_ERROR; + } + } else { + miniopt_init(&to, fn_name, NULL, FALSE); + while ((opt_err = miniopt(&to, argv)) != -1) { + if (opt_err == 1) { + err = BCME_USAGE_ERROR; + goto exit; + } + argv += to.consumed; + + if (to.opt == 'c') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for" + " the channel\n", fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if (to.val > 224) { + fprintf(stderr, "%s: invalid channel %d\n", + fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + chanspec |= to.val; + ch_set = TRUE; + } + if (to.opt == 'b') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for band\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val != 5) && (to.val != 2)) { + fprintf(stderr, + "%s: invalid band %d\n", + fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + if (to.val == 5) + chanspec |= WL_CHANSPEC_BAND_5G; + else + chanspec |= WL_CHANSPEC_BAND_2G; + band_set = TRUE; + } + if (to.opt == 'w') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for" + " bandwidth\n", fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val != 20) && (to.val != 40) && (to.val != 80)) { + fprintf(stderr, + "%s: invalid bandwidth %d\n", + fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + if (to.val == 20) + chanspec |= WL_CHANSPEC_BW_20; + else if (to.val == 40) + chanspec |= WL_CHANSPEC_BW_40; + else + chanspec |= WL_CHANSPEC_BW_80; + bw_set = TRUE; + } + if (to.opt == 's') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for" + " ctl sideband\n", fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val != 1) && (to.val != 0) && (to.val != -1)) { + fprintf(stderr, + "%s: invalid ctl sideband %d\n", + fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + if (to.val == -1) + chanspec |= WL_CHANSPEC_CTL_SB_LOWER; + else if (to.val == 1) + chanspec |= WL_CHANSPEC_CTL_SB_UPPER; + ctl_sb_set = TRUE; + } + } + + /* set ctl sb to 20 if not set and 20mhz is selected */ + if (!ctl_sb_set && CHSPEC_IS20(chanspec)) { + ctl_sb_set = TRUE; + } + + if (ch_set && band_set && bw_set && ctl_sb_set) { + val = wl_chspec32_to_driver(chanspec); + if (val != INVCHANSPEC) { + err = wlu_iovar_setint(wl, cmd->name, val); + } else { + err = BCME_USAGE_ERROR; + } + } else { + if (!ch_set) + fprintf(stderr, "%s: you need to set a channel," + " '-c <ch>'\n", fn_name); + if (!band_set) + fprintf(stderr, "%s: you need to set a band," + " '-b <5|2>'\n", fn_name); + if (!bw_set) + fprintf(stderr, "%s: you need to set a bandwidth," + " '-w <20|40>'\n", fn_name); + if (!ctl_sb_set) + fprintf(stderr, "%s: you need to set a ctl sideband," + " '-s <-1|0|1>'\n", fn_name); + err = BCME_USAGE_ERROR; + } + } + + if (!err) + printf("Chanspec set to 0x%x\n", chanspec); + +exit: + return err; +} + +static int +wl_rclass(void *wl, cmd_t *cmd, char **argv) +{ + int err = BCME_USAGE_ERROR; + chanspec_t chanspec = 0; + void *ptr; + + /* toss the command name */ + argv++; + + if (*argv) { + chanspec = wf_chspec_aton(*argv); + if (chanspec != 0) { + err = wlu_var_getbuf(wl, cmd->name, &chanspec, sizeof(chanspec_t), &ptr); + + if (err) + printf("Read rclass fails: chanspec:0x%x\n", chanspec); + else + printf("rclass=0x%x\n", *((int *)ptr)); + } + } + + return err; +} + +static int +wl_chanim_state(void *wl, cmd_t *cmd, char **argv) +{ + uint32 chanspec; + int argc = 0; + int ret, val; + + argv++; + + /* find the arg count */ + while (argv[argc]) + argc++; + + if (argc != 1) + return BCME_USAGE_ERROR; + + chanspec = wf_chspec_aton(*argv); + chanspec = wl_chspec32_to_driver(chanspec); + if (chanspec == INVCHANSPEC) { + return BCME_USAGE_ERROR; + } + + ret = wlu_iovar_getbuf(wl, cmd->name, &chanspec, sizeof(chanspec), + buf, WLC_IOCTL_SMLEN); + if (ret < 0) + return ret; + val = *(int*)buf; + val = dtoh32(val); + + printf("%d\n", val); + return 0; +} + +static int +wl_chanim_mode(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + char *endptr; + int mode; + + if (!*++argv) { + if (cmd->get < 0) + return -1; + if ((ret = wlu_iovar_getint(wl, cmd->name, &mode)) < 0) + return ret; + + switch (mode) { + case CHANIM_DISABLE: + printf("CHANIM mode: disabled.\n"); + break; + case CHANIM_DETECT: + printf("CHANIM mode: detect only.\n"); + break; + case CHANIM_EXT: + printf("CHANIM mode: external (acsd).\n"); + break; + case CHANIM_ACT: + printf("CHANIM mode: detect + act.\n"); + break; + } + return 0; + } else { + mode = CHANIM_DETECT; + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + switch (val) { + case 0: + mode = CHANIM_DISABLE; + break; + case 1: + mode = CHANIM_DETECT; + break; + case 2: + mode = CHANIM_EXT; + break; + case 3: + mode = CHANIM_ACT; + break; + default: + return BCME_BADARG; + } + + mode = htod32(mode); + return wlu_iovar_setint(wl, cmd->name, mode); + } +} + +int +wl_ether_atoe(const char *a, struct ether_addr *n) +{ + char *c = NULL; + int i = 0; + + memset(n, 0, ETHER_ADDR_LEN); + for (;;) { + n->octet[i++] = (uint8)strtoul(a, &c, 16); + if (!*c++ || i == ETHER_ADDR_LEN) + break; + a = c; + } + return (i == ETHER_ADDR_LEN); +} +char * +wl_ether_etoa(const struct ether_addr *n) +{ + static char etoa_buf[ETHER_ADDR_LEN * 3]; + char *c = etoa_buf; + int i; + + for (i = 0; i < ETHER_ADDR_LEN; i++) { + if (i) + *c++ = ':'; + c += sprintf(c, "%02X", n->octet[i] & 0xff); + } + return etoa_buf; +} + +int +wl_atoip(const char *a, struct ipv4_addr *n) +{ + char *c = NULL; + int i = 0; + + for (;;) { + n->addr[i++] = (uint8)strtoul(a, &c, 0); + if (*c++ != '.' || i == IPV4_ADDR_LEN) + break; + a = c; + } + return (i == IPV4_ADDR_LEN); +} + + +int wl_ipv6_colon(const char *a, char *x) +{ + int i; + const char *t; + int colons = 0; + int double_colons = 0; + int zero_req = 0; + + if (*a == ':' && *(a+1) != ':') + return 1; /* Illegal */ + t = a; + while ((t = strstr(t, "::")) != NULL) { + ++t; + ++double_colons; + } + + if (double_colons == 0) { + strcpy(x, a); /* No double colon in the address */ + return 0; + } + + if (double_colons > 1) { + return 1; /* Illegal */ + } + t = a; + while ((t = strchr(t, ':')) != NULL) { + ++t; + ++colons; + } + zero_req = 8 - colons; + if (zero_req) { + t = a; + while (*t) { + if (*t == ':' && *(t+1) == ':') { + if (t == a) { + *x++ = '0'; + } + *x++ = *t++; + for (i = 0; i < zero_req; i++) { + *x++ = '0'; + *x++ = ':'; + } + t++; + } else { + *x++ = *t++; + } + } + } else { + strcpy(x, a); + } + return 0; +} + +int +wl_atoipv6(const char *a, struct ipv6_addr *n) +{ + char *c = NULL; + int i = 0; + uint16 *addr16; + char x[64]; + char *t = x; + + memset(x, 0, 64); + + if (wl_ipv6_colon(a, x) == 1) { + return 0; + } + + for (;;) { + addr16 = (uint16 *)&n->addr[i]; + *addr16 = hton16((uint16)strtoul((char *)t, &c, 16)); + i += 2; + if (*c++ != ':' || i == IPV6_ADDR_LEN) + break; + t = c; + } + + return (i == IPV6_ADDR_LEN); +} + +char * +wl_ipv6toa(const void *ipv6) +{ + /* Implementing RFC 5952 Sections 4 + 5 */ + /* Not thoroughly tested */ + uint16 *a = (uint16 *)ipv6; + + /* Returned buffer is from a static circular pool to permit several calls in a printf */ +#define IPV6_BUFFER_CNT 4 + static char buffer[IPV6_BUFFER_CNT][IPV6_ADDR_LEN * 4]; + static int idx = 0; + + char *p = buffer[idx++ % IPV6_BUFFER_CNT]; + int i, i_max = -1, cnt = 0, cnt_max = 1; + uint8 *a4 = NULL; + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if (a[i]) { + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + cnt = 0; + } else + cnt++; + } + if (cnt > cnt_max) { + cnt_max = cnt; + i_max = i - cnt; + } + if (i_max == 0 && + /* IPv4-translated: ::ffff:0:a.b.c.d */ + ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || + /* IPv4-mapped: ::ffff:a.b.c.d */ + (cnt_max == 5 && a[5] == 0xffff))) + a4 = (uint8*) (a + 6); + + for (i = 0; i < IPV6_ADDR_LEN/2; i++) { + if ((uint8*) (a + i) == a4) { + sprintf(p, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); + break; + } else if (i == i_max) { + *p++ = ':'; + i += cnt_max - 1; + p[0] = ':'; + p[1] = '\0'; + } else { + if (i) + *p++ = ':'; + p += sprintf(p, "%x", ntoh16(a[i])); + } + } + + /* Sub-buffer start is found back by rounding p with the sub-buffer size */ + return buffer[(p - buffer[0]) / sizeof(buffer[0])]; +} + +char * +wl_iptoa(const struct ipv4_addr *n) +{ + static char iptoa_buf[IPV4_ADDR_LEN * 4]; + + sprintf(iptoa_buf, "%u.%u.%u.%u", + n->addr[0], n->addr[1], n->addr[2], n->addr[3]); + + return iptoa_buf; +} + +int +wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len) +{ + int i, c; + char *p = ssid_buf; + + if (ssid_len > 32) + ssid_len = 32; + + for (i = 0; i < ssid_len; i++) { + c = (int)ssid[i]; + if (c == '\\') { + *p++ = '\\'; + *p++ = '\\'; + } else if (isprint((uchar)c)) { + *p++ = (char)c; + } else { + p += sprintf(p, "\\x%02X", c); + } + } + *p = '\0'; + + return p - ssid_buf; +} + +/* pretty hex print a contiguous buffer */ +void +wl_hexdump(uchar *dump_buf, uint nbytes) +{ + char line[256]; + char* p; + uint i; + + if (nbytes == 0) { + printf("\n"); + return; + } + + p = line; + for (i = 0; i < nbytes; i++) { + if (i % 16 == 0 && nbytes > 16) { + p += sprintf(p, "%04d: ", i); /* line prefix */ + } + p += sprintf(p, "%02x ", dump_buf[i]); + if (i % 16 == 15) { + printf("%s\n", line); /* flush line */ + p = line; + } + } + + /* flush last partial line */ + if (p != line) + printf("%s\n", line); +} + +static int +wl_plcphdr(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + + if (!*++argv) { + if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0) + return ret; + val = dtoh32(val); + if (val == WLC_PLCP_AUTO) + printf("long"); + else if (val == WLC_PLCP_SHORT) + printf("auto"); + else if (val == WLC_PLCP_LONG) + printf("debug"); + else + printf("unknown"); + printf("\n"); + return 0; + } else { + if (!stricmp(*argv, "long")) + val = WLC_PLCP_AUTO; + else if (!stricmp(*argv, "auto")) + val = WLC_PLCP_SHORT; + else if (!stricmp(*argv, "debug")) + val = WLC_PLCP_LONG; + else + return BCME_USAGE_ERROR; + val = htod32(val); + return wlu_set(wl, cmd->set, &val, sizeof(int)); + } +} + +/* WLC_GET_RADIO and WLC_SET_RADIO in driver operate on radio_disabled which + * is opposite of "wl radio [1|0]". So invert for user. + * In addition, display WL_RADIO_SW_DISABLE and WL_RADIO_HW_DISABLE bits. + */ +static int +wl_radio(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + uint val; + char *endptr = NULL; + + if (!*++argv) { + if (cmd->get < 0) + return -1; + if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0) + return ret; + val = dtoh32(val); + printf("0x%04x\n", val); + return 0; + } else { + if (cmd->set < 0) + return -1; + if (!stricmp(*argv, "on")) + val = WL_RADIO_SW_DISABLE << 16; + else if (!stricmp(*argv, "off")) + val = WL_RADIO_SW_DISABLE << 16 | WL_RADIO_SW_DISABLE; + else { + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + + /* raw bits setting, add the mask if not provided */ + if ((val >> 16) == 0) { + val |= val << 16; + } + } + val = htod32(val); + return wlu_set(wl, cmd->set, &val, sizeof(int)); + } +} + +static char * +ver2str(unsigned int vms, unsigned int vls) +{ + static char verstr[100]; + unsigned int maj, year, month, day, build; + + maj = (vms >> 16) & 0xFFFF; + if (maj > 1000) { + /* it is probably a date... */ + year = (vms >> 16) & 0xFFFF; + month = vms & 0xFFFF; + day = (vls >> 16) & 0xFFFF; + build = vls & 0xFFFF; + sprintf(verstr, "%d/%d/%d build %d", + month, day, year, build); + } else { + /* it is a tagged release. */ + sprintf(verstr, "%d.%d RC%d.%d", + (vms>>16)&0xFFFF, vms&0xFFFF, + (vls>>16)&0xFFFF, vls&0xFFFF); + } + return verstr; +} + + +static int +wl_version(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int bcmerr = 0; + char *p = NULL; + char *dump_buf; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + printf("%s\n", + ver2str(((EPI_MAJOR_VERSION) << 16) | EPI_MINOR_VERSION, + (EPI_RC_NUMBER << 16) | EPI_INCREMENTAL_NUMBER)); + dump_buf = malloc(WLC_IOCTL_SMLEN); + if (dump_buf == NULL) { + fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WLC_IOCTL_SMLEN); + return BCME_NOMEM; + } + memset(dump_buf, 0, WLC_IOCTL_SMLEN); + + /* query for 'ver' to get version info */ + ret = wlu_iovar_get(wl, "ver", dump_buf, WLC_IOCTL_SMLEN); + + /* if the query is successful, continue on and print the result. */ + + /* if the query fails, check for a legacy driver that does not support + * the "dump" iovar, and instead issue a WLC_DUMP ioctl. + */ + if (ret) { + wlu_iovar_getint(wl, "bcmerror", &bcmerr); + if (bcmerr == BCME_UNSUPPORTED) { + ret = wlu_get(wl, WLC_DUMP, dump_buf, WLC_IOCTL_SMLEN); + } + } + + if (ret) { + fprintf(stderr, "Error %d on query of driver dump\n", (int)ret); + free(dump_buf); + return ret; + } + + /* keep only the first line from the dump buf output */ + p = strchr(dump_buf, '\n'); + if (p) + *p = '\0'; + printf("%s\n", dump_buf); + + free(dump_buf); + + return 0; +} + +static int +wl_rateparam(void *wl, cmd_t *cmd, char **argv) +{ + int val[2]; + + if (!*++argv) + return BCME_USAGE_ERROR; + val[0] = htod32(atoi(*argv)); + if (!*++argv) + return BCME_USAGE_ERROR; + val[1] = htod32(atoi(*argv)); + return wlu_set(wl, cmd->set, val, 2 * sizeof(val)); +} + +/* wl scan + * -s --ssid=ssid_list + * -t T --scan_type=T : [active|passive] + * --bss_type=T : [infra|bss|adhoc|ibss] + * -b --bssid= + * -n --nprobes= + * -a --active= + * -p --passive= + * -h --home= + * -c --channels= + * ssid_list + */ + +/* Parse a comma-separated list from list_str into ssid array, starting + * at index idx. Max specifies size of the ssid array. Parses ssids + * and returns updated idx; if idx >= max not all fit, the excess have + * not been copied. Returns -1 on empty string, or on ssid too long. + */ +static int +wl_parse_ssid_list(char* list_str, wlc_ssid_t* ssid, int idx, int max) +{ + char *str, *ptr; + + if (list_str == NULL) + return -1; + + for (str = list_str; str != NULL; str = ptr) { + if ((ptr = strchr(str, ',')) != NULL) + *ptr++ = '\0'; + + if (strlen(str) > DOT11_MAX_SSID_LEN) { + fprintf(stderr, "ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN); + return -1; + } + if (strlen(str) == 0) + ssid[idx].SSID_len = 0; + + if (idx < max) { + strcpy((char*)ssid[idx].SSID, str); + ssid[idx].SSID_len = strlen(str); + } + idx++; + } + + return idx; +} + +static int +wl_scan_prep(void *wl, cmd_t *cmd, char **argv, wl_scan_params_t *params, int *params_size) +{ + int val = 0; + char key[64]; + int keylen; + char *p, *eq, *valstr, *endptr = NULL; + char opt; + bool positional_param; + bool good_int; + bool opt_end; + int err = 0; + int i; + + int nchan = 0; + int nssid = 0; + wlc_ssid_t ssids[WL_SCAN_PARAMS_SSID_MAX]; + + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(cmd); + + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = 0; + params->nprobes = -1; + params->active_time = -1; + params->passive_time = -1; + params->home_time = -1; + params->channel_num = 0; + memset(ssids, 0, WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t)); + + /* skip the command name */ + argv++; + + opt_end = FALSE; + while ((p = *argv) != NULL) { + argv++; + positional_param = FALSE; + memset(key, 0, sizeof(key)); + opt = '\0'; + valstr = NULL; + good_int = FALSE; + + if (opt_end) { + positional_param = TRUE; + valstr = p; + } + else if (!strcmp(p, "--")) { + opt_end = TRUE; + continue; + } + else if (!strncmp(p, "--", 2)) { + eq = strchr(p, '='); + if (eq == NULL) { + fprintf(stderr, + "wl_scan: missing \" = \" in long param \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + keylen = eq - (p + 2); + if (keylen > 63) + keylen = 63; + memcpy(key, p + 2, keylen); + + valstr = eq + 1; + if (*valstr == '\0') { + fprintf(stderr, + "wl_scan: missing value after \" = \" in long param \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + } + else if (!strncmp(p, "-", 1)) { + opt = p[1]; + if (strlen(p) > 2) { + fprintf(stderr, + "wl_scan: only single char options, error on param \"%s\"\n", p); + err = BCME_BADARG; + goto exit; + } + if (*argv == NULL) { + fprintf(stderr, + "wl_scan: missing value parameter after \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + valstr = *argv; + argv++; + } else { + positional_param = TRUE; + valstr = p; + } + + /* parse valstr as int just in case */ + if (valstr) { + val = (int)strtol(valstr, &endptr, 0); + if (*endptr == '\0') { + /* not all the value string was parsed by strtol */ + good_int = TRUE; + } + } + + if (opt == 's' || !strcmp(key, "ssid") || positional_param) { + nssid = wl_parse_ssid_list(valstr, ssids, nssid, WL_SCAN_PARAMS_SSID_MAX); + if (nssid < 0) { + err = BCME_BADARG; + goto exit; + } + } + + /* scan_type is a bitmap value and can have multiple options */ + if (opt == 't' || !strcmp(key, "scan_type")) { + if (!strcmp(valstr, "active")) { + /* do nothing - scan_type is initialized outside of while loop */ + } else if (!strcmp(valstr, "passive")) { + params->scan_type |= WL_SCANFLAGS_PASSIVE; + } else if (!strcmp(valstr, "prohibit")) { + params->scan_type |= WL_SCANFLAGS_PROHIBITED; + } else if (!strcmp(valstr, "offchan")) { + params->scan_type |= WL_SCANFLAGS_OFFCHAN; + } else if (!strcmp(valstr, "hotspot")) { + params->scan_type |= WL_SCANFLAGS_HOTSPOT; + } else { + fprintf(stderr, + "scan_type value should be \"active\", " + "\"passive\", \"prohibit\", \"offchan\" " + "or \"hotspot\", but got \"%s\"\n", valstr); + err = BCME_USAGE_ERROR; + goto exit; + } + } + if (!strcmp(key, "bss_type")) { + if (!strcmp(valstr, "bss") || !strcmp(valstr, "infra")) { + params->bss_type = DOT11_BSSTYPE_INFRASTRUCTURE; + } else if (!strcmp(valstr, "ibss") || !strcmp(valstr, "adhoc")) { + params->bss_type = DOT11_BSSTYPE_INDEPENDENT; + } else if (!strcmp(valstr, "any")) { + params->bss_type = DOT11_BSSTYPE_ANY; + } else { + fprintf(stderr, + "bss_type value should be " + "\"bss\", \"ibss\", or \"any\", but got \"%s\"\n", valstr); + err = BCME_USAGE_ERROR; + goto exit; + } + } + if (opt == 'b' || !strcmp(key, "bssid")) { + if (!wl_ether_atoe(valstr, ¶ms->bssid)) { + fprintf(stderr, + "could not parse \"%s\" as an ethernet MAC address\n", valstr); + err = BCME_USAGE_ERROR; + goto exit; + } + } + if (opt == 'n' || !strcmp(key, "nprobes")) { + if (!good_int) { + fprintf(stderr, + "could not parse \"%s\" as an int for value nprobes\n", valstr); + err = BCME_BADARG; + goto exit; + } + params->nprobes = val; + } + if (opt == 'a' || !strcmp(key, "active")) { + if (!good_int) { + fprintf(stderr, + "could not parse \"%s\" as an int for active dwell time\n", + valstr); + err = BCME_BADARG; + goto exit; + } + params->active_time = val; + } + if (opt == 'p' || !strcmp(key, "passive")) { + if (!good_int) { + fprintf(stderr, + "could not parse \"%s\" as an int for passive dwell time\n", + valstr); + err = BCME_BADARG; + goto exit; + } + params->passive_time = val; + } + if (opt == 'h' || !strcmp(key, "home")) { + if (!good_int) { + fprintf(stderr, + "could not parse \"%s\" as an int for home channel dwell time\n", + valstr); + err = BCME_BADARG; + goto exit; + } + params->home_time = val; + } + if (opt == 'c' || !strcmp(key, "channels")) { + nchan = wl_parse_channel_list(valstr, params->channel_list, + WL_NUMCHANNELS); + if (nchan == -1) { + fprintf(stderr, "error parsing channel list arg\n"); + err = BCME_BADARG; + goto exit; + } + } + } + + if (nssid > WL_SCAN_PARAMS_SSID_MAX) { + fprintf(stderr, "ssid count %d exceeds max of %d\n", + nssid, WL_SCAN_PARAMS_SSID_MAX); + err = BCME_BADARG; + goto exit; + } + + params->nprobes = htod32(params->nprobes); + params->active_time = htod32(params->active_time); + params->passive_time = htod32(params->passive_time); + params->home_time = htod32(params->home_time); + + for (i = 0; i < nchan; i++) { + params->channel_list[i] = htodchanspec(params->channel_list[i]); + } + + for (i = 0; i < nssid; i++) { + ssids[i].SSID_len = htod32(ssids[i].SSID_len); + } + + /* For a single ssid, use the single fixed field */ + if (nssid == 1) { + nssid = 0; + memcpy(¶ms->ssid, &ssids[0], sizeof(ssids[0])); + } + + /* Copy ssid array if applicable */ + if (nssid > 0) { + i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16); + i = ROUNDUP(i, sizeof(uint32)); + if (i + nssid * sizeof(wlc_ssid_t) > (uint)*params_size) { + fprintf(stderr, "additional ssids exceed params_size\n"); + err = BCME_BADARG; + goto exit; + } + + p = (char*)params + i; + memcpy(p, ssids, nssid * sizeof(wlc_ssid_t)); + p += nssid * sizeof(wlc_ssid_t); + } else { + p = (char*)params->channel_list + nchan * sizeof(uint16); + } + + params->channel_num = htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | + (nchan & WL_SCAN_PARAMS_COUNT_MASK)); + *params_size = p - (char*)params + nssid * sizeof(wlc_ssid_t); +exit: + return err; +} + + +static int +wl_roamparms(void *wl, cmd_t *cmd, char **argv) +{ + int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); + wl_scan_params_t *params; + wl_join_scan_params_t jparms; + int err = 0; + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + params = (wl_scan_params_t*)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size); + return BCME_NOMEM; + } + memset(params, 0, params_size); + memset(&jparms, 0, sizeof(jparms)); + + if (!(argv[1])) { + err = wlu_iovar_getbuf(wl, "roamscan_parms", &jparms, sizeof(jparms), + buf, WLC_IOCTL_SMLEN); + memset(&jparms, 0, sizeof(jparms)); + memcpy(&jparms, buf, sizeof(jparms)); + + printf("Roam Scan Parameters:\n"); + printf("scan_type: %d\n", jparms.scan_type); + printf("nprobes: %d\n", jparms.nprobes); + printf("active_time: %d\n", jparms.active_time); + printf("passive_time: %d\n", jparms.passive_time); + printf("home_time: %d\n", jparms.home_time); + + goto done; + } + + + printf("Setting Roam Scan parameters \n"); + + + err = wl_scan_prep(wl, cmd, argv, params, ¶ms_size); + + if (err) + goto done; + /* after all of that arg processing we're going to toss some of them + * and only send down the ones relevant to a wl_join__scan_params_t + */ + jparms.scan_type = params->scan_type; + jparms.nprobes = params->nprobes; + jparms.active_time = params->active_time; + jparms.passive_time = params->passive_time; + jparms.home_time = params->home_time; + + err = wlu_iovar_setbuf(wl, "roamscan_parms", &jparms, sizeof(jparms), buf, WLC_IOCTL_SMLEN); + +done: + free(params); + return err; +} +static int +wl_scan(void *wl, cmd_t *cmd, char **argv) +{ + int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); + wl_scan_params_t *params; + int err = 0; + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + params = (wl_scan_params_t*)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size); + return BCME_NOMEM; + } + memset(params, 0, params_size); + + err = wl_scan_prep(wl, cmd, argv, params, ¶ms_size); + + if (!err) { + err = wlu_set(wl, cmd->set, params, params_size); + } + + free(params); + return err; +} + +extern time_t time(time_t *ptr); +static int +wl_escan(void *wl, cmd_t *cmd, char **argv) +{ + int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)) + + (WL_NUMCHANNELS * sizeof(uint16)); + wl_escan_params_t *params; + int err = 0; + uint16 action = WL_SCAN_ACTION_START; + + if (!stricmp(*argv, "escan")) + /* start an escan */ + action = WL_SCAN_ACTION_START; + else if (!stricmp(*argv, "escanabort")) + /* abort an escan */ + action = WL_SCAN_ACTION_ABORT; + else { + printf("unknown escan command: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + params = (wl_escan_params_t*)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size); + return BCME_NOMEM; + } + memset(params, 0, params_size); + + err = wl_scan_prep(wl, cmd, argv, ¶ms->params, ¶ms_size); + + if (!err) { + params->version = htod32(ESCAN_REQ_VERSION); + params->action = htod16(action); + + srand((unsigned)time(NULL)); + params->sync_id = htod16(rand() & 0xffff); + + params_size += OFFSETOF(wl_escan_params_t, params); + err = wlu_iovar_setbuf(wl, "escan", params, params_size, buf, WLC_IOCTL_MAXLEN); + } + + free(params); + return err; +} + +static int +wl_iscan(void *wl, cmd_t *cmd, char **argv) +{ + int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) + + (WL_NUMCHANNELS * sizeof(uint16)); + wl_iscan_params_t *params; + int err = 0; + uint16 action = WL_SCAN_ACTION_START; + char **p; + uint16 iscan_duration = 0; + + if (!stricmp(*argv, "iscan_s")) + action = WL_SCAN_ACTION_START; + else if (!stricmp(*argv, "iscan_c")) + action = WL_SCAN_ACTION_CONTINUE; + else { + printf("unknown iscan command: %s\n", *argv); + return BCME_USAGE_ERROR; + } + + /* look for iscan_duration parameter */ + p = argv; + while (*p != NULL) { + if (!strcmp(*p, "-d") || !strncmp(*p, "--duration=", 11)) { + char *valptr; + int val; + char *endptr; + if (!strcmp(*p, "-d")) + valptr = *(++p); + else + valptr = *p + 11; + val = (int)strtol(valptr, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, + "could not parse \"%s\" as an int for duration\n", + valptr); + err = -1; + goto exit; + } + iscan_duration = (uint16) val; + break; + } + ++p; + } + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + params = (wl_iscan_params_t*)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size); + return BCME_NOMEM; + } + memset(params, 0, params_size); + + err = wl_scan_prep(wl, cmd, argv, ¶ms->params, ¶ms_size); + + if (!err) { + params->version = htod32(ISCAN_REQ_VERSION); + params->action = htod16(action); + params->scan_duration = htod16(iscan_duration); + params_size += OFFSETOF(wl_iscan_params_t, params); + err = wlu_iovar_setbuf(wl, "iscan", params, params_size, buf, WLC_IOCTL_MAXLEN); + } + + free(params); +exit: + return err; +} + +static int +wl_parse_assoc_params(char **argv, wl_assoc_params_t *params, bool *prescanned) +{ + int err = BCME_OK; + char *p, *eq, *valstr; + char opt; + bool opt_end; + int keylen; + char key[64]; + int i; + bool bssid_set = FALSE; + bool ch_set = FALSE; + + opt_end = FALSE; + + while ((p = *argv) != NULL) { + argv++; + memset(key, 0, sizeof(key)); + opt = '\0'; + valstr = NULL; + + if (opt_end) { + valstr = p; + } + else if (!strcmp(p, "--")) { + opt_end = TRUE; + continue; + } + else if (!strcmp(p, "prescanned")) { + if (prescanned) + *prescanned = TRUE; + continue; + } + else if (!strncmp(p, "--", 2)) { + eq = strchr(p, '='); + if (eq == NULL) { + fprintf(stderr, "wl_parse_assoc_params: missing \" = \" in " + "long param \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + keylen = eq - (p + 2); + if (keylen > 63) + keylen = 63; + memcpy(key, p + 2, keylen); + + valstr = eq + 1; + if (*valstr == '\0') { + fprintf(stderr, "wl_parse_assoc_params: missing value after " + "\" = \" in long param \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + } + else if (!strncmp(p, "-", 1)) { + opt = p[1]; + if (strlen(p) > 2) { + fprintf(stderr, "wl_parse_assoc_params: only single char options, " + "error on param \"%s\"\n", p); + err = BCME_BADARG; + goto exit; + } + if (*argv == NULL) { + fprintf(stderr, "wl_parse_assoc_params: missing value parameter " + "after \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + valstr = *argv++; + } else { + valstr = p; + } + + /* handle -o v or --option=val */ + if (opt == 'b' || !stricmp(key, "bssid")) { + if (!wl_ether_atoe(valstr, ¶ms->bssid)) { + fprintf(stderr, "could not parse as an ethernet MAC address\n"); + err = BCME_USAGE_ERROR; + goto exit; + } + bssid_set = TRUE; + } + else if (opt == 'c' || !strcmp(key, "chanspecs")) { + params->chanspec_num = + wl_parse_chanspec_list(valstr, params->chanspec_list, WL_NUMCHANNELS); + if (params->chanspec_num == -1) { + fprintf(stderr, "error parsing chanspec list arg\n"); + err = BCME_BADARG; + goto exit; + } + ch_set = TRUE; + } + } + + if (prescanned && *prescanned && (ch_set || bssid_set)) { + fprintf(stderr, "cannot use bssid/channel options with prescan option\n"); + err = BCME_BADARG; + goto exit; + } + + /* prepare the chanspec using the channel number and the user provided options */ + for (i = 0; i < params->chanspec_num; i++) { + chanspec_t chanspec = wl_chspec_to_driver(params->chanspec_list[i]); + if (chanspec == INVCHANSPEC) { + err = BCME_USAGE_ERROR; + goto exit; + } + params->chanspec_list[i] = chanspec; + } + params->chanspec_num = htod32(params->chanspec_num); + +exit: + return err; +} + +/* wl reassoc <bssid> + * Options: + * -c CL, --chanspecs=CL, where CL is a comma or space separated list of chanspecs + */ +static int +wl_reassoc(void *wl, cmd_t *cmd, char **argv) +{ + int params_size = WL_REASSOC_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(chanspec_t); + wl_reassoc_params_t *params; + int err = 0; + + UNUSED_PARAMETER(cmd); + + if (*++argv == NULL) { + fprintf(stderr, "no arguments to wl_reassoc\n"); + return BCME_USAGE_ERROR; + } + + params = (wl_reassoc_params_t *)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size); + return BCME_NOMEM; + } + memset(params, 0, params_size); + + if (!wl_ether_atoe(*argv, ¶ms->bssid)) { + fprintf(stderr, "could not parse %s as an Ethernet MAC address\n", *argv); + err = BCME_USAGE_ERROR; + goto exit; + } + /* default to plain old ioctl */ + params_size = ETHER_ADDR_LEN; + + if (*++argv != NULL) { + if ((err = wl_parse_reassoc_params(argv, params)) != BCME_OK) { + fprintf(stderr, "could not parse reassociation parameters\n"); + goto exit; + } + params_size = WL_REASSOC_PARAMS_FIXED_SIZE + + dtoh32(params->chanspec_num) * sizeof(chanspec_t); + } + + err = wlu_set(wl, WLC_REASSOC, params, params_size); + +exit: + free(params); + return err; +} + +#ifdef EXTENDED_SCAN +/* wl extdscan + * -s --ssid=ssid1 ssid2 ssid3 + * -b --split_scan=0 : [split_scan] + * -t --scan_type=0 : [background/forcedbackground/foreground] + * -n --nprobes= + * -c --channels= + */ +static int +wl_extdscan(void *wl, cmd_t *cmd, char **argv) +{ + wl_extdscan_params_t *params; + int params_size = WL_EXTDSCAN_PARAMS_FIXED_SIZE + + (WL_NUMCHANNELS * sizeof(chan_scandata_t)); + int val = 0; + char *p, *eq, *valstr, *endptr; + char opt; + bool positional_param; + bool good_int; + bool opt_end; + int err = 0; + int keylen; + char key[64]; + int i; + int nssid = 0; + + fprintf(stderr, "params alloc size is %d\n", params_size); + params = (wl_extdscan_params_t *)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size); + return BCME_NOMEM; + } + memset(params, 0, params_size); + + params->scan_type = EXTDSCAN_FORCEDBACKGROUND_SCAN; + params->nprobes = 3; + params->band = WLC_BAND_2G; + params->split_scan = 0; + + /* skip the command name */ + argv++; + + if (*argv == NULL) { + fprintf(stderr, "no arguments to wl_extdscan\n"); + err = BCME_USAGE_ERROR; + goto exit; + } + opt_end = FALSE; + while ((p = *argv) != NULL) { + argv++; + positional_param = FALSE; + memset(key, 0, sizeof(key)); + opt = '\0'; + valstr = NULL; + good_int = FALSE; + + if (opt_end) { + positional_param = TRUE; + valstr = p; + } + else if (!strcmp(p, "--")) { + opt_end = TRUE; + continue; + } + else if (!strncmp(p, "--", 2)) { + eq = strchr(p, '='); + if (eq == NULL) { + fprintf(stderr, + "wl_extdscan: missing \" = \" in long param \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + keylen = eq - (p + 2); + if (keylen > 63) + keylen = 63; + memcpy(key, p + 2, keylen); + + valstr = eq + 1; + if (*valstr == '\0') { + fprintf(stderr, + "extdscan: missing value after \" = \" in long param \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + } + else if (!strncmp(p, "-", 1)) { + opt = p[1]; + if (strlen(p) > 2) { + fprintf(stderr, + "extdscan: only single char options, error on param \"%s\"\n", p); + err = BCME_BADARG; + goto exit; + } + if (*argv == NULL) { + fprintf(stderr, + "extdscan: missing value parameter after \"%s\"\n", p); + err = BCME_USAGE_ERROR; + goto exit; + } + valstr = *argv; + argv++; + } else { + positional_param = TRUE; + valstr = p; + } + + /* parse valstr as int just in case */ + if (valstr) { + val = (int)strtol(valstr, &endptr, 0); + if (*endptr == '\0') { + /* not all the value string was parsed by strtol */ + good_int = TRUE; + } + } + + if (opt == 's' || !strcmp(key, "ssid") || positional_param) { + nssid = wl_parse_ssid_list(valstr, params->ssid, + nssid, WLC_EXTDSCAN_MAX_SSID); + if (nssid < 0) { + err = BCME_BADARG; + goto exit; + } + } + if (opt == 'b' || !strcmp(key, "band")) { + if (!strcmp(valstr, "5G")) { + params->band = WLC_BAND_5G; + } + else if (!strcmp(valstr, "2.4G")) { + params->band = WLC_BAND_2G; + } + else if (!strcmp(valstr, "all")) { + params->band = WLC_BAND_ALL; + } else { + fprintf(stderr, + "scan_type value should be \"5G\" " + "or \"2.4G\" " "or \"all\" but got \"%s\"\n", valstr); + err = BCME_USAGE_ERROR; + goto exit; + } + } + if (opt == 't' || !strcmp(key, "scan_type")) { + if (!strcmp(valstr, "background")) { + params->scan_type = EXTDSCAN_BACKGROUND_SCAN; + } else if (!strcmp(valstr, "fbackground")) { + params->scan_type = EXTDSCAN_FORCEDBACKGROUND_SCAN; + } else if (!strcmp(valstr, "foreground")) { + params->scan_type = EXTDSCAN_FOREGROUND_SCAN; + } else { + fprintf(stderr, + "scan_type value should be \"background\" " + "or \"fbackground\" " "or \"foreground\" but got \"%s\"\n", valstr); + err = BCME_USAGE_ERROR; + goto exit; + } + } + if (opt == 'n' || !strcmp(key, "nprobes")) { + if (!good_int) { + fprintf(stderr, + "could not parse \"%s\" as an int for value nprobes\n", valstr); + err = BCME_BADARG; + goto exit; + } + params->nprobes = val; + } + if (opt == 'x' || !strcmp(key, "split_scan")) { + if (val != 0) + params->split_scan = 1; + } + if (opt == 'c' || !strcmp(key, "channels")) { + params->channel_num = wl_parse_extdchannel_list(valstr, + params->channel_list, WL_NUMCHANNELS); + if (params->channel_num == -1) { + fprintf(stderr, "error parsing channel list arg\n"); + err = BCME_BADARG; + goto exit; + } + } + } + + if (nssid > WLC_EXTDSCAN_MAX_SSID) { + fprintf(stderr, "ssid count %d exceeds max of %d\n", + nssid, WLC_EXTDSCAN_MAX_SSID); + err = BCME_BADARG; + goto exit; + } + + params_size = WL_EXTDSCAN_PARAMS_FIXED_SIZE + + (params->channel_num * sizeof(chan_scandata_t)); + + fprintf(stderr, "ssid list is %s(%d) %s(%d) %s(%d) %s(%d) %s(%d)\n", + (char *)¶ms->ssid[0].SSID, params->ssid[0].SSID_len, + (char *)¶ms->ssid[1].SSID, params->ssid[1].SSID_len, + (char *)¶ms->ssid[2].SSID, params->ssid[2].SSID_len, + (char *)¶ms->ssid[3].SSID, params->ssid[3].SSID_len, + (char *)¶ms->ssid[4].SSID, params->ssid[4].SSID_len); + if (params->split_scan) + fprintf(stderr, "split scan is enabled\n"); + else + fprintf(stderr, "split scan is not enabled\n"); + + fprintf(stderr, "scan type is %d, nprobes are %d, band is %d, channels are %d\n", + params->scan_type, params->nprobes, params->band, params->channel_num); + + fprintf(stderr, "params size is %d\n", params_size); + params->scan_type = htodenum(params->scan_type); + for (i = 0; i < WLC_EXTDSCAN_MAX_SSID; i++) { + params->ssid[i].SSID_len = htod32(params->ssid[i].SSID_len); + } + for (i = 0; i < params->channel_num; i++) { + chanspec_t chanspec = params->channel_list[i].channel; + chanspec = wl_chspec_to_driver(chanspec); + if (chanspec == INVCHANSPEC) { + err = BCME_USAGE_ERROR; + goto exit; + } + params->channel_list[i].channel = chanspec; + params->channel_list[i].channel_mintime = + htod32(params->channel_list[i].channel_mintime); + params->channel_list[i].channel_maxtime = + htod32(params->channel_list[i].channel_maxtime); + } + params->channel_num = htod32(params->channel_num); + err = wlu_var_setbuf(wl, cmd->name, params, params_size); + +exit: + free(params); + return err; +} + +static int +wl_parse_extdchannel_list(char* list_str, chan_scandata_t* channel_list, int channel_num) +{ + int num; + int val; + char* str; + char* endptr; + + if (list_str == NULL) + return -1; + + str = list_str; + num = 0; + while (*str != '\0') { + val = (int)strtol(str, &endptr, 0); + if (endptr == str) { + fprintf(stderr, + "could not parse channel number starting at" + " substring \"%s\" in list:\n%s\n", + str, list_str); + return -1; + } + str = endptr + strspn(endptr, " ,"); + + if (num == channel_num) { + fprintf(stderr, "too many channels (more than %d) in channel list:\n%s\n", + channel_num, list_str); + return -1; + } + channel_list->channel = (uint16)val; + channel_list++; + num++; + } + + return num; +} +#endif /* EXTENDED_SCAN */ + +static int +wl_parse_channel_list(char* list_str, uint16* channel_list, int channel_num) +{ + int num; + int val; + char* str; + char* endptr = NULL; + + if (list_str == NULL) + return -1; + + str = list_str; + num = 0; + while (*str != '\0') { + val = (int)strtol(str, &endptr, 0); + if (endptr == str) { + fprintf(stderr, + "could not parse channel number starting at" + " substring \"%s\" in list:\n%s\n", + str, list_str); + return -1; + } + str = endptr + strspn(endptr, " ,"); + + if (num == channel_num) { + fprintf(stderr, "too many channels (more than %d) in channel list:\n%s\n", + channel_num, list_str); + return -1; + } + + channel_list[num++] = (uint16)val; + } + + return num; +} + +static int +wl_parse_chanspec_list(char *list_str, chanspec_t *chanspec_list, int chanspec_num) +{ + int num = 0; + chanspec_t chanspec; + char *next, str[8]; + size_t len; + + if ((next = list_str) == NULL) + return BCME_ERROR; + + while ((len = strcspn(next, " ,")) > 0) { + if (len >= sizeof(str)) { + fprintf(stderr, "string \"%s\" before ',' or ' ' is too long\n", next); + return BCME_ERROR; + } + strncpy(str, next, len); + str[len] = 0; + chanspec = wf_chspec_aton(str); + if (chanspec == 0) { + fprintf(stderr, "could not parse chanspec starting at " + "\"%s\" in list:\n%s\n", str, list_str); + return BCME_ERROR; + } + if (num == chanspec_num) { + fprintf(stderr, "too many chanspecs (more than %d) in chanspec list:\n%s\n", + chanspec_num, list_str); + return BCME_ERROR; + } + chanspec_list[num++] = chanspec; + next += len; + next += strspn(next, " ,"); + } + + return num; +} + +/* channel info structure */ +typedef struct { + uint chan; /* channel number */ + uint freq; /* in Mhz */ +} chan_info_t; + +static chan_info_t chan_info[] = { + /* B channels */ + { 1, 2412}, + { 2, 2417}, + { 3, 2422}, + { 4, 2427}, + { 5, 2432}, + { 6, 2437}, + { 7, 2442}, + { 8, 2447}, + { 9, 2452}, + { 10, 2457}, + { 11, 2462}, + { 12, 2467}, + { 13, 2472}, + { 14, 2484}, + + /* A channels */ + /* 11a usa low */ + { 36, 5180}, + { 40, 5200}, + { 44, 5220}, + { 48, 5240}, + { 52, 5260}, + { 56, 5280}, + { 60, 5300}, + { 64, 5320}, + + /* 11a Europe */ + { 100, 5500}, + { 104, 5520}, + { 108, 5540}, + { 112, 5560}, + { 116, 5580}, + { 120, 5600}, + { 124, 5620}, + { 128, 5640}, + { 132, 5660}, + { 136, 5680}, + { 140, 5700}, + + /* 11a usa high */ + { 149, 5745}, + { 153, 5765}, + { 157, 5785}, + { 161, 5805}, + + /* 11a japan */ + { 184, 4920}, + { 188, 4940}, + { 192, 4960}, + { 196, 4980}, + { 200, 5000}, + { 204, 5020}, + { 208, 5040}, + { 212, 5060}, + { 216, 5080} +}; + +uint +freq2channel(uint freq) +{ + int i; + + for (i = 0; i < (int)ARRAYSIZE(chan_info); i++) { + if (chan_info[i].freq == freq) + return (chan_info[i].chan); + } + return (0); +} + +void +dump_rateset(uint8 *rates, uint count) +{ + uint i; + uint r; + bool b; + + printf("[ "); + for (i = 0; i < count; i++) { + r = rates[i] & 0x7f; + b = rates[i] & 0x80; + if (r == 0) + break; + printf("%d%s%s ", (r / 2), (r % 2)?".5":"", b?"(b)":""); + } + printf("]"); +} + +/* Helper routine to print the infrastructure mode while pretty printing the BSS list */ +static const char * +capmode2str(uint16 capability) +{ + capability &= (DOT11_CAP_ESS | DOT11_CAP_IBSS); + + if (capability == DOT11_CAP_ESS) + return "Managed"; + else if (capability == DOT11_CAP_IBSS) + return "Ad Hoc"; + else + return "<unknown>"; +} + +/* + * Traverse a string of 1-byte tag/1-byte length/variable-length value + * triples, returning a pointer to the substring whose first element + * matches tag + */ +static uint8 * +wlu_parse_tlvs(uint8 *tlv_buf, int buflen, uint key) +{ + uint8 *cp; + int totlen; + + cp = tlv_buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= 2) { + uint tag; + int len; + + tag = *cp; + len = *(cp +1); + + /* validate remaining totlen */ + if ((tag == key) && (totlen >= (len + 2))) + return (cp); + + cp += (len + 2); + totlen -= (len + 2); + } + + return NULL; +} + +static int +wlu_bcmp(const void *b1, const void *b2, int len) +{ + return (memcmp(b1, b2, len)); +} + +/* Is this body of this tlvs entry a WPA entry? If */ +/* not update the tlvs buffer pointer/length */ +static bool +wlu_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, uint *tlvs_len) +{ + uint8 *ie = *wpaie; + + /* If the contents match the WPA_OUI and type=1 */ + if ((ie[1] >= 6) && !wlu_bcmp(&ie[2], WPA_OUI "\x01", 4)) { + return TRUE; + } + + /* point to the next ie */ + ie += ie[1] + 2; + /* calculate the length of the rest of the buffer */ + *tlvs_len -= (int)(ie - *tlvs); + /* update the pointer to the start of the buffer */ + *tlvs = ie; + + return FALSE; +} + +static void +wl_dump_wpa_rsn_ies(uint8* cp, uint len) +{ + uint8 *parse = cp; + uint parse_len = len; + uint8 *wpaie; + uint8 *rsnie; + + while ((wpaie = wlu_parse_tlvs(parse, parse_len, DOT11_MNG_WPA_ID))) + if (wlu_is_wpa_ie(&wpaie, &parse, &parse_len)) + break; + if (wpaie) + wl_rsn_ie_dump((bcm_tlv_t*)wpaie); + + rsnie = wlu_parse_tlvs(cp, len, DOT11_MNG_RSN_ID); + if (rsnie) + wl_rsn_ie_dump((bcm_tlv_t*)rsnie); + + return; +} + +static void +wl_rsn_ie_dump(bcm_tlv_t *ie) +{ + int i; + int rsn; + wpa_ie_fixed_t *wpa = NULL; + rsn_parse_info_t rsn_info; + wpa_suite_t *suite; + uint8 std_oui[3]; + int unicast_count = 0; + int akm_count = 0; + uint16 capabilities; + uint cntrs; + int err; + + if (ie->id == DOT11_MNG_RSN_ID) { + rsn = TRUE; + memcpy(std_oui, WPA2_OUI, WPA_OUI_LEN); + err = wl_rsn_ie_parse_info(ie->data, ie->len, &rsn_info); + } else { + rsn = FALSE; + memcpy(std_oui, WPA_OUI, WPA_OUI_LEN); + wpa = (wpa_ie_fixed_t*)ie; + err = wl_rsn_ie_parse_info((uint8*)&wpa->version, wpa->length - WPA_IE_OUITYPE_LEN, + &rsn_info); + } + if (err || rsn_info.version != WPA_VERSION) + return; + + if (rsn) + printf("RSN:\n"); + else + printf("WPA:\n"); + + /* Check for multicast suite */ + if (rsn_info.mcast) { + printf("\tmulticast cipher: "); + if (!wlu_bcmp(rsn_info.mcast->oui, std_oui, 3)) { + switch (rsn_info.mcast->type) { + case WPA_CIPHER_NONE: + printf("NONE\n"); + break; + case WPA_CIPHER_WEP_40: + printf("WEP64\n"); + break; + case WPA_CIPHER_WEP_104: + printf("WEP128\n"); + break; + case WPA_CIPHER_TKIP: + printf("TKIP\n"); + break; + case WPA_CIPHER_AES_OCB: + printf("AES-OCB\n"); + break; + case WPA_CIPHER_AES_CCM: + printf("AES-CCMP\n"); + break; + default: + printf("Unknown-%s(#%d)\n", rsn ? "RSN" : "WPA", + rsn_info.mcast->type); + break; + } + } +#ifdef BCMCCX + else if (!wlu_bcmp(rsn_info.mcast->oui, CISCO_AIRONET_OUI, 3)) { + switch (rsn_info.mcast->type + CISCO_BASE) { + case WPA_CIPHER_CKIP: + printf("CKIP\n"); + break; + case WPA_CIPHER_CKIP_MMH: + printf("CKIP+CMIC\n"); + break; + case WPA_CIPHER_WEP_MMH: + printf("CMIC\n"); + break; + default: + break; + } + } +#endif /* BCMCCX */ + else { + printf("Unknown-%02X:%02X:%02X(#%d) ", + rsn_info.mcast->oui[0], rsn_info.mcast->oui[1], + rsn_info.mcast->oui[2], rsn_info.mcast->type); + } + } + + /* Check for unicast suite(s) */ + if (rsn_info.ucast) { + unicast_count = ltoh16_ua(&rsn_info.ucast->count); + printf("\tunicast ciphers(%d): ", unicast_count); + for (i = 0; i < unicast_count; i++) { + suite = &rsn_info.ucast->list[i]; + if (!wlu_bcmp(suite->oui, std_oui, 3)) { + switch (suite->type) { + case WPA_CIPHER_NONE: + printf("NONE "); + break; + case WPA_CIPHER_WEP_40: + printf("WEP64 "); + break; + case WPA_CIPHER_WEP_104: + printf("WEP128 "); + break; + case WPA_CIPHER_TKIP: + printf("TKIP "); + break; + case WPA_CIPHER_AES_OCB: + printf("AES-OCB "); + break; + case WPA_CIPHER_AES_CCM: + printf("AES-CCMP "); + break; + default: + printf("WPA-Unknown-%s(#%d) ", rsn ? "RSN" : "WPA", + suite->type); + break; + } + } +#ifdef BCMCCX + else if (!wlu_bcmp(suite->oui, CISCO_AIRONET_OUI, 3)) { + switch (suite->type + CISCO_BASE) { + case WPA_CIPHER_CKIP: + printf("CKIP "); + break; + case WPA_CIPHER_CKIP_MMH: + printf("CKIP+CMIC "); + break; + case WPA_CIPHER_WEP_MMH: + printf("CMIC "); + break; + default: + printf("Cisco-Unknown(#%d) ", suite->type); + break; + } + } +#endif /* BCMCCX */ + else { + printf("Unknown-%02X:%02X:%02X(#%d) ", + suite->oui[0], suite->oui[1], suite->oui[2], + suite->type); + } + } + printf("\n"); + } + /* Authentication Key Management */ + if (rsn_info.akm) { + akm_count = ltoh16_ua(&rsn_info.akm->count); + printf("\tAKM Suites(%d): ", akm_count); + for (i = 0; i < akm_count; i++) { + suite = &rsn_info.akm->list[i]; + if (!wlu_bcmp(suite->oui, std_oui, 3)) { + switch (suite->type) { + case RSN_AKM_NONE: + printf("None "); + break; + case RSN_AKM_UNSPECIFIED: + printf("WPA "); + break; + case RSN_AKM_PSK: + printf("WPA-PSK "); + break; + case RSN_AKM_FBT_1X: + printf("FT-802.1x "); + break; + case RSN_AKM_FBT_PSK: + printf("FT-PSK "); + break; + default: + printf("Unknown-%s(#%d) ", + rsn ? "RSN" : "WPA", suite->type); + break; + } + } +#ifdef BCMCCX + else if (!wlu_bcmp(suite->oui, CISCO_AIRONET_OUI, 3)) { + switch (suite->type + CISCO_BASE) { + case WPA_AUTH_CCKM: + printf("CCKM "); + break; + default: + printf("Cisco-Unknown(#%d) ", suite->type); + break; + } + } +#endif /* BCMCCX */ + else { + printf("Unknown-%02X:%02X:%02X(#%d) ", + suite->oui[0], suite->oui[1], suite->oui[2], + suite->type); + } + } + printf("\n"); + } + + /* Capabilities */ + if (rsn_info.capabilities) { + capabilities = ltoh16_ua(rsn_info.capabilities); + printf("\tCapabilities(0x%04x): ", capabilities); + if (rsn) + printf("%sPre-Auth, ", (capabilities & RSN_CAP_PREAUTH) ? "" : "No "); + + printf("%sPairwise, ", (capabilities & RSN_CAP_NOPAIRWISE) ? "No " : ""); + + cntrs = wl_rsn_ie_decode_cntrs((capabilities & RSN_CAP_PTK_REPLAY_CNTR_MASK) >> + RSN_CAP_PTK_REPLAY_CNTR_SHIFT); + + printf("%d PTK Replay Ctr%s", cntrs, (cntrs > 1)?"s":""); + + if (rsn) { + cntrs = wl_rsn_ie_decode_cntrs( + (capabilities & RSN_CAP_GTK_REPLAY_CNTR_MASK) >> + RSN_CAP_GTK_REPLAY_CNTR_SHIFT); + + printf("%d GTK Replay Ctr%s\n", cntrs, (cntrs > 1)?"s":""); + } else { + printf("\n"); + } + } else { + printf("\tNo %s Capabilities advertised\n", rsn ? "RSN" : "WPA"); + } + +} + +/* Validates and parses the RSN or WPA IE contents into a rsn_parse_info_t structure + * Returns 0 on success, or 1 if the information in the buffer is not consistant with + * an RSN IE or WPA IE. + * The buf pointer passed in should be pointing at the version field in either an RSN IE + * or WPA IE. + */ +static int +wl_rsn_ie_parse_info(uint8* rsn_buf, uint len, rsn_parse_info_t *rsn) +{ + uint16 count; + + memset(rsn, 0, sizeof(rsn_parse_info_t)); + + /* version */ + if (len < sizeof(uint16)) + return 1; + + rsn->version = ltoh16_ua(rsn_buf); + len -= sizeof(uint16); + rsn_buf += sizeof(uint16); + + /* Multicast Suite */ + if (len < sizeof(wpa_suite_mcast_t)) + return 0; + + rsn->mcast = (wpa_suite_mcast_t*)rsn_buf; + len -= sizeof(wpa_suite_mcast_t); + rsn_buf += sizeof(wpa_suite_mcast_t); + + /* Unicast Suite */ + if (len < sizeof(uint16)) + return 0; + + count = ltoh16_ua(rsn_buf); + + if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t))) + return 1; + + rsn->ucast = (wpa_suite_ucast_t*)rsn_buf; + len -= (sizeof(uint16) + count * sizeof(wpa_suite_t)); + rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t)); + + /* AKM Suite */ + if (len < sizeof(uint16)) + return 0; + + count = ltoh16_ua(rsn_buf); + + if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t))) + return 1; + + rsn->akm = (wpa_suite_auth_key_mgmt_t*)rsn_buf; + len -= (sizeof(uint16) + count * sizeof(wpa_suite_t)); + rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t)); + + /* Capabilites */ + if (len < sizeof(uint16)) + return 0; + + rsn->capabilities = rsn_buf; + + return 0; +} + +static uint +wl_rsn_ie_decode_cntrs(uint cntr_field) +{ + uint cntrs; + + switch (cntr_field) { + case RSN_CAP_1_REPLAY_CNTR: + cntrs = 1; + break; + case RSN_CAP_2_REPLAY_CNTRS: + cntrs = 2; + break; + case RSN_CAP_4_REPLAY_CNTRS: + cntrs = 4; + break; + case RSN_CAP_16_REPLAY_CNTRS: + cntrs = 16; + break; + default: + cntrs = 0; + break; + } + + return cntrs; +} + + +void +wl_dump_raw_ie(bcm_tlv_t *ie, uint len) +{ + uint dump_len; + + if (len == 0) { + return; + } else if (len == 1) { + printf("IE header truncated: ID: 0x%02X\n", ie->id); + return; + } else if (len < (uint)(ie->len + TLV_HDR_LEN)) { + printf("IE data truncated: ID: 0x%02X Len: %d\n", ie->id, ie->len); + dump_len = len - TLV_HDR_LEN; + } else { + printf("ID: 0x%02X Len: %d\n", ie->id, ie->len); + dump_len = ie->len; + } + + /* choose how to format the data based on data len */ + if (dump_len > 16) + printf("Data:\n"); + else if (dump_len > 0) + printf("Data: "); + + if (dump_len > 0) + wl_hexdump(ie->data, dump_len); + + if (dump_len < ie->len) + printf("<missing %d bytes>\n", ie->len - dump_len); + + return; +} + + +/* Pretty print the BSS list */ +static void +dump_networks(char *network_buf) +{ + wl_scan_results_t *list = (wl_scan_results_t*)network_buf; + wl_bss_info_t *bi; + uint i; + + if (list->count == 0) + return; + else if (list->version != WL_BSS_INFO_VERSION && + list->version != LEGACY2_WL_BSS_INFO_VERSION && + list->version != LEGACY_WL_BSS_INFO_VERSION) { + fprintf(stderr, "Sorry, your driver has bss_info_version %d " + "but this program supports only version %d.\n", + list->version, WL_BSS_INFO_VERSION); + return; + } + + bi = list->bss_info; + for (i = 0; i < list->count; i++, bi = (wl_bss_info_t*)((int8*)bi + dtoh32(bi->length))) { + dump_bss_info(bi); + } +} + +static void +bcm_wps_version(uint8 *wps_ie) +{ + uint16 wps_len; + uint16 wps_off, wps_suboff; + uint16 wps_key; + uint8 wps_field_len; + + wps_len = (uint16)*(wps_ie+TLV_LEN_OFF); /* Get the length of the WPS OUI header */ + wps_off = WPS_OUI_FIXED_HEADER_OFF; /* Skip the fixed headers */ + wps_field_len = 1; + + /* Parsing the OUI header looking for version number */ + while ((wps_len >= wps_off + 2) && (wps_field_len)) + { + wps_key = (((uint8)wps_ie[wps_off]*256) + (uint8)wps_ie[wps_off+1]); + if (wps_key == WPS_ID_VENDOR_EXT) { + /* Key found */ + wps_suboff = wps_off + WPS_OUI_HEADER_SIZE; + + /* Looking for the Vendor extension code 0x00 0x37 0x2A + * and the Version 2 sudId 0x00 + * if found then the next byte is the len of field which is always 1 + * for version field the byte after is the version number + */ + if (!wlu_bcmp(&wps_ie[wps_suboff], WFA_VENDOR_EXT_ID, WPS_OUI_LEN)&& + (wps_ie[wps_suboff+WPS_WFA_SUBID_V2_OFF] == WPS_WFA_SUBID_VERSION2)) + { + printf("V%d.%d ", (wps_ie[wps_suboff+WPS_WFA_V2_OFF]>>4), + (wps_ie[wps_suboff+WPS_WFA_V2_OFF] & 0x0f)); + return; + } + } + /* Jump to next field */ + wps_field_len = wps_ie[wps_off+WPS_OUI_HEADER_LEN+1]; + wps_off += WPS_OUI_HEADER_SIZE + wps_field_len; + } + + /* If nothing found from the parser then this is the WPS version 1.0 */ + printf("V1.0 "); +} + +static void +bcm_is_wps_configured(uint8 *wps_ie) +{ + /* Before calling this function the test of WPS_OUI type 4 should be already done + * If the contents match the WPS_OUI_SC_STATE + */ + uint16 wps_key; + wps_key = (wps_ie[WPS_SCSTATE_OFF]*256) + wps_ie[WPS_SCSTATE_OFF+1]; + if ((wps_ie[TLV_LEN_OFF] > (WPS_SCSTATE_OFF+5))&& + (wps_key == WPS_ID_SC_STATE)) + { + switch (wps_ie[WPS_SCSTATE_OFF+WPS_OUI_HEADER_SIZE]) + { + case WPS_SCSTATE_UNCONFIGURED: + printf("Unconfigured\n"); + break; + case WPS_SCSTATE_CONFIGURED: + printf("Configured\n"); + break; + default: + printf("Unknown State\n"); + } + } +} + +/* Looking for WPS OUI in the propriatary_ie */ +static bool +bcm_is_wps_ie(uint8 *ie, uint8 **tlvs, uint32 *tlvs_len) +{ + bool retval = FALSE; + /* If the contents match the WPS_OUI and type=4 */ + if ((ie[TLV_LEN_OFF] > (WPS_OUI_LEN+1)) && + !wlu_bcmp(&ie[TLV_BODY_OFF], WPS_OUI "\x04", WPS_OUI_LEN + 1)) { + retval = TRUE; + } + + /* point to the next ie */ + ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; + /* calculate the length of the rest of the buffer */ + *tlvs_len -= (int)(ie - *tlvs); + /* update the pointer to the start of the buffer */ + *tlvs = ie; + + return retval; +} + +static void +wl_dump_wps(uint8* cp, uint len) +{ + uint8 *parse = cp; + uint32 parse_len = len; + uint8 *proprietary_ie; + + while ((proprietary_ie = wlu_parse_tlvs(parse, parse_len, DOT11_MNG_WPA_ID))) { + if (bcm_is_wps_ie(proprietary_ie, &parse, &parse_len)) { + /* Print WPS status */ + printf("WPS: "); + /* Print the version get from vendor extension field */ + bcm_wps_version(proprietary_ie); + /* Print the WPS configure or Unconfigure option */ + bcm_is_wps_configured(proprietary_ie); + break; + } + } +} + +void +dump_bss_info(wl_bss_info_t *bi) +{ + char ssidbuf[SSID_FMT_BUF_LEN]; + char chspec_str[CHANSPEC_STR_LEN]; + wl_bss_info_107_t *old_bi; + int mcs_idx = 0; + uint16 capability; + + /* Convert version 107 to 109 */ + if (dtoh32(bi->version) == LEGACY_WL_BSS_INFO_VERSION) { + old_bi = (wl_bss_info_107_t *)bi; + bi->chanspec = CH20MHZ_CHSPEC(old_bi->channel); + bi->ie_length = old_bi->ie_length; + bi->ie_offset = sizeof(wl_bss_info_107_t); + } else { + /* do endian swap and format conversion for chanspec if we have + * not created it from legacy bi above + */ + bi->chanspec = wl_chspec_from_driver(bi->chanspec); + } + + wl_format_ssid(ssidbuf, bi->SSID, bi->SSID_len); + + printf("SSID: \"%s\"\n", ssidbuf); + + printf("Mode: %s\t", capmode2str(dtoh16(bi->capability))); + printf("RSSI: %d dBm\t", (int16)(dtoh16(bi->RSSI))); + + /* + * SNR has valid value in only 109 version. + * So print SNR for 109 version only. + */ + if (dtoh32(bi->version) == WL_BSS_INFO_VERSION) { + printf("SNR: %d dB\t", (int16)(dtoh16(bi->SNR))); + } + + printf("noise: %d dBm\t", bi->phy_noise); + if (bi->flags) { + uint16 flags = dtoh16(bi->flags); + printf("Flags: "); + if (flags & WL_BSS_FLAGS_FROM_BEACON) + printf("FromBcn "); + if (flags & WL_BSS_FLAGS_FROM_CACHE) + printf("Cached "); + if (flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) + printf("RSSI on-channel "); + printf("\t"); + } + printf("Channel: %s\n", wf_chspec_ntoa(bi->chanspec, chspec_str)); + + printf("BSSID: %s\t", wl_ether_etoa(&bi->BSSID)); + + printf("Capability: "); + capability = dtoh16(bi->capability); + if (capability & DOT11_CAP_ESS) + printf("ESS "); + if (capability & DOT11_CAP_IBSS) + printf("IBSS "); + if (capability & DOT11_CAP_POLLABLE) + printf("Pollable "); + if (capability & DOT11_CAP_POLL_RQ) + printf("PollReq "); + if (capability & DOT11_CAP_PRIVACY) + printf("WEP "); + if (capability & DOT11_CAP_SHORT) + printf("ShortPre "); + if (capability & DOT11_CAP_PBCC) + printf("PBCC "); + if (capability & DOT11_CAP_AGILITY) + printf("Agility "); + if (capability & DOT11_CAP_SHORTSLOT) + printf("ShortSlot "); + if (capability & DOT11_CAP_RRM) + printf("RRM "); + if (capability & DOT11_CAP_CCK_OFDM) + printf("CCK-OFDM "); + printf("\n"); + + printf("Supported Rates: "); + dump_rateset(bi->rateset.rates, dtoh32(bi->rateset.count)); + printf("\n"); + if (dtoh32(bi->ie_length)) + wl_dump_wpa_rsn_ies((uint8 *)(((uint8 *)bi) + dtoh16(bi->ie_offset)), + dtoh32(bi->ie_length)); + + if (dtoh32(bi->version) != LEGACY_WL_BSS_INFO_VERSION && bi->n_cap) { + if (bi->vht_cap) + printf("VHT Capable:\n"); + else + printf("HT Capable:\n"); + printf("\tChanspec: %sGHz channel %d %dMHz (0x%x)\n", + CHSPEC_IS2G(bi->chanspec)?"2.4":"5", CHSPEC_CHANNEL(bi->chanspec), + (CHSPEC_IS80(bi->chanspec) ? + 80 : (CHSPEC_IS40(bi->chanspec) ? + 40 : (CHSPEC_IS20(bi->chanspec) ? 20 : 10))), + bi->chanspec); + printf("\tPrimary channel: %d\n", bi->ctl_ch); + printf("\tHT Capabilities: "); + if (dtoh32(bi->nbss_cap) & HT_CAP_40MHZ) + printf("40Mhz "); + if (dtoh32(bi->nbss_cap) & HT_CAP_SHORT_GI_20) + printf("SGI20 "); + if (dtoh32(bi->nbss_cap) & HT_CAP_SHORT_GI_40) + printf("SGI40 "); + printf("\n\tSupported MCS : [ "); + for (mcs_idx = 0; mcs_idx < (MCSSET_LEN * 8); mcs_idx++) + if (isset(bi->basic_mcs, mcs_idx)) + printf("%d ", mcs_idx); + printf("]\n"); + + if (bi->vht_cap) { + int i; + uint mcs; + printf("\tVHT Capabilities: \n"); + printf("\tSupported VHT (tx) Rates:\n"); + for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) { + mcs = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_txmcsmap)); + if (mcs != VHT_CAP_MCS_MAP_NONE) + printf("\t\tNSS: %d MCS: %s\n", i, + (mcs == VHT_CAP_MCS_MAP_0_9 ? "0-9" : + (mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8" : "0-7"))); + } + printf("\tSupported VHT (rx) Rates:\n"); + for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) { + mcs = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap)); + if (mcs != VHT_CAP_MCS_MAP_NONE) + printf("\t\tNSS: %d MCS: %s\n", i, + (mcs == VHT_CAP_MCS_MAP_0_9 ? "0-9" : + (mcs == VHT_CAP_MCS_MAP_0_8 ? "0-8" : "0-7"))); + } + } + bi->chanspec = wl_chspec_to_driver(bi->chanspec); + } + + if (dtoh32(bi->ie_length)) + { + wl_dump_wps((uint8 *)(((uint8 *)bi) + dtoh16(bi->ie_offset)), + dtoh32(bi->ie_length)); + } + + if (dtoh16(bi->flags) & WL_BSS_FLAGS_HS20) { + printf("Hotspot 2.0 capable\n"); + } + + printf("\n"); +} + +static int +_wl_dump_lq(void *wl) +{ + int ret = BCME_OK, noise = 0; + wl_lq_t *plq = NULL; + void *ptr = NULL; + + memset(buf, 0, sizeof(wl_lq_t)); + + /* Display stats when disabled */ + if ((ret = wlu_get(wl, WLC_GET_PHY_NOISE, &noise, sizeof(int))) < 0) { + printf("wlc_get noise failed with retcode:%d\n", ret); + return ret; + } + + if ((ret = wlu_var_getbuf_sm (wl, "monitor_lq_status", NULL, 0, &ptr)) < 0) { + printf("wlc_get lq_status failed with retcode:%d\n", ret); + return ret; + } + + plq = (wl_lq_t *)ptr; + + if (!plq->isvalid) { + printf("Stats collection currently disabled" + "['wl monitor_lq 1' to enable statistics collection]\n"); + return ret; + } + + noise = dtoh32(noise); + plq->rssi[LQ_IDX_MIN] = dtoh32(plq->rssi[LQ_IDX_MIN]); + plq->rssi[LQ_IDX_MAX] = dtoh32(plq->rssi[LQ_IDX_MAX]); + plq->rssi[LQ_IDX_AVG] = dtoh32(plq->rssi[LQ_IDX_AVG]); + + printf("rss: %d, %d, %d\nsnr: %d, %d, %d\n", + plq->rssi[LQ_IDX_MIN], + plq->rssi[LQ_IDX_AVG], + plq->rssi[LQ_IDX_MAX], + plq->rssi[LQ_IDX_MIN]-noise, + plq->rssi[LQ_IDX_AVG]-noise, + plq->rssi[LQ_IDX_MAX]-noise); + + return ret; +} /* _wl_dump_lq */ + +static int +wl_dump_lq(void *wl, cmd_t *cmd, char **argv) +{ + int ret = BCME_OK; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) + ret = _wl_dump_lq(wl); + + return ret; +} /* wl_dump_lq */ + +static int +wl_monitor_lq(void *wl, cmd_t *cmd, char **argv) +{ + int ret = BCME_OK; + char *endptr = NULL; + char **startptr = argv; + + if (!*++startptr) { /* Get */ + ret = wl_varint(wl, cmd, argv); + } + else { + int val = *startptr[0]; + val = strtol(*startptr, &endptr, 0); + + if (*endptr != '\0') { + return BCME_USAGE_ERROR; + } + + val = htod32(val); + + if (val == LQ_STOP_MONITOR) { + if ((ret = _wl_dump_lq(wl))) + return ret; + } + + ret = wl_varint(wl, cmd, argv); /* Standard set call after getting stats */ + } + + return ret; +} /* wl_monitor_lq */ + +static int +wl_bcnlenhist(void *wl, cmd_t *cmd, char **argv) +{ + wlc_bcn_len_hist_t *bcnlenhist = NULL; + uint32 *bcns_len = NULL; + char* dump_buf = NULL; + uint32 counter = 0; + int index = 0; + int err = 0; + + UNUSED_PARAMETER(cmd); + + dump_buf = malloc(WLC_IOCTL_SMLEN); + if (dump_buf == NULL) { + fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WLC_IOCTL_SMLEN); + return -1; + } + memset(dump_buf, 0, WLC_IOCTL_SMLEN); + + if (argv[1]) + err = wlu_iovar_getbuf(wl, "bcnlenhist", argv[1], 1, dump_buf, WLC_IOCTL_SMLEN); + else + err = wlu_iovar_getbuf(wl, "bcnlenhist", NULL, 0, dump_buf, WLC_IOCTL_SMLEN); + + if (BCME_OK == err) { + bcnlenhist = (wlc_bcn_len_hist_t *)dump_buf; + + index = bcnlenhist->cur_index; + counter = bcnlenhist->ringbuff_len; + bcns_len = bcnlenhist->bcnlen_ring; + + index--; + printf("LAST %d BEACON LENGTH's: ", counter); + for (; counter--; index--) { + if (index < 0) + index = bcnlenhist->ringbuff_len - 1; + printf("%d ", bcns_len[index]); + } + + printf("\nMAX BCNLEN: %d\n", bcnlenhist->max_bcnlen); + + if (bcnlenhist->min_bcnlen == (int)0x7fffffff) + printf("MIN BCNLEN: 0\n\n"); + else + printf("MIN BCNLEN: %d\n\n", bcnlenhist->min_bcnlen); + } + + free(dump_buf); + + return err; +} + +static int +wl_dump_networks(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + char *dump_buf, *dump_buf_orig; + uint32 status = 0; + bool iscan = FALSE; + + dump_buf_orig = dump_buf = malloc(WL_DUMP_BUF_LEN); + if (dump_buf == NULL) { + fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", WL_DUMP_BUF_LEN); + return BCME_NOMEM; + } + + iscan = (cmd->get != WLC_SCAN_RESULTS); + if (iscan) { + int buflen = 1920; /* usually fits about 10 BSS infos */ + + if (*(++argv)) { + char *endptr = NULL; + buflen = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + ret = BCME_USAGE_ERROR; + goto exit; + } + } + ret = wl_get_iscan(wl, dump_buf, buflen); + } else + ret = wl_get_scan(wl, WLC_SCAN_RESULTS, dump_buf, WL_DUMP_BUF_LEN); + + if (ret == 0) { + if (iscan) { + status = dtoh32(((wl_iscan_results_t *)dump_buf)->status); + dump_buf += OFFSETOF(wl_iscan_results_t, results); + } + dump_networks(dump_buf); + if (iscan) { + switch (status) { + case WL_SCAN_RESULTS_PARTIAL: + printf("iscanresults incomplete\n"); + break; + case WL_SCAN_RESULTS_SUCCESS: + printf("iscanresults complete\n"); + break; + case WL_SCAN_RESULTS_PENDING: + printf("iscanresults pending\n"); + break; + case WL_SCAN_RESULTS_ABORTED: + printf("iscanresults aborted\n"); + break; + default: + printf("iscanresults returned unknown status %d\n", status); + break; + } + } + } + +exit: + free(dump_buf_orig); + return ret; +} + +static int +wl_dump_chanlist(void *wl, cmd_t *cmd, char **argv) +{ + uint32 chan_buf[WL_NUMCHANNELS + 1]; + wl_uint32_list_t *list; + int ret; + uint i; + + UNUSED_PARAMETER(argv); + + list = (wl_uint32_list_t *)(void *)chan_buf; + list->count = htod32(WL_NUMCHANNELS); + ret = wlu_get(wl, cmd->get, chan_buf, sizeof(chan_buf)); + if (ret < 0) + return ret; + + for (i = 0; i < dtoh32(list->count); i++) + printf("%d ", dtoh32(list->element[i])); + printf("\n"); + return ret; +} + +static int +wl_cur_mcsset(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + memset(buf, 0, WLC_IOCTL_SMLEN); + ret = wlu_iovar_get(wl, "cur_mcsset", &buf[0], MCSSET_LEN); + if (ret < 0) + return ret; + + wl_print_mcsset(buf); + + return ret; +} + +/* Dump chanspecs based on the driver's current configuration of band, band-width & locale. */ +static int +wl_dump_chanspecs_defset(void *wl, cmd_t *cmd, char **argv) +{ + const char* fn_name = "wl_dump_chanspecs_defset"; + wl_uint32_list_t *list; + int ret, buflen; + chanspec_t c = 0; + uint i; + int err; + char chspec_str[CHANSPEC_STR_LEN]; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + memset(buf, 0, WLC_IOCTL_MAXLEN); + + strcpy(buf, "chanspecs_defset"); + buflen = strlen(buf) + 1; + + /* toss the command name */ + argv++; + + /* Validate arguments if any */ + if (*argv) { + fprintf(stderr, + "%s: This IOVAR doesn't take any arguments.\n", fn_name); + err = BCME_USAGE_ERROR; + goto exit; + } + + /* Add list */ + list = (wl_uint32_list_t *)(buf + buflen); + list->count = htod32(WL_NUMCHANSPECS); + buflen += sizeof(uint32)*(WL_NUMCHANSPECS + 1); + + ret = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen); + if (ret < 0) + return ret; + + list = (wl_uint32_list_t *)buf; + for (i = 0; i < dtoh32(list->count); i++) { + c = (chanspec_t)dtoh32(list->element[i]); + wf_chspec_ntoa(c, chspec_str); + printf("%s (0x%04x)\n", chspec_str, c); + } + printf("\n"); + return ret; + + exit: + return err; +} + +static int +wl_dump_chanspecs(void *wl, cmd_t *cmd, char **argv) +{ + miniopt_t to; + const char* fn_name = "wl_dump_chanspecs"; + wl_uint32_list_t *list; + chanspec_t c = 0, *chanspec; + int ret, buflen; + uint i; + int err, opt_err; + bool band_set = FALSE, bw_set = FALSE; + char abbrev[WLC_CNTRY_BUF_SZ] = ""; /* default.. current locale */ + char chspec_str[CHANSPEC_STR_LEN]; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + memset(buf, 0, WLC_IOCTL_MAXLEN); + + /* multiple commands are using this API to dump a channel list: + * chanspecs + * roam_channels_in_cache + * roam_channels_in_hotlist + */ + strcpy(buf, cmd->name); + buflen = strlen(buf) + 1; + + /* toss the command name */ + argv++; + + /* Validate arguments if any */ + if (*argv) { + miniopt_init(&to, fn_name, NULL, FALSE); + while ((opt_err = miniopt(&to, argv)) != -1) { + if (opt_err == 1) { + err = BCME_USAGE_ERROR; + goto exit; + } + argv += to.consumed; + + if (to.opt == 'b') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for band\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val != 5) && (to.val != 2)) { + fprintf(stderr, + "%s: invalid band %d\n", + fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + if (to.val == 5) + c |= WL_CHANSPEC_BAND_5G; + else + c |= WL_CHANSPEC_BAND_2G; + band_set = TRUE; + } + if (to.opt == 'w') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for" + " bandwidth\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val != 20) && (to.val != 40) && (to.val != 80)) { + fprintf(stderr, + "%s: invalid bandwidth %d\n", + fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + if (to.val == 20) + c |= WL_CHANSPEC_BW_20; + else if (to.val == 40) + c |= WL_CHANSPEC_BW_40; + else { + if (ioctl_version == 1) { + fprintf(stderr, + "%s: bandwidth 80 MHz is not supported by " + "this version driver.\n", + fn_name); + err = BCME_USAGE_ERROR; + goto exit; + + } + c |= WL_CHANSPEC_BW_80; + } + + bw_set = TRUE; + } + if (to.opt == 'c') { + if (!to.valstr) { + fprintf(stderr, + "%s: please provide country abbrev \n", fn_name); + err = BCME_USAGE_ERROR; + goto exit; + } + strncpy(abbrev, to.valstr, WLC_CNTRY_BUF_SZ - 1); + abbrev[WLC_CNTRY_BUF_SZ - 1] = '\0'; + } + } + if (!bw_set || !band_set) { + if (!band_set) + fprintf(stderr, "%s: you need to set a band, '-b <5|2>'\n", + fn_name); + if (!bw_set) + fprintf(stderr, + "%s: you need to set a bandwidth, '-w <20|40|80>'\n", + fn_name); + err = BCME_USAGE_ERROR; + goto exit; + } + } + + /* convert chanspec to legacy if needed */ + if (c != 0) { + c = wl_chspec_to_driver(c); + if (c == INVCHANSPEC) { + err = BCME_USAGE_ERROR; + goto exit; + } + } + + /* Add chanspec argument */ + chanspec = (chanspec_t *) (buf + buflen); + *chanspec = c; + buflen += (sizeof(chanspec_t)); + + /* Add country abbrev */ + strncpy(buf + buflen, abbrev, WLC_CNTRY_BUF_SZ); + buflen += WLC_CNTRY_BUF_SZ; + + /* Add list */ + list = (wl_uint32_list_t *)(buf + buflen); + list->count = htod32(WL_NUMCHANSPECS); + buflen += sizeof(uint32)*(WL_NUMCHANSPECS + 1); + + ret = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen); + if (ret < 0) + return ret; + + list = (wl_uint32_list_t *)buf; + for (i = 0; i < dtoh32(list->count); i++) { + c = wl_chspec32_from_driver(list->element[i]); + wf_chspec_ntoa(c, chspec_str); + printf("%s (0x%04x)\n", chspec_str, c); + } + printf("\n"); + return ret; + +exit: + return err; +} + +static int +wl_channels_in_country(void *wl, cmd_t *cmd, char **argv) +{ + wl_channels_in_country_t *cic; + int ret; + uint i, len; + + cic = (wl_channels_in_country_t *)buf; + cic->buflen = WLC_IOCTL_MAXLEN; + cic->count = 0; + + /* country abbrev must follow */ + if (!*++argv) { + fprintf(stderr, "missing country abbrev\n"); + return BCME_USAGE_ERROR; + } + + len = strlen(*argv); + if ((len > 3) || (len < 2)) { + fprintf(stderr, "invalid country abbrev: %s\n", *argv); + return BCME_BADARG; + } + + strcpy(cic->country_abbrev, *argv); + + /* band must follow */ + if (!*++argv) { + fprintf(stderr, "missing band\n"); + return BCME_USAGE_ERROR; + } + + if (!stricmp(*argv, "a")) + cic->band = WLC_BAND_5G; + else if (!stricmp(*argv, "b")) + cic->band = WLC_BAND_2G; + else { + fprintf(stderr, "unsupported band: %s\n", *argv); + return BCME_UNSUPPORTED; + } + + cic->buflen = htod32(cic->buflen); + cic->band = htod32(cic->band); + cic->count = htod32(cic->count); + ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN); + if (ret < 0) + return ret; + + for (i = 0; i < dtoh32(cic->count); i++) + printf("%d ", dtoh32(cic->channel[i])); + printf("\n"); + + return ret; +} + +int +wl_get_scan(void *wl, int opc, char *scan_buf, uint buf_len) +{ + wl_scan_results_t *list = (wl_scan_results_t*)scan_buf; + int ret; + + list->buflen = htod32(buf_len); + ret = wlu_get(wl, opc, scan_buf, buf_len); + if (ret < 0) + return ret; + ret = 0; + + list->buflen = dtoh32(list->buflen); + list->version = dtoh32(list->version); + list->count = dtoh32(list->count); + if (list->buflen == 0) { + list->version = 0; + list->count = 0; + } else if (list->version != WL_BSS_INFO_VERSION && + list->version != LEGACY2_WL_BSS_INFO_VERSION && + list->version != LEGACY_WL_BSS_INFO_VERSION) { + fprintf(stderr, "Sorry, your driver has bss_info_version %d " + "but this program supports only version %d.\n", + list->version, WL_BSS_INFO_VERSION); + list->buflen = 0; + list->count = 0; + } + + return ret; +} + +static int +wl_get_iscan(void *wl, char *scan_buf, uint buf_len) +{ + wl_iscan_results_t list; + wl_scan_results_t *results; + int ret; + + memset(&list, '\0', sizeof(list)); + list.results.buflen = htod32(buf_len); + ret = wlu_iovar_getbuf(wl, "iscanresults", &list, WL_ISCAN_RESULTS_FIXED_SIZE, + scan_buf, WLC_IOCTL_MAXLEN); + + if (ret < 0) + return ret; + + ret = 0; + + results = &((wl_iscan_results_t*)scan_buf)->results; + results->buflen = dtoh32(results->buflen); + results->version = dtoh32(results->version); + results->count = dtoh32(results->count); + if (results->buflen == 0) { + printf("wl_get_iscan buflen 0\n"); + results->version = 0; + results->count = 0; + } else if (results->version != WL_BSS_INFO_VERSION && + results->version != LEGACY2_WL_BSS_INFO_VERSION && + results->version != LEGACY_WL_BSS_INFO_VERSION) { + fprintf(stderr, "Sorry, your driver has bss_info_version %d " + "but this program supports only version %d.\n", + results->version, WL_BSS_INFO_VERSION); + results->buflen = 0; + results->count = 0; + } + + return ret; +} + +static int +wl_spect(void *wl, cmd_t *cmd, char **argv) +{ + int ret, spect; + char *endptr = NULL; + + if (!*++argv) { + if ((ret = wlu_get(wl, cmd->get, &spect, sizeof(spect))) < 0) { + return ret; + } + + spect = dtoh32(spect); + switch (spect) { + case SPECT_MNGMT_OFF: + printf("Off\n"); + break; + + case SPECT_MNGMT_LOOSE_11H: + printf("Loose interpretation of 11h spec - may join non 11h AP.\n"); + break; + + case SPECT_MNGMT_STRICT_11H: + printf("Strict interpretation of 11h spec - may not join non 11h AP.\n"); + break; + + case SPECT_MNGMT_STRICT_11D: + printf("802.11d mode\n"); + break; + + case SPECT_MNGMT_LOOSE_11H_D: + printf("Loose interpretation of 11h+d spec - may join non-11h APs\n"); + break; + + default: + printf("invalid value 0x%x\n", spect); + return BCME_BADARG; + } + return (0); + } else { + spect = strtol(*argv, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + if (spect < SPECT_MNGMT_OFF || spect > SPECT_MNGMT_LOOSE_11H_D) + return BCME_BADARG; + + spect = htod32(spect); + return wlu_set(wl, cmd->set, &spect, sizeof(spect)); + } +} + +static int +wl_status(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + struct ether_addr bssid; + wlc_ssid_t ssid; + char ssidbuf[SSID_FMT_BUF_LEN]; + wl_bss_info_t *bi; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + if ((ret = wlu_get(wl, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) == 0) { + /* The adapter is associated. */ + *(uint32*)buf = htod32(WLC_IOCTL_MAXLEN); + if ((ret = wlu_get(wl, WLC_GET_BSS_INFO, buf, WLC_IOCTL_MAXLEN)) < 0) + return ret; + + bi = (wl_bss_info_t*)(buf + 4); + if (dtoh32(bi->version) == WL_BSS_INFO_VERSION || + dtoh32(bi->version) == LEGACY2_WL_BSS_INFO_VERSION || + dtoh32(bi->version) == LEGACY_WL_BSS_INFO_VERSION) + dump_bss_info(bi); + else + fprintf(stderr, "Sorry, your driver has bss_info_version %d " + "but this program supports only version %d.\n", + bi->version, WL_BSS_INFO_VERSION); + } else { + printf("Not associated. Last associated with "); + + if ((ret = wlu_get(wl, WLC_GET_SSID, &ssid, sizeof(wlc_ssid_t))) < 0) { + printf("\n"); + return ret; + } + + wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); + printf("SSID: \"%s\"\n", ssidbuf); + } + + return 0; +} + +static int +wl_deauth_rc(void *wl, cmd_t *cmd, char **argv) +{ + scb_val_t scb_val; + int ret; + + if (!*++argv) { + fprintf(stderr, "STA MAC not specified, deauth all\n"); + ret = wlu_set(wl, WLC_SCB_DEAUTHENTICATE, (void *)ðer_bcast, + ETHER_ADDR_LEN); + return ret; + + } else if (!wl_ether_atoe(*argv, &scb_val.ea)) { + fprintf(stderr, "Malformed STA MAC parameter\n"); + ret = BCME_USAGE_ERROR; + + } else if (!*++argv) { + /* No reason code furnished, so driver will use its default */ + ret = wlu_set(wl, WLC_SCB_DEAUTHENTICATE, &scb_val.ea, + ETHER_ADDR_LEN); + + } else { + scb_val.val = htod32((uint32)strtoul(*argv, NULL, 0)); + ret = wlu_set(wl, cmd->set, &scb_val, sizeof(scb_val)); + } + return ret; +} + +static int +wl_wpa_auth(void *wl, cmd_t *cmd, char **argv) +{ + int bsscfg_idx = 0; + int consumed; + int wpa_auth = 0; + int ret = 0; + int i; + static struct { + int val; + const char *name; + } auth_mode[] = + /* Keep the numeric values in the staticly initialized + * help string consistent. Unfortunately, there isn't + * an automatic way for that. + */ + {{WPA_AUTH_NONE, "WPA-NONE"}, + {WPA_AUTH_UNSPECIFIED, "WPA-802.1x"}, + {WPA_AUTH_PSK, "WPA-PSK"}, +#ifdef BCMCCX + {WPA_AUTH_CCKM, "CCKM(WPA)"}, + {WPA2_AUTH_CCKM, "CCKM(WPA2)"}, +#endif /* BCMCCX */ + {WPA2_AUTH_UNSPECIFIED, "WPA2-802.1x"}, + {WPA2_AUTH_PSK, "WPA2-PSK"}, +#ifdef BCMWAPI_WAI + {WAPI_AUTH_UNSPECIFIED, "WAPI-AS"}, + {WAPI_AUTH_PSK, "WAPI-PSK"}, +#endif /* BCMWAPI_WAI */ + {WPA2_AUTH_FT, "FT"}, + {WPA_AUTH_DISABLED, "disabled"}}; + + /* skip the command name */ + argv++; + + /* parse a bsscfg_idx option if present */ + if ((ret = wl_cfg_option(argv, cmd->name, &bsscfg_idx, &consumed)) != 0) + return ret; + + argv += consumed; + + if (!*argv) { + /* no arg, so this is a GET. */ + + if (!consumed) + ret = wlu_iovar_getint(wl, "wpa_auth", &wpa_auth); + else + ret = wl_bssiovar_getint(wl, "wpa_auth", bsscfg_idx, &wpa_auth); + + if (ret < 0) + return ret; + + /* Show all AKM suites enabled */ + printf("0x%x", wpa_auth); + + if (wpa_auth == WPA_AUTH_DISABLED) + printf(" Disabled"); + + for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) { + if (wpa_auth & auth_mode[i].val) + printf(" %s", auth_mode[i].name); + } + + printf("\n"); + return ret; + + + } else { + /* there's an arg, so this is a SET. */ + ret = 1; + + /* Validate the user input range */ + if (isdigit((int)*argv[0])) { + unsigned int range = 0; + + /* param is a number; look for value in the list */ + wpa_auth = strtoul(*argv, NULL, 0); + + /* Validate the user input range */ + + for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) + range |= auth_mode[i].val; + + range = (~range) & 0xFFFF; + + if (range & wpa_auth) { + ret = 1; + goto usage; + } else { + ret = 0; + } + + } else { + + int arg_count = 0; + char** p_argv; + int j = 0; + unsigned int range = 0; + + wpa_auth = 0; + p_argv = argv; + + for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) + range |= auth_mode[i].val; + + range = (~range) & (0xFFFF); + + while (*p_argv) { + arg_count++; + p_argv++; + } + + p_argv = argv; + + for (j = 0; j < arg_count; j++) { + bool found = FALSE; + + argv = p_argv + j; + + /* treat param as string to be matched in list */ + for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) { + if (!stricmp(auth_mode[i].name, *argv)) { + + found = TRUE; + wpa_auth |= auth_mode[i].val; + ret = 0; + + /* traverse the list */ + argv++; + if (!*argv) + break; + } + } + + if ((found == FALSE) || (range & wpa_auth)) + goto usage; + } + + } + if (ret) + fprintf(stderr, "%s is not a valid WPA auth mode\n", *argv); + else { + if (!consumed) + ret = wlu_iovar_setint(wl, "wpa_auth", wpa_auth); + else + ret = wl_bssiovar_setint(wl, "wpa_auth", bsscfg_idx, wpa_auth); + } + } + + return ret; + +usage: + fprintf(stderr, "Inavlid user argument.\n"); + fprintf(stderr, "Values may be a bitvector or list of names from the set.\n"); + + for (i = 0; i < (int)ARRAYSIZE(auth_mode); i++) { + fprintf(stderr, "\n0x%04x %s", auth_mode[i].val, auth_mode[i].name); + } + + printf("\n"); + return ret; +} + +static int +wl_set_pmk(void *wl, cmd_t *cmd, char **argv) +{ + wsec_pmk_t psk; + size_t key_len; + + if (!*++argv) { + return BCME_USAGE_ERROR; + } + key_len = strlen(*argv); + if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) { + fprintf(stderr, "passphrase must be between %d and %d characters long\n", + WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN); + return BCME_BADARG; + } + psk.key_len = htod16((ushort) key_len); + psk.flags = htod16(WSEC_PASSPHRASE); + memcpy(psk.key, *argv, key_len); + return wlu_set(wl, cmd->set, &psk, sizeof(psk)); +} + +static int +wl_wsec(void *wl, cmd_t *cmd, char **argv) +{ + int wsec; + int bsscfg_idx = 0; + int consumed; + char *endptr = NULL; + int error; + + UNUSED_PARAMETER(cmd); + + argv++; + + /* parse a bsscfg_idx option if present */ + if ((error = wl_cfg_option(argv, "wsec", &bsscfg_idx, &consumed)) != 0) + return error; + + argv += consumed; + + if (!*argv) { + /* This is a GET */ + if (consumed == 0) { + error = wlu_get(wl, WLC_GET_WSEC, &wsec, sizeof(uint32)); + wsec = dtoh32(wsec); + } + else + error = wl_bssiovar_getint(wl, "wsec", bsscfg_idx, &wsec); + + if (!error) + wl_printint(wsec); + } else { + /* This is a SET */ + if (!stricmp(*argv, "off")) + wsec = 0; + else { + wsec = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + } + + if (consumed == 0) { + wsec = htod32(wsec); + error = wlu_set(wl, WLC_SET_WSEC, &wsec, sizeof(uint32)); + } + else + error = wl_bssiovar_setint(wl, "wsec", bsscfg_idx, wsec); + } + + return error; +} + +static int +parse_wep(char **argv, wl_wsec_key_t *key, bool options) +{ + char hex[] = "XX"; + unsigned char *data = key->data; + char *keystr = *argv; + + switch (strlen(keystr)) { + case 5: + case 13: + case 16: + key->len = strlen(keystr); + memcpy(data, keystr, key->len + 1); + break; + case 12: + case 28: + case 34: + case 66: + /* strip leading 0x */ + if (!strnicmp(keystr, "0x", 2)) + keystr += 2; + else + return -1; + /* fall through */ + case 10: + case 26: + case 32: + case 64: + key->len = strlen(keystr) / 2; + while (*keystr) { + strncpy(hex, keystr, 2); + *data++ = (char) strtoul(hex, NULL, 16); + keystr += 2; + } + break; + default: + return -1; + } + + switch (key->len) { + case 5: + key->algo = CRYPTO_ALGO_WEP1; + break; + case 13: + key->algo = CRYPTO_ALGO_WEP128; + break; + case 16: + /* default to AES-CCM */ + key->algo = CRYPTO_ALGO_AES_CCM; + break; + case 32: + key->algo = CRYPTO_ALGO_TKIP; + break; + default: + return -1; + } + + /* Set as primary key by default */ + key->flags |= WL_PRIMARY_KEY; + + if (options) { + /* Get options */ + while (*++argv) { + if (!strnicmp("ccm", *argv, 3) && key->len == 16) + key->algo = CRYPTO_ALGO_AES_CCM; +#ifdef BCMWAPI_WPI + else if (!strnicmp("wapi", *argv, 4) && key->len == 32) + key->algo = CRYPTO_ALGO_SMS4; +#endif /* BCMWAPI_WPI */ + else if (!strnicmp("ocb", *argv, 3) && key->len == 16) + key->algo = CRYPTO_ALGO_AES_OCB_MPDU; + else if (!strnicmp("notx", *argv, 4)) + key->flags &= ~WL_PRIMARY_KEY; + else if (!wl_ether_atoe(*argv, &key->ea)) + memset(&key->ea, 0, ETHER_ADDR_LEN); + } + } + + return 0; +} + +static int +wl_primary_key(void *wl, cmd_t *cmd, char **argv) +{ + int i, val, ret = 0; + + if (!*++argv) { + i = 0; + do { + val = htod32(i); + if ((ret = wlu_get(wl, cmd->get, &val, sizeof(val))) < 0) { + return ret; + } + if (dtoh32(val)) { + printf("Key %d is primary\n", i); + return 0; + } + } while (++i < DOT11_MAX_DEFAULT_KEYS); + printf("No primary key set\n"); + + } else { + val = htod32(atoi(*argv)); + ret = wlu_set(wl, cmd->set, &val, sizeof(val)); + } + return ret; +} + +static int +wl_addwep(void *wl, cmd_t *cmd, char **argv) +{ + wl_wsec_key_t key; + int bsscfg_idx = 0; + int consumed; + int error; + + memset(&key, 0, sizeof(key)); + + argv++; + + /* parse a bsscfg_idx option if present */ + if ((error = wl_cfg_option(argv, "addwep", &bsscfg_idx, &consumed)) != 0) + return error; + + argv += consumed; + + /* GET operation not allowed */ + if (!*argv) + return BCME_USAGE_ERROR; + + key.index = atoi(*argv++); + + if (!*argv) { + fprintf(stderr, "No key specified\n"); + return BCME_USAGE_ERROR; + } + if (parse_wep(argv, &key, TRUE)) + return BCME_BADARG; + + key.index = htod32(key.index); + key.len = htod32(key.len); + key.algo = htod32(key.algo); + key.flags = htod32(key.flags); + + if (consumed == 0) { + error = wlu_set(wl, cmd->set, &key, sizeof(key)); + } else { + error = wlu_bssiovar_setbuf(wl, "wsec_key", bsscfg_idx, + &key, sizeof(key), buf, WLC_IOCTL_MAXLEN); + } + + return error; +} + +static int +wl_rmwep(void *wl, cmd_t *cmd, char **argv) +{ + wl_wsec_key_t key; + int bsscfg_idx = 0; + int consumed; + int error; + + memset(&key, 0, sizeof(key)); + + argv++; + + /* parse a bsscfg_idx option if present */ + if ((error = wl_cfg_option(argv, "rmwep", &bsscfg_idx, &consumed)) != 0) + return error; + + argv += consumed; + + /* GET operation not allowed */ + if (!*argv) + return BCME_USAGE_ERROR; + + key.index = htod32(atoi(*argv++)); + + if (*argv) { + if (!(wl_ether_atoe(*argv, &key.ea))) + return BCME_USAGE_ERROR; + } + + if (consumed == 0) { + error = wlu_set(wl, cmd->set, &key, sizeof(key)); + } else { + error = wlu_var_setbuf(wl, "wsec_key", &key, sizeof(key)); + } + + return error; +} + +static struct { + uint value; + const char *string; +} wsec_test[] = { + {WSEC_GEN_MIC_ERROR, "mic_error"}, + {WSEC_GEN_REPLAY, "replay"}, + {WSEC_GEN_ICV_ERROR, "icv_error"}, + {WSEC_GEN_MFP_ACT_ERROR, "act_error"}, + {WSEC_GEN_MFP_DISASSOC_ERROR, "disassoc_error"}, + {WSEC_GEN_MFP_DEAUTH_ERROR, "deauth_error"}, + {0, NULL} +}; + + +static int +wl_wsec_test(void *wl, cmd_t *cmd, char **argv) +{ + wl_wsec_key_t *key; + int i, len; + char *endptr = NULL, *wsec_buf = NULL; + uint32 val, last_val; + int err = 0; + + if (!*++argv) { + err = BCME_USAGE_ERROR; + goto usage; + } + + val = strtol(*argv, &endptr, 0); + if (endptr == *argv) { + /* the value string was not parsed by strtol */ + for (i = 0; wsec_test[i].value; i++) + if (stricmp(wsec_test[i].string, *argv) == 0) { + val = wsec_test[i].value; + break; + } + if (wsec_test[i].value == 0) { + err = BCME_BADARG; + goto usage; + } + } + ++argv; + + switch (val) { + case WSEC_GEN_REPLAY: + case WSEC_GEN_MIC_ERROR: + case WSEC_GEN_ICV_ERROR: + case WSEC_GEN_MFP_ACT_ERROR: + case WSEC_GEN_MFP_DISASSOC_ERROR: + case WSEC_GEN_MFP_DEAUTH_ERROR: + if (!*argv) { + fprintf(stderr, "insufficient arguments\n"); + return BCME_USAGE_ERROR; + } + len = sizeof(wl_wsec_key_t) + 4; + wsec_buf = malloc(len); + if (wsec_buf == NULL) { + fprintf(stderr, "Error allocating memory failed for wsec_buf"); + return BCME_NOMEM; + } + *(uint32 *)wsec_buf = htod32(val); + key = (wl_wsec_key_t *)&wsec_buf[4]; + memset(key, 0, sizeof(wl_wsec_key_t)); + /* If it doesn't look like an ether addr, suppose it's a key index */ + if (!(wl_ether_atoe(*argv, &key->ea))) { + memset(&key->ea, 0, ETHER_ADDR_LEN); + key->index = htod32(atoi(*argv)); + } + break; + default: + goto usage; + } + + err = wlu_set(wl, cmd->set, wsec_buf, len); + free(wsec_buf); + goto exit; + +usage: + fprintf(stderr, "wsec test_type may be a number or name from the following set:"); + last_val = 0xffffffff; + for (i = 0; (val = wsec_test[i].value); i++) { + if (val != last_val) + fprintf(stderr, "\n0x%04x %s", val, wsec_test[i].string); + else + fprintf(stderr, ", %s", wsec_test[i].string); + last_val = val; + } + fprintf(stderr, "\n"); + +exit: + return err; +} + +static int +wl_keys(void *wl, cmd_t *cmd, char **argv) +{ + uint i, j; + union { + int index; + wl_wsec_key_t key; + } u; + int wep_is_on = 0; + const char *addr; + int ret = BCME_OK; + + UNUSED_PARAMETER(argv); + + if (wlu_iovar_getint(wl, "wsec", &wep_is_on) < 0) + fprintf(stderr, "Could not query wsec status.\n"); + + for (i = 0; i < 256; i++) { + memset(&u, 0, sizeof(u)); + u.index = htod32(i); + ret = wlu_get(wl, cmd->get, &u, sizeof(u)); + if (ret == BCME_IOCTL_ERROR) { + int bcmerr; + if (wlu_iovar_getint(wl, "bcmerror", &bcmerr) >= 0 && + (bcmerr == BCME_BADKEYIDX)) { + ret = BCME_OK; + } + } + + if (ret != BCME_OK) + break; + + /* ignore empty keys */ + if (dtoh32(u.key.algo) == CRYPTO_ALGO_OFF || (u.key.len == 0)) + continue; + + if (ETHER_ISNULLADDR(&u.key.ea)) + addr = "(default)"; + else + addr = wl_ether_etoa(&u.key.ea); + + printf("%3d: %-17s Key %d: %s ", i, addr, dtoh32(u.key.index), + bcm_crypto_algo_name(dtoh32(u.key.algo))); + + if (wep_is_on && dtoh32(u.key.flags) & WL_PRIMARY_KEY) + printf("*"); + printf("\t"); + + if (dtoh32(u.key.len) == 0) + printf("No key present"); + else { + if (dtoh32(u.key.flags) & WL_SOFT_KEY) + printf("soft "); + printf("len %d, data 0x", dtoh32(u.key.len)); + for (j = 0; j < dtoh32(u.key.len); j++) + printf("%02X", u.key.data[j]); + + for (j = 0; j < dtoh32(u.key.len); j++) + if (!isprint(u.key.data[j])) + break; + if (j == dtoh32(u.key.len)) + printf(" (%.*s)", (int)dtoh32(u.key.len), u.key.data); + + } + + printf("\n"); + } + + return ret; +} + +static int +wl_tsc(void *wl, cmd_t *cmd, char **argv) +{ + union { + int32 index; + uint8 tsc[DOT11_WPA_KEY_RSC_LEN]; + } u; + uint32 hi, lo; + int idx, ret; + + if (!*++argv) + return BCME_USAGE_ERROR; + idx = atoi(*argv); + if (idx < 0) { + fprintf(stderr, "Key index %d out of range. Should be positive.\n", idx); + return BCME_BADARG; + } + u.index = htod32(idx); + if ((ret = wlu_get(wl, cmd->get, &u, sizeof(u))) < 0) + return ret; + lo = u.tsc[0] | (u.tsc[1] << 8) | (u.tsc[2] << 16) | (u.tsc[3] << 24); + hi = u.tsc[4] | (u.tsc[5] << 8) | (u.tsc[6] << 16) | (u.tsc[7] << 24); + + printf("Key %d TSC: 0x%04x:%08x\n", idx, hi, lo); + return 0; +} + + +static void +wl_txppr_print(ppr_t *ppr, int cck, uint flags) +{ + + switch (ppr_get_ch_bw(ppr)) { + case WL_TX_BW_20: + printf("\n20MHz:\n"); + wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_20); + break; + case WL_TX_BW_40: + printf("\n20 in 40MHz:\n"); + wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_20IN40); + printf("\n40MHz:\n"); + wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_40); + break; + case WL_TX_BW_80: + printf("\n20 in 80MHz:\n"); + wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_20IN80); + printf("\n40 in 80MHz:\n"); + wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_40IN80); + printf("\n80MHz:\n"); + wl_txppr_print_bw(ppr, cck, flags, WL_TX_BW_80); + break; + default: + break; + } + /* MCS32 value is obsoleted */ + /* printf("MCS32 %2d\n", ppr->mcs32); */ + printf("\n"); +} + + +/* get a power value from the opaque ppr structure */ +static int8 wl_ppr_get_pwr(ppr_t* pprptr, reg_rate_index_t rate_idx, wl_tx_bw_t bw) +{ + clm_rate_group_id_t group_id = ppr_table[rate_idx].id; + int8 power = WL_RATE_DISABLED; + switch (ppr_group_table[group_id].rate_type) { + case PPR_RATE_DSSS: + { + ppr_dsss_rateset_t rateset; + ppr_get_dsss(pprptr, bw, ppr_group_table[group_id].chain, &rateset); + power = rateset.pwr[rate_idx-ppr_group_table[group_id].first_rate]; + } + break; + case PPR_RATE_OFDM: + { + ppr_ofdm_rateset_t rateset; + ppr_get_ofdm(pprptr, bw, ppr_group_table[group_id].mode, + ppr_group_table[group_id].chain, &rateset); + power = rateset.pwr[rate_idx-ppr_group_table[group_id].first_rate]; + } + break; + case PPR_RATE_HT: + { + ppr_ht_mcs_rateset_t rateset; + ppr_get_ht_mcs(pprptr, bw, ppr_group_table[group_id].nss, + ppr_group_table[group_id].mode, + ppr_group_table[group_id].chain, &rateset); + power = rateset.pwr[rate_idx-ppr_group_table[group_id].first_rate]; + } + break; + case PPR_RATE_VHT: + { + ppr_vht_mcs_rateset_t rateset; + ppr_get_vht_mcs(pprptr, bw, ppr_group_table[group_id].nss, + ppr_group_table[group_id].mode, + ppr_group_table[group_id].chain, &rateset); + power = rateset.pwr[rate_idx-ppr_group_table[group_id].first_rate]; + } + break; + default: + break; + } + + return power; +} + + +#define PRINT_PPR_RATE_LOOP(idx, len, rates) \ + for (idx = 0; idx < len; idx++) { \ + if (rates[idx] == WL_RATE_DISABLED) \ + printf(" -"); \ + else \ + printf(" %2d", rates[idx]); \ + } + +/* print power offset for for a given bandwidth */ +static void +wl_txppr_print_bw(ppr_t *ppr, int cck, uint flags, wl_tx_bw_t bw) +{ + uint i, j, rlen; + uint n = WL_NUM_2x2_ELEMENTS; + uint offset = 0; + int8 *ptr, *vhtptr; + const char *str = ""; + bool siso = ((flags & WL_TX_POWER_F_MIMO) == 0); + bool vht = ((flags & WL_TX_POWER_F_VHT) != 0); + ppr_ofdm_rateset_t ofdm_rate; + ppr_vht_mcs_rateset_t vhtrate; + + if (!siso) { + offset = n = WL_NUM_3x3_ELEMENTS; + } + + if (cck) { + ppr_dsss_rateset_t rate; + ppr_get_dsss(ppr, bw, WL_TX_CHAINS_1, &rate); + printf("CCK "); + PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_DSSS, rate.pwr); + if (!siso) { + ppr_get_dsss(ppr, bw, WL_TX_CHAINS_2, &rate); + printf("\nCCK CDD 1x2 "); + PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_DSSS, rate.pwr); + ppr_get_dsss(ppr, bw, WL_TX_CHAINS_3, &rate); + printf("\nCCK CDD 1x3 "); + PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_DSSS, rate.pwr); + } + } + ppr_get_ofdm(ppr, bw, WL_TX_MODE_NONE, WL_TX_CHAINS_1, &ofdm_rate); + printf("\nOFDM "); + PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_OFDM, ofdm_rate.pwr); + ppr_get_ofdm(ppr, bw, WL_TX_MODE_CDD, WL_TX_CHAINS_2, &ofdm_rate); + printf("\nOFDM-CDD "); + PRINT_PPR_RATE_LOOP(j, WL_RATESET_SZ_OFDM, ofdm_rate.pwr); + printf("\n"); + for (i = 0; i < n; i++) { + wl_tx_nss_t nss; + wl_tx_mode_t mode; + wl_tx_chains_t chains; + switch (i + offset) { + case 0: + str = "MCS-SISO "; + nss = WL_TX_NSS_1; + mode = WL_TX_MODE_NONE; + chains = WL_TX_CHAINS_1; + ptr = vhtrate.pwr; + vhtptr = NULL; + break; + case 1: + str = "MCS-CDD "; + nss = WL_TX_NSS_1; + mode = WL_TX_MODE_CDD; + chains = WL_TX_CHAINS_2; + ptr = vhtrate.pwr; + vhtptr = NULL; + break; + case 2: + str = "MCS STBC "; + nss = WL_TX_NSS_1; + mode = WL_TX_MODE_STBC; + chains = WL_TX_CHAINS_2; + ptr = vhtrate.pwr; + vhtptr = NULL; + break; + case 3: + str = "MCS 8~15 "; + nss = WL_TX_NSS_2; + mode = WL_TX_MODE_NONE; + chains = WL_TX_CHAINS_2; + ptr = vhtrate.pwr; + vhtptr = NULL; + break; + case 4: + case 5: + ptr = NULL; + vhtptr = NULL; + break; + case 6: + str = "1 Nsts 1 Tx"; + nss = WL_TX_NSS_1; + mode = WL_TX_MODE_NONE; + chains = WL_TX_CHAINS_1; + ptr = vhtrate.pwr; + vhtptr = &vhtrate.pwr[8]; + break; + case 7: + str = "1 Nsts 2 Tx"; + nss = WL_TX_NSS_1; + mode = WL_TX_MODE_CDD; + chains = WL_TX_CHAINS_2; + ptr = vhtrate.pwr; + vhtptr = &vhtrate.pwr[8]; + break; + case 8: + str = "1 Nsts 3 Tx"; + nss = WL_TX_NSS_1; + mode = WL_TX_MODE_CDD; + chains = WL_TX_CHAINS_3; + ptr = vhtrate.pwr; + vhtptr = &vhtrate.pwr[8]; + break; + case 9: + str = "2 Nsts 2 Tx"; + nss = WL_TX_NSS_2; + mode = WL_TX_MODE_NONE; + chains = WL_TX_CHAINS_2; + ptr = vhtrate.pwr; + vhtptr = &vhtrate.pwr[8]; + break; + case 10: + str = "2 Nsts 3 Tx"; + nss = WL_TX_NSS_2; + mode = WL_TX_MODE_NONE; + chains = WL_TX_CHAINS_3; + ptr = vhtrate.pwr; + vhtptr = &vhtrate.pwr[8]; + break; + case 11: + str = "3 Nsts 3 Tx"; + nss = WL_TX_NSS_3; + mode = WL_TX_MODE_NONE; + chains = WL_TX_CHAINS_3; + ptr = vhtrate.pwr; + vhtptr = &vhtrate.pwr[8]; + break; + default: + ptr = NULL; + vhtptr = NULL; + break; + } + if (ptr == NULL) + continue; + ppr_get_vht_mcs(ppr, bw, nss, mode, chains, &vhtrate); + printf("%s ", str); + if (vht && vhtptr) + rlen = WL_RATESET_SZ_VHT_MCS; + else + rlen = WL_RATESET_SZ_HT_MCS; + PRINT_PPR_RATE_LOOP(j, rlen, ptr); + printf("\n"); + } +} + +static int +wl_get_current_txppr(void *wl, cmd_t *cmd, char **argv) +{ + int err; + uint flags; + chanspec_t chanspec; + char chanspec_str[CHANSPEC_STR_LEN]; + uint pprsize = ppr_ser_size_by_bw(ppr_get_max_bw()); + wl_txppr_t *wl_txppr; + ppr_t *pprptr = NULL; + + wl_txppr = (wl_txppr_t *)malloc(sizeof(*wl_txppr) + pprsize); + + if (wl_txppr == NULL) { + fprintf(stderr, "Error allocating memory failed for curppr"); + return BCME_NOMEM; + } + + memset(wl_txppr, 0, sizeof(*wl_txppr)); + wl_txppr->buflen = pprsize; + if ((err = ppr_init_ser_mem_by_bw(wl_txppr->pprbuf, ppr_get_max_bw(), pprsize)) + != BCME_OK) { + free(wl_txppr); + return err; + } + + if (WLC_IOCTL_MAXLEN < sizeof(wl_txppr_t) + pprsize) { + free(wl_txppr); + return BCME_ERROR; + } + + argv++; + if (*argv) + fprintf(stderr, "Ignoring arguments for %s\n", cmd->name); + + wl_txppr->ver = WL_TXPPR_VERSION; + wl_txppr->len = WL_TXPPR_LENGTH; + if ((err = wlu_iovar_getbuf(wl, "curppr", wl_txppr, sizeof(*wl_txppr) + pprsize, + buf, WLC_IOCTL_MAXLEN)) < 0) { + free(wl_txppr); + return err; + } + + /* the input buffer is no longer needed, output results are in buf */ + free(wl_txppr); + wl_txppr = (wl_txppr_t *)buf; + + /* parse */ + wl_txppr->flags = dtoh32(wl_txppr->flags); + wl_txppr->chanspec = wl_chspec_from_driver(wl_txppr->chanspec); + wl_txppr->local_chanspec = wl_chspec_from_driver(wl_txppr->local_chanspec); + + chanspec = wl_txppr->chanspec; + flags = (wl_txppr->flags & WL_TX_POWER_F_VHT) | + (wl_txppr->flags & WL_TX_POWER_F_HT) | + (wl_txppr->flags & WL_TX_POWER_F_MIMO) | + (wl_txppr->flags & WL_TX_POWER_F_SISO); + + /* dump */ + printf("Current channel:\t %s\n", + wf_chspec_ntoa(wl_txppr->chanspec, chanspec_str)); + printf("BSS channel:\t\t %s\n", + wf_chspec_ntoa(wl_txppr->local_chanspec, chanspec_str)); + printf("Power/Rate Dump (in 1/4dB): Channel %d\n", CHSPEC_CHANNEL(chanspec)); + if ((err = ppr_deserialize_create(NULL, wl_txppr->pprbuf, pprsize, &pprptr)) == BCME_OK) { + wl_txppr_print(pprptr, CHSPEC_IS2G(chanspec), flags); + ppr_delete(NULL, pprptr); + } + return err; +} + +/* This version number must be incremented for every + * modification to the curpower output format. Minor changes + * warrant a decimal point increment. Major (potential + * script-breaking) changes should be met with a major increment. + */ +#define CURPOWER_OUTPUT_FORMAT_VERSION "5.1" + +#define RATE_STR_LEN 64 + +static int +wl_get_current_power(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int mimo; + int i; + chanspec_t chanspec; + char chanspec_str[CHANSPEC_STR_LEN]; + bool verbose = FALSE; + bool brief = FALSE; + int16 power_target; + char rate_str[RATE_STR_LEN]; + int clk; + uint8 *ppr_ser; + size_t pprsize = ppr_ser_size_by_bw(ppr_get_max_bw()); + tx_pwr_rpt_t *ppr_wl = NULL; + + /* firmware will crash if clk = 0 while using curpower */ + if ((err = wlu_get(wl, WLC_GET_CLK, &clk, sizeof(int))) < 0) + return err; + + if (!clk) { + fprintf(stderr, "Error: clock not active, do wl up (if not done already) " + "and force mpc 0 to active clock\n"); + return BCME_ERROR; + } + /* Allocate memory for curpower report structure with 2 ppr data block */ + ppr_wl = (tx_pwr_rpt_t *)malloc(sizeof(tx_pwr_rpt_t) + pprsize*2); + + if (ppr_wl == NULL) { + fprintf(stderr, "Allocating mem failed for curpower\n"); + return BCME_NOMEM; + } + ppr_ser = ppr_wl->pprdata; + + memset(ppr_wl, 0, sizeof(tx_pwr_rpt_t) + pprsize*2); + ppr_wl->board_limit_len = pprsize; + ppr_wl->target_len = pprsize; + ppr_wl->version = TX_POWER_T_VERSION; + /* init allocated mem for serialisation */ + ppr_init_ser_mem_by_bw(ppr_ser, ppr_get_max_bw(), ppr_wl->board_limit_len); + ppr_ser += ppr_wl->board_limit_len; + ppr_init_ser_mem_by_bw(ppr_ser, ppr_get_max_bw(), ppr_wl->target_len); + + + if (argv[1] && (!strcmp(argv[1], "--verbose") || !strcmp(argv[1], "-v"))) { + verbose = TRUE; + argv++; + } + if (argv[1] && (!strcmp(argv[1], "--brief") || !strcmp(argv[1], "-b"))) { + brief = TRUE; + argv++; + } + argv++; + if (*argv) + fprintf(stderr, "Ignoring arguments for %s\n", cmd->name); + + if ((err = wlu_get(wl, cmd->get, ppr_wl, sizeof(tx_pwr_rpt_t) + pprsize*2)) < 0) { + fprintf(stderr, "Error: Curpower failed. "); + fprintf(stderr, "Bring up interface and disable mpc if necessary (wl mpc 0)\n"); + free(ppr_wl); + return err; + } + + /* parse */ + if (ppr_wl->version != TX_POWER_T_VERSION) { + printf("error: version mismatch - driver %d, wl executable was expecting %d\n", + ppr_wl->version, TX_POWER_T_VERSION); + err = BCME_ERROR; + } else { + ppr_t* ppr_board = NULL; + ppr_t* ppr_target = NULL; + ppr_wl->flags = dtoh32(ppr_wl->flags); + ppr_wl->chanspec = wl_chspec_from_driver(ppr_wl->chanspec); + ppr_wl->local_chanspec = wl_chspec_from_driver(ppr_wl->local_chanspec); + + chanspec = ppr_wl->chanspec; + mimo = (ppr_wl->flags & WL_TX_POWER_F_HT) | + (ppr_wl->flags & WL_TX_POWER_F_MIMO) | + (ppr_wl->flags & WL_TX_POWER_F_SISO); + if ((err = ppr_deserialize_create(NULL, ppr_wl->pprdata, ppr_wl->board_limit_len, + &ppr_board)) != BCME_OK) { + goto exit; + } + + if ((err = ppr_deserialize_create(NULL, ppr_ser, ppr_wl->target_len, &ppr_target)) + != BCME_OK) { + goto exit; + } + + /* dump */ + if (verbose) + printf("%-23s%s\n", "Output Format Version:", + CURPOWER_OUTPUT_FORMAT_VERSION); + + printf("%-23s%s, %s\n", "Power Control:", + (ppr_wl->flags & WL_TX_POWER_F_ENABLED) ? "On" : "Off", + (ppr_wl->flags & WL_TX_POWER_F_HW) ? "HW" : "SW"); + printf("%-23s%s\n", "Current Channel:", + wf_chspec_ntoa(ppr_wl->chanspec, chanspec_str)); + printf("%-23s%s\n", "BSS Channel:", + wf_chspec_ntoa(ppr_wl->local_chanspec, chanspec_str)); + printf("%-23s%d.%d dBm\n", "BSS Local Max:", + DIV_QUO(ppr_wl->local_max, 4), DIV_REM(ppr_wl->local_max, 4)); + printf("%-23s%d.%d dB\n", "BSS Local Constraint:", + DIV_QUO(ppr_wl->local_constraint, 4), DIV_REM(ppr_wl->local_constraint, 4)); + printf("%-23s%s\n", "Channel Width:", + ((ppr_wl->channel_bandwidth == WL_BW_20MHZ) ? "20MHz" : + ((ppr_wl->channel_bandwidth == WL_BW_40MHZ) ? "40MHz" : "80MHz"))); + printf("%-23s%d.%d dBm\n", "User Target:", + DIV_QUO(ppr_wl->user_target, 4), DIV_REM(ppr_wl->user_target, 4)); + printf("%-23s%d.%d dB\n", "SROM Antgain 2G:", + DIV_QUO(ppr_wl->antgain[0], 4), DIV_REM(ppr_wl->antgain[0], 4)); + printf("%-23s%d.%d dB\n", "SROM Antgain 5G:", + DIV_QUO(ppr_wl->antgain[1], 4), DIV_REM(ppr_wl->antgain[1], 4)); + printf("%-23s", "SAR:"); + if (ppr_wl->sar != WLC_TXPWR_MAX) + printf("%d.%d dB\n", DIV_QUO(ppr_wl->sar, 4), DIV_REM(ppr_wl->sar, 4)); + else + printf("-\n"); + printf("%-23s", "Open loop:"); + if (ppr_wl->flags & WL_TX_POWER_F_OPENLOOP) + printf("On\n"); + else + printf("Off\n"); + printf("%-23s", "Current rate:"); + wl_rate_print(rate_str, ppr_wl->last_tx_ratespec); + printf("[%s] %s\n", get_reg_rate_string_from_ratespec(ppr_wl->last_tx_ratespec), + rate_str); + printf("\n"); + + printf("Regulatory Limits:\n"); + if (brief) + { + wl_txpwr_regulatory_array_row_print(ppr_wl->clm_limits, + ppr_wl->clm_limits_subchan1, ppr_wl->clm_limits_subchan2, + ppr_wl->channel_bandwidth, + get_reg_rate_index_from_ratespec(ppr_wl->last_tx_ratespec)); + } + else + { + wl_txpwr_regulatory_array_print(ppr_wl->clm_limits, + ppr_wl->clm_limits_subchan1, + ppr_wl->clm_limits_subchan2, ppr_wl->channel_bandwidth, verbose); + } + printf("\n"); + + printf("%-23s%d\n", "Core Index:", ppr_wl->display_core); + printf("Board Limits:\n"); + if (brief) + { + wl_txpwr_array_row_print(ppr_target, ppr_wl->channel_bandwidth, + get_reg_rate_index_from_ratespec(ppr_wl->last_tx_ratespec)); + } + else + { + wl_txpwr_array_print(ppr_board, ppr_wl->channel_bandwidth, verbose, + CHSPEC_IS5G(chanspec)); + printf("\n"); + } + + printf("Power Targets:\n"); + if (brief) + { + wl_txpwr_array_row_print(ppr_target, ppr_wl->channel_bandwidth, + get_reg_rate_index_from_ratespec(ppr_wl->last_tx_ratespec)); + } + else + { + wl_txpwr_array_print(ppr_target, ppr_wl->channel_bandwidth, verbose, + CHSPEC_IS5G(chanspec)); + } + printf("\n"); + + /* print the different power estimate combinations */ + if (mimo) { + printf("Maximum Power Target among all rates:\t"); + for (i = 0; i < ppr_wl->rf_cores; i++) + printf("%2d.%02d ", + DIV_QUO(ppr_wl->tx_power_max[i], 4), + DIV_REM(ppr_wl->tx_power_max[i], 4)); + printf("\n"); + + printf("Last est. power :\t"); + for (i = 0; i < ppr_wl->rf_cores; i++) + printf("%2d.%02d ", + DIV_QUO(ppr_wl->est_Pout[i], 4), + DIV_REM(ppr_wl->est_Pout[i], 4)); + printf("\n"); + + printf("Power Target for the current rate :\t"); + for (i = 0; i < ppr_wl->rf_cores; i++) + { + if (ppr_wl->target_offsets[i] != WL_RATE_DISABLED) + { + power_target = ppr_wl->tx_power_max[i] - + ppr_wl->target_offsets[i]; + /* for ACPHY, clip the power_target if it + is larger than the SAR limit for the + current path. For non-ACPHY or + WLC_SARLIMIT disabled, this threshold is + set to be MAX pwr, ie. 127 + */ + if (power_target > ppr_wl->SARLIMIT[i]) + power_target = ppr_wl->SARLIMIT[i]; + printf("%2d.%02d ", + DIV_QUO(power_target, 4), + DIV_REM(power_target, 4)); + } + else + { + printf("- "); + } + } + printf("\n"); + + printf("Last adjusted est. power :\t"); + for (i = 0; i < ppr_wl->rf_cores; i++) + printf("%2d.%02d ", + DIV_QUO(ppr_wl->est_Pout[i], 4), + DIV_REM(ppr_wl->est_Pout[i], 4)); + printf("\n"); + } else { + printf("Last est. power:\t%2d.%02d dBm\n", + DIV_QUO(ppr_wl->est_Pout[0], 4), + DIV_REM(ppr_wl->est_Pout[0], 4)); + } + + if (!mimo && CHSPEC_IS2G(chanspec)) { + printf("Last CCK est. power:\t%2d.%02d dBm\n", + DIV_QUO(ppr_wl->est_Pout_cck, 4), + DIV_REM(ppr_wl->est_Pout_cck, 4)); + } +exit: + if (ppr_board != NULL) { + ppr_delete(NULL, ppr_board); + } + if (ppr_target != NULL) { + ppr_delete(NULL, ppr_target); + } + } + free(ppr_wl); + return err; +} + +static int wl_get_txpwr_target_max(void *wl, cmd_t *cmd, char **argv) +{ + int err; + txpwr_target_max_t target_pwr; + int i; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_iovar_get(wl, cmd->name, (void *)&target_pwr, sizeof(target_pwr))) < 0) { + fprintf(stderr, "Error: txpwr_target failed. Make sure interface is up.\n"); + return err; + } + + if (target_pwr.version != TXPWR_TARGET_VERSION) { + fprintf(stderr, "Error: version [%d] mismatch Driver version:%d\n", + TXPWR_TARGET_VERSION, target_pwr.version); + return err; + } + + printf("Maximum Tx Power Target (chanspec:0x%x):\t", target_pwr.chanspec); + for (i = 0; i < target_pwr.rf_cores; i++) + printf("%2d.%02d ", + DIV_QUO(target_pwr.txpwr[i], 4), + DIV_REM(target_pwr.txpwr[i], 4)); + printf("\n"); + + return err; +} + +/* print a single row of the power data. + convert data from dB to qdB; + decide if the pwr data is 20 or 40MHz data; + print "-" in the other channels + */ +static void +wl_txpwr_print_row(const char *label, uint8 chains, int8 pwr20, + int8 pwr20in40, int8 pwr40, int8 pwr80, int8 pwr20in80, int8 pwr40in80, + int8 unsupported_rate, int8 channel_bandwidth, bool verbose) +{ + /* homebrew conversion to qdB, pseudo-floating point representation. */ + int pwr20_q = DIV_QUO(pwr20, 4); + int pwr20_r = DIV_REM(pwr20, 4); + + int pwr20in40_q = DIV_QUO(pwr20in40, 4); + int pwr20in40_r = DIV_REM(pwr20in40, 4); + + int pwr40_q = DIV_QUO(pwr40, 4); + int pwr40_r = DIV_REM(pwr40, 4); + + int pwr80_q = DIV_QUO(pwr80, 4); + int pwr80_r = DIV_REM(pwr80, 4); + + int pwr20in80_q = DIV_QUO(pwr20in80, 4); + int pwr20in80_r = DIV_REM(pwr20in80, 4); + + int pwr40in80_q = DIV_QUO(pwr40in80, 4); + int pwr40in80_r = DIV_REM(pwr40in80, 4); + + + char rate20[] = "- "; + char rate20in40[] = "- "; + char rate40[] = "- "; + char rate80[] = "- "; + char rate20in80[] = "- "; + char rate40in80[] = "- "; + char pad[] = " "; + + if (pwr20 != unsupported_rate) + sprintf(rate20, "%2d.%-2d", pwr20_q, pwr20_r); + if (pwr20in40 != unsupported_rate) + sprintf(rate20in40, "%2d.%-2d", pwr20in40_q, pwr20in40_r); + if (pwr40 != unsupported_rate) + sprintf(rate40, "%2d.%-2d", pwr40_q, pwr40_r); + if (pwr80 != unsupported_rate) + sprintf(rate80, "%2d.%-2d", pwr80_q, pwr80_r); + if (pwr20in80 != unsupported_rate) + sprintf(rate20in80, "%2d.%-2d", pwr20in80_q, pwr20in80_r); + if (pwr40in80 != unsupported_rate) + sprintf(rate40in80, "%2d.%-2d", pwr40in80_q, pwr40in80_r); + + printf("%-23s%d ", label, chains); + if (!verbose) { + switch (channel_bandwidth) { + case WL_BW_20MHZ: + printf("%s\n", rate20); + break; + case WL_BW_40MHZ: + printf("%s%s%s\n", rate20in40, pad, rate40); + break; + case WL_BW_80MHZ: + printf("%s%s%s%s%s\n", rate20in80, pad, rate40in80, pad, rate80); + break; + } + } else { + printf("%s%s%s%s%s%s%s%s%s%s%s\n", rate20, pad, rate20in40, pad, + rate40, pad, rate20in80, pad, rate40in80, pad, rate80); + } + +} + +static void +wl_txpwr_array_row_print(ppr_t *pprptr, int8 channel_bandwidth, reg_rate_index_t rate_index) +{ + const char *label; + int8 pwr20 = WL_RATE_DISABLED; + int8 pwr20in40 = WL_RATE_DISABLED; + int8 pwr40 = WL_RATE_DISABLED; + int8 pwr80 = WL_RATE_DISABLED; + int8 pwr20in80 = WL_RATE_DISABLED; + int8 pwr40in80 = WL_RATE_DISABLED; + + if (rate_index == NO_RATE) + { + printf("(NO_RATE) - - - - - - -\n"); + } + else + { + clm_rate_group_id_t group_id = ppr_table[rate_index].id; + label = ppr_table[rate_index].label; + + switch (channel_bandwidth) { + case WL_BW_20MHZ: + pwr20 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20); + break; + + case WL_BW_40MHZ: + pwr20in40 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20IN40); + pwr40 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_40); + break; + + case WL_BW_80MHZ: + pwr80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_80); + pwr20in80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_20IN80); + pwr40in80 = wl_ppr_get_pwr(pprptr, rate_index, WL_TX_BW_40IN80); + break; + } + + wl_txpwr_print_row(label, ppr_group_table[group_id].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, pwr40in80, + WL_RATE_DISABLED, channel_bandwidth, TRUE); + } +} + +static void +wl_txpwr_print_header(int8 channel_bandwidth, bool verbose) +{ + printf("Rate Chains "); + if (!verbose) + { + switch (channel_bandwidth) { + case WL_BW_20MHZ: + printf("20MHz\n"); + break; + case WL_BW_40MHZ: + printf("20in40 40MHz\n"); + break; + case WL_BW_80MHZ: + printf("20in80 40in80 80MHz\n"); + break; + } + } else { + printf("20MHz 20in40 40MHz 20in80 40in80 80MHz\n"); + } +} + +static void +wl_txpwr_array_print(ppr_t* pprptr, int8 bw, bool verbose, bool is5G) +{ + clm_rate_group_id_t i; + reg_rate_index_t rate_index = DSSS1; + wl_txpwr_print_header(bw, verbose); + for (i = RATE_GROUP_ID_DSSS; i < RATE_GROUP_ID_COUNT; i++) { + wl_txpwr_ppr_print(pprptr, verbose, ppr_group_table[i].rate_type, i, bw, + &rate_index, is5G); + /* VHT rates are printed in two parts: MCS + VHT8,9 */ + if (ppr_group_table[i].rate_type == PPR_RATE_VHT) + i++; + } +} + +/* print power value for each group of rates, if not in verbose mode and rates + * are uniform, one power value is printed out for the whole group + */ +static void +wl_txpwr_ppr_print(ppr_t* pprptr, int vb, ppr_rate_type_t type, + clm_rate_group_id_t gid, int8 bw, reg_rate_index_t *rate_index, bool is5G) +{ + uint i; + const char *label; + int buniform = FALSE; + int8 pwr20 = WL_RATE_DISABLED; + int8 pwr20in40 = WL_RATE_DISABLED; + int8 pwr40 = WL_RATE_DISABLED; + int8 pwr80 = WL_RATE_DISABLED; + int8 pwr20in80 = WL_RATE_DISABLED; + int8 pwr40in80 = WL_RATE_DISABLED; + uint len = 0; + if (pprptr == NULL) { + fprintf(stderr, "illegal ppr data!\n"); + return; + } + + switch (type) { + case PPR_RATE_DSSS: + { + int tx_pwr_min = WL_RATE_DISABLED; + if (is5G) { + tx_pwr_min = ppr_get_min(pprptr, WL_RATE_DISABLED); + } + len = sizeof(ppr_dsss_rateset_t); + if (bw == WL_BW_20MHZ) { + ppr_dsss_rateset_t rate; + ppr_get_dsss(pprptr, WL_TX_BW_20, ppr_group_table[gid].chain, + &rate); + if (is5G) { + uint idx; + for (idx = 0; idx < sizeof(rate); idx++) { + if (rate.pwr[idx] == tx_pwr_min) + rate.pwr[idx] = WL_RATE_DISABLED; + } + } + buniform = wl_array_check_val(rate.pwr, + sizeof(rate), rate.pwr[0]) && !vb; + if (buniform) { + pwr20 = rate.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20 = rate.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } else if (bw == WL_BW_40MHZ) { + ppr_dsss_rateset_t rate20in40; + ppr_dsss_rateset_t rate40; + + ppr_get_dsss(pprptr, WL_TX_BW_20IN40, ppr_group_table[gid].chain, + &rate20in40); + ppr_get_dsss(pprptr, WL_TX_BW_40, ppr_group_table[gid].chain, + &rate40); + if (is5G) { + uint idx; + for (idx = 0; idx < sizeof(ppr_dsss_rateset_t); idx++) { + if (rate20in40.pwr[idx] == tx_pwr_min) + rate20in40.pwr[idx] = WL_RATE_DISABLED; + if (rate40.pwr[idx] == tx_pwr_min) + rate40.pwr[idx] = WL_RATE_DISABLED; + } + } + buniform = wl_array_check_val(rate40.pwr, + sizeof(ppr_dsss_rateset_t), rate40.pwr[0]) && !vb && + wl_array_check_val(rate20in40.pwr, + sizeof(ppr_dsss_rateset_t), rate20in40.pwr[0]); + if (buniform) { + pwr20in40 = rate20in40.pwr[0]; + pwr40 = rate40.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20in40 = rate20in40.pwr[i]; + pwr40 = rate40.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } else if (bw == WL_BW_80MHZ) { + ppr_dsss_rateset_t rate20in80; + ppr_dsss_rateset_t rate40in80; + ppr_dsss_rateset_t rate80; + ppr_get_dsss(pprptr, WL_TX_BW_20IN80, ppr_group_table[gid].chain, + &rate20in80); + ppr_get_dsss(pprptr, WL_TX_BW_40IN80, ppr_group_table[gid].chain, + &rate40in80); + ppr_get_dsss(pprptr, WL_TX_BW_80, ppr_group_table[gid].chain, + &rate80); + if (is5G) { + uint idx; + for (idx = 0; idx < sizeof(ppr_dsss_rateset_t); idx++) { + if (rate20in80.pwr[idx] == tx_pwr_min) + rate20in80.pwr[idx] = WL_RATE_DISABLED; + if (rate40in80.pwr[idx] == tx_pwr_min) + rate40in80.pwr[idx] = WL_RATE_DISABLED; + if (rate80.pwr[idx] == tx_pwr_min) + rate80.pwr[idx] = WL_RATE_DISABLED; + } + } + buniform = wl_array_check_val(rate80.pwr, + sizeof(ppr_dsss_rateset_t), rate80.pwr[0]) && !vb && + wl_array_check_val(rate20in80.pwr, + sizeof(ppr_dsss_rateset_t), rate20in80.pwr[0]) && + wl_array_check_val(rate40in80.pwr, + sizeof(ppr_dsss_rateset_t), rate40in80.pwr[0]); + if (buniform) { + pwr20in80 = rate20in80.pwr[0]; + pwr40in80 = rate40in80.pwr[0]; + pwr80 = rate80.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20in80 = rate20in80.pwr[i]; + pwr40in80 = rate40in80.pwr[i]; + pwr80 = rate80.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } + *rate_index += len; + } + break; + case PPR_RATE_OFDM: + { + len = sizeof(ppr_ofdm_rateset_t); + if (bw == WL_BW_20MHZ) { + ppr_ofdm_rateset_t rate; + ppr_get_ofdm(pprptr, WL_TX_BW_20, ppr_group_table[gid].mode, + ppr_group_table[gid].chain, &rate); + buniform = wl_array_check_val(rate.pwr, + sizeof(rate), rate.pwr[0]) && !vb; + if (buniform) { + pwr20 = rate.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20 = rate.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } else if (bw == WL_BW_40MHZ) { + ppr_ofdm_rateset_t rate20in40; + ppr_ofdm_rateset_t rate40; + + ppr_get_ofdm(pprptr, WL_TX_BW_20IN40, ppr_group_table[gid].mode, + ppr_group_table[gid].chain, &rate20in40); + ppr_get_ofdm(pprptr, WL_TX_BW_40, ppr_group_table[gid].mode, + ppr_group_table[gid].chain, &rate40); + buniform = wl_array_check_val(rate40.pwr, + sizeof(ppr_ofdm_rateset_t), rate40.pwr[0]) && !vb && + wl_array_check_val(rate20in40.pwr, + sizeof(ppr_ofdm_rateset_t), rate20in40.pwr[0]); + if (buniform) { + pwr20in40 = rate20in40.pwr[0]; + pwr40 = rate40.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20in40 = rate20in40.pwr[i]; + pwr40 = rate40.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } else if (bw == WL_BW_80MHZ) { + ppr_ofdm_rateset_t rate20in80; + ppr_ofdm_rateset_t rate40in80; + ppr_ofdm_rateset_t rate80; + ppr_get_ofdm(pprptr, WL_TX_BW_20IN80, ppr_group_table[gid].mode, + ppr_group_table[gid].chain, &rate20in80); + ppr_get_ofdm(pprptr, WL_TX_BW_40IN80, ppr_group_table[gid].mode, + ppr_group_table[gid].chain, &rate40in80); + ppr_get_ofdm(pprptr, WL_TX_BW_80, ppr_group_table[gid].mode, + ppr_group_table[gid].chain, &rate80); + buniform = wl_array_check_val(rate80.pwr, + sizeof(ppr_ofdm_rateset_t), rate80.pwr[0]) && !vb && + wl_array_check_val(rate20in80.pwr, + sizeof(ppr_ofdm_rateset_t), rate20in80.pwr[0]) && + wl_array_check_val(rate40in80.pwr, + sizeof(ppr_ofdm_rateset_t), rate40in80.pwr[0]); + if (buniform) { + pwr20in80 = rate20in80.pwr[0]; + pwr40in80 = rate40in80.pwr[0]; + pwr80 = rate80.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20in80 = rate20in80.pwr[i]; + pwr40in80 = rate40in80.pwr[i]; + pwr80 = rate80.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } + *rate_index += len; + } + break; + case PPR_RATE_HT: + { + len = sizeof(ppr_ht_mcs_rateset_t); + if (bw == WL_BW_20MHZ) { + ppr_ht_mcs_rateset_t rate; + ppr_get_ht_mcs(pprptr, WL_TX_BW_20, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate); + buniform = wl_array_check_val(rate.pwr, + sizeof(rate), rate.pwr[0]) && !vb; + if (buniform) { + pwr20 = rate.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20 = rate.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } else if (bw == WL_BW_40MHZ) { + ppr_ht_mcs_rateset_t rate20in40; + ppr_ht_mcs_rateset_t rate40; + + ppr_get_ht_mcs(pprptr, WL_TX_BW_20IN40, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate20in40); + ppr_get_ht_mcs(pprptr, WL_TX_BW_40, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate40); + buniform = wl_array_check_val(rate40.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate40.pwr[0]) && !vb && + wl_array_check_val(rate20in40.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate20in40.pwr[0]); + if (buniform) { + pwr20in40 = rate20in40.pwr[0]; + pwr40 = rate40.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20in40 = rate20in40.pwr[i]; + pwr40 = rate40.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } else if (bw == WL_BW_80MHZ) { + ppr_ht_mcs_rateset_t rate20in80; + ppr_ht_mcs_rateset_t rate40in80; + ppr_ht_mcs_rateset_t rate80; + ppr_get_ht_mcs(pprptr, WL_TX_BW_20IN80, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate20in80); + ppr_get_ht_mcs(pprptr, WL_TX_BW_40IN80, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate40in80); + ppr_get_ht_mcs(pprptr, WL_TX_BW_80, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate80); + buniform = wl_array_check_val(rate80.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate80.pwr[0]) && !vb && + wl_array_check_val(rate20in80.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate20in80.pwr[0]) && + wl_array_check_val(rate40in80.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate40in80.pwr[0]); + if (buniform) { + pwr20in80 = rate20in80.pwr[0]; + pwr40in80 = rate40in80.pwr[0]; + pwr80 = rate80.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < len; i++) { + pwr20in80 = rate20in80.pwr[i]; + pwr40in80 = rate40in80.pwr[i]; + pwr80 = rate80.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } + *rate_index += len; + } + break; + case PPR_RATE_VHT: + { + uint bvhtuniform = FALSE; + uint lenht = sizeof(ppr_ht_mcs_rateset_t); + len = sizeof(ppr_vht_mcs_rateset_t); + /* VHT RATES are printed as two parts: MCS0-7 and VTH8-9 */ + if (bw == WL_BW_20MHZ) { + ppr_vht_mcs_rateset_t rate; + ppr_get_vht_mcs(pprptr, WL_TX_BW_20, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate); + buniform = wl_array_check_val(rate.pwr, lenht, rate.pwr[0])&& !vb; + bvhtuniform = wl_array_check_val(&rate.pwr[lenht], len-lenht, + rate.pwr[lenht]) && !vb; + if (buniform) { + pwr20 = rate.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < lenht; i++) { + pwr20 = rate.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + if (bvhtuniform) { + pwr20 = rate.pwr[lenht]; + /* print VHT8-9 label */ + label = get_clm_rate_group_label(gid+1); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + } else { + for (i = lenht; i < len; i++) { + pwr20 = rate.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } else if (bw == WL_BW_40MHZ) { + ppr_vht_mcs_rateset_t rate20in40; + ppr_vht_mcs_rateset_t rate40; + + ppr_get_vht_mcs(pprptr, WL_TX_BW_20IN40, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate20in40); + ppr_get_vht_mcs(pprptr, WL_TX_BW_40, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate40); + + buniform = wl_array_check_val(rate40.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate40.pwr[0]) && !vb && + wl_array_check_val(rate20in40.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate20in40.pwr[0]); + bvhtuniform = wl_array_check_val(&rate40.pwr[lenht], len-lenht, + rate40.pwr[lenht]) && !vb && + wl_array_check_val(&rate20in40.pwr[lenht], len-lenht, + rate20in40.pwr[lenht]); + if (buniform) { + pwr20in40 = rate20in40.pwr[0]; + pwr40 = rate40.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < lenht; i++) { + pwr20in40 = rate20in40.pwr[i]; + pwr40 = rate40.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + if (bvhtuniform) { + pwr20in40 = rate20in40.pwr[lenht]; + pwr40 = rate40.pwr[lenht]; + /* print VHT8-9 label */ + label = get_clm_rate_group_label(gid+1); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + } else { + for (i = lenht; i < len; i++) { + pwr20in40 = rate20in40.pwr[i]; + pwr40 = rate40.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } else if (bw == WL_BW_80MHZ) { + ppr_vht_mcs_rateset_t rate20in80; + ppr_vht_mcs_rateset_t rate40in80; + ppr_vht_mcs_rateset_t rate80; + ppr_get_vht_mcs(pprptr, WL_TX_BW_20IN80, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate20in80); + ppr_get_vht_mcs(pprptr, WL_TX_BW_40IN80, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate40in80); + ppr_get_vht_mcs(pprptr, WL_TX_BW_80, ppr_group_table[gid].nss, + ppr_group_table[gid].mode, ppr_group_table[gid].chain, + &rate80); + buniform = wl_array_check_val(rate80.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate80.pwr[0]) && !vb && + wl_array_check_val(rate20in80.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate20in80.pwr[0]) && + wl_array_check_val(rate40in80.pwr, + sizeof(ppr_ht_mcs_rateset_t), rate40in80.pwr[0]); + bvhtuniform = wl_array_check_val(&rate80.pwr[lenht], len-lenht, + rate80.pwr[lenht]) && !vb && + wl_array_check_val(&rate20in80.pwr[lenht], len-lenht, + rate20in80.pwr[lenht]) && + wl_array_check_val(&rate40in80.pwr[lenht], len-lenht, + rate40in80.pwr[lenht]); + + if (buniform) { + pwr20in80 = rate20in80.pwr[0]; + pwr40in80 = rate40in80.pwr[0]; + pwr80 = rate80.pwr[0]; + label = get_clm_rate_group_label(gid); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + + } else { + for (i = 0; i < lenht; i++) { + pwr20in80 = rate20in80.pwr[i]; + pwr40in80 = rate40in80.pwr[i]; + pwr80 = rate80.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + if (bvhtuniform) { + pwr20in80 = rate20in80.pwr[lenht]; + pwr40in80 = rate40in80.pwr[lenht]; + pwr80 = rate80.pwr[lenht]; + /* print VHT8-9 label */ + label = get_clm_rate_group_label(gid+1); + wl_txpwr_print_row(label, ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, bw, vb); + } else { + for (i = lenht; i < len; i++) { + pwr20in80 = rate20in80.pwr[i]; + pwr40in80 = rate40in80.pwr[i]; + pwr80 = rate80.pwr[i]; + label = ppr_table[*rate_index+i].label; + wl_txpwr_print_row(label, + ppr_group_table[gid].chain, + pwr20, pwr20in40, pwr40, pwr80, pwr20in80, + pwr40in80, WL_RATE_DISABLED, + bw, vb); + } + } + } + *rate_index += len; + } + break; + } +} + +/* helper function to check if the array are uniformly same as the input value */ +static int wl_array_check_val(int8 *pwr, uint count, int8 val) +{ + uint i; + for (i = 0; i < count; i++) { + if (pwr[i] != val) + return FALSE; + } + return TRUE; +} + +static void +wl_txpwr_regulatory_array_row_print(int8 *powers, int8 *powers_subchan1, + int8 *powers_subchan2, int8 channel_bandwidth, reg_rate_index_t rate_index) +{ + const int RATE_UNSUPPORTED = -128; /* CLM uses -128 as the unsupported rate */ + const char* label; + uint8 chains; + int pwr20 = RATE_UNSUPPORTED; + int pwr20in40 = RATE_UNSUPPORTED; + int pwr40 = RATE_UNSUPPORTED; + int pwr80 = RATE_UNSUPPORTED; + int pwr20in80 = RATE_UNSUPPORTED; + int pwr40in80 = RATE_UNSUPPORTED; + + wl_txpwr_print_header(channel_bandwidth, TRUE); + + if (rate_index == NO_RATE) + { + printf("(NO_RATE) - - - - - - -\n"); + } + else + { + label = ppr_table[rate_index].label; + chains = ppr_group_table[ppr_table[rate_index].id].chain; + + switch (channel_bandwidth) { + case WL_BW_20MHZ: + pwr20 = powers[ppr_table[rate_index].rate]; + break; + case WL_BW_40MHZ: + pwr40 = powers[ppr_table[rate_index].rate]; + pwr20in40 = powers_subchan1[ppr_table[rate_index].rate]; + break; + case WL_BW_80MHZ: + pwr80 = powers[ppr_table[rate_index].rate]; + pwr40in80 = powers_subchan1[ppr_table[rate_index].rate]; + pwr20in80 = powers_subchan2[ppr_table[rate_index].rate]; + break; + } + wl_txpwr_print_row(label, chains, pwr20, pwr20in40, + pwr40, pwr80, pwr20in80, pwr40in80, RATE_UNSUPPORTED, + channel_bandwidth, TRUE); + } +} + +/* Essentially the same as wl_txpwr_array_print, but the + * format of the regulatory data is now diffreent enough that we need a separate function. + * The data format should be unified, and this code removed. + */ +static void +wl_txpwr_regulatory_array_print(int8 *powers, int8 *powers_subchan1, + int8 *powers_subchan2, int8 channel_bandwidth, bool verbose) +{ + int i, j; + const int RATE_UNSUPPORTED = -128; /* CLM uses -128 as the unsupported rate */ + const char* label; + + /* This code assumes that all of the rates in a group will be contiguous */ + wl_txpwr_print_header(channel_bandwidth, verbose); + for (i = 0; i < RATE_GROUP_ID_COUNT; i++) { + int first_rate = 0; + int num_rates = 0; + uint8 chains; + bool compress_rate = FALSE; + int pwr20 = RATE_UNSUPPORTED; + int pwr20in40 = RATE_UNSUPPORTED; + int pwr40 = RATE_UNSUPPORTED; + int pwr80 = RATE_UNSUPPORTED; + int pwr20in80 = RATE_UNSUPPORTED; + int pwr40in80 = RATE_UNSUPPORTED; + + /* find the first rate index in this group. */ + while ((int)ppr_table[first_rate].id != i) + first_rate++; + /* how many rates in that group? */ + while ((first_rate + num_rates < WL_NUMRATES) && + ((int)ppr_table[first_rate + num_rates].id == i)) + num_rates++; + + /* are the regulatory power settings the same? */ + switch (channel_bandwidth) { + case WL_BW_20MHZ: + compress_rate = !verbose && + wl_array_uniform((uint8*)&powers[ppr_table[first_rate].rate], 0, + num_rates); + break; + case WL_BW_40MHZ: + compress_rate = !verbose && + wl_array_uniform((uint8*)&powers[ppr_table[first_rate].rate], 0, + num_rates) && + wl_array_uniform((uint8*)&powers_subchan1[ppr_table + [first_rate].rate], 0, num_rates); + break; + case WL_BW_80MHZ: + compress_rate = !verbose && + wl_array_uniform((uint8*)&powers[ppr_table[first_rate].rate], 0, + num_rates) && + wl_array_uniform((uint8*)&powers_subchan1[ppr_table + [first_rate].rate], 0, num_rates) && + wl_array_uniform((uint8*)&powers_subchan2[ppr_table + [first_rate].rate], 0, num_rates); + break; + } + + if (compress_rate) + j = num_rates - 1; + else + j = 0; + + for (; j < num_rates; j++) { + if (compress_rate) + label = get_clm_rate_group_label(i); + else + label = ppr_table[first_rate + j].label; + + chains = ppr_group_table[ppr_table[first_rate + j].id].chain; + + switch (channel_bandwidth) { + case WL_BW_20MHZ: + pwr20 = powers[ppr_table[first_rate + j].rate]; + break; + case WL_BW_40MHZ: + pwr40 = powers[ppr_table[first_rate + j].rate]; + pwr20in40 = powers_subchan1[ppr_table[first_rate + j].rate]; + break; + case WL_BW_80MHZ: + pwr80 = powers[ppr_table[first_rate + j].rate]; + pwr40in80 = powers_subchan1[ppr_table[first_rate + j].rate]; + pwr20in80 = powers_subchan2[ppr_table[first_rate + j].rate]; + break; + } + wl_txpwr_print_row(label, chains, pwr20, pwr20in40, + pwr40, pwr80, pwr20in80, pwr40in80, RATE_UNSUPPORTED, + channel_bandwidth, verbose); + } + } +} +/* return TRUE if all the values in the array are uniformly the same */ +static int +wl_array_uniform(uint8 *pwr, int start, int count) +{ + int i, rate; + + for (i = 1, rate = start + 1; i < count; i++, rate++) + if (pwr[rate] != pwr[rate - 1]) + return FALSE; + + return TRUE; +} + +static int +wl_get_instant_power(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + tx_inst_power_t *power; + uint band_list[3]; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + strcpy(buf, "txinstpwr"); + if ((ret = wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN)) < 0) { + return ret; + } + + power = (tx_inst_power_t *)buf; + /* Make the most of the info returned in band_list! + * b/g and a + * b/g-uni + * a-uni + * NOTE: NO a and b/g case ... + */ + if ((ret = wlu_get(wl, WLC_GET_BANDLIST, band_list, sizeof(band_list))) < 0) + return (ret); + band_list[0] = dtoh32(band_list[0]); + band_list[1] = dtoh32(band_list[1]); + band_list[2] = dtoh32(band_list[2]); + + /* If B/G is present it's always the lower index */ + if (band_list[1] == WLC_BAND_2G) { + printf("Last B phy CCK est. power:\t%2d.%d dBm\n", + DIV_QUO(power->txpwr_est_Pout[0], 4), + DIV_REM(power->txpwr_est_Pout[0], 4)); + printf("Last B phy OFDM est. power:\t%2d.%d dBm\n", + DIV_QUO(power->txpwr_est_Pout_gofdm, 4), + DIV_REM(power->txpwr_est_Pout_gofdm, 4)); + + printf("\n"); + } + + /* A band */ + if (band_list[1] == WLC_BAND_5G || (band_list[0] > 1 && band_list[2] == WLC_BAND_5G)) { + printf("Last A phy est. power:\t\t%2d.%d dBm\n", + DIV_QUO(power->txpwr_est_Pout[1], 4), + DIV_REM(power->txpwr_est_Pout[1], 4)); + } + + return ret; +} + +static int +wl_evm(void *wl, cmd_t *cmd, char **argv) +{ + int val[3]; + + /* Get channel */ + if (!*++argv) { + fprintf(stderr, "Need to specify at least one parameter\n"); + return BCME_USAGE_ERROR; + } + + if (!stricmp(*argv, "off")) + val[0] = 0; + else + val[0] = atoi(*argv); + + /* set optional parameters to default */ + val[1] = 4; /* rate in 500Kb units */ + val[2] = 0; /* This is ignored */ + + /* Get optional rate and convert to 500Kb units */ + if (*++argv) + val[1] = rate_string2int(*argv); + + val[0] = htod32(val[0]); + val[1] = htod32(val[1]); + val[2] = htod32(val[2]); + return wlu_set(wl, cmd->set, val, sizeof(val)); +} + +#define WL_JOIN_PARAMS_MAX WL_JOIN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(chanspec_t) + +/* when prescanned option is specified */ +static int +wl_join_prescanned(void *wl, wl_join_params_t *join_params, uint *join_params_size) +{ + /* load with prescanned channels and bssids */ + int ret, err = 0; + char *destbuf; + wl_scan_results_t *scanres = NULL; + wl_bss_info_t *bi; + uint i, cnt, bssid_cnt, bi_len; + + if ((destbuf = malloc(WL_DUMP_BUF_LEN)) == NULL) { + fprintf(stderr, "Failed to allocate %d-byte buffer for scanresults\n", + WL_DUMP_BUF_LEN); + err = BCME_NOMEM; + goto pexit; + } + + if ((ret = wl_get_scan(wl, WLC_SCAN_RESULTS, destbuf, WL_DUMP_BUF_LEN)) != 0) { + fprintf(stderr, "failed to fetch scan results, err %d\n", ret); + err = ret; + goto pexit; + } + + scanres = (wl_scan_results_t *)destbuf; + if (scanres->version != WL_BSS_INFO_VERSION) { + fprintf(stderr, "scan parsing failed (expect version %d, got %d)\n", + WL_BSS_INFO_VERSION, scanres->version); + err = -1; + goto pexit; + } + + /* find matching ssids to fill the channel list */ + for (cnt = i = 0, bi = scanres->bss_info; i < scanres->count; + i++, bi = (wl_bss_info_t*)((int8*)bi + bi_len)) { + bi_len = dtoh32(bi->length); + if ((bi->SSID_len != join_params->ssid.SSID_len) || + memcmp(bi->SSID, join_params->ssid.SSID, + join_params->ssid.SSID_len)) { + continue; + } else { + dump_bss_info(bi); + printf("--------------------------------\n"); + } + + memcpy(&join_params->params.chanspec_list[cnt], + &bi->chanspec, sizeof(chanspec_t)); + cnt++; + } + bssid_cnt = (uint16)cnt; + + /* append the corresponding bssids */ + destbuf = (char*)&join_params->params.chanspec_list[cnt]; + *join_params_size = destbuf - (char*)join_params; + *join_params_size += (cnt * sizeof(struct ether_addr)); + + if (*join_params_size > WL_JOIN_PARAMS_MAX) { + fprintf(stderr, "Can't fit bssids for all %d APs found\n", cnt); + err = -1; + goto pexit; + } + + for (cnt = i = 0, bi = scanres->bss_info; + (i < scanres->count) && (cnt < bssid_cnt); + i++, bi = (wl_bss_info_t*)((int8*)bi + bi_len)) { + bi_len = dtoh32(bi->length); + if ((bi->SSID_len != join_params->ssid.SSID_len) || + memcmp(bi->SSID, join_params->ssid.SSID, + join_params->ssid.SSID_len)) { + continue; + } + + memcpy(destbuf, &bi->BSSID, sizeof(struct ether_addr)); + destbuf += sizeof(struct ether_addr); + cnt++; + } + + if (cnt != bssid_cnt) { + fprintf(stderr, "Mismatched channel and bssid counts!\n"); + err = -1; + goto pexit; + } + + if (cnt == 0) { + printf("No matches found, issuing normal join.\n"); + } else { + printf("Passing %d channel/bssid pairs.\n", cnt); + } + join_params->params.bssid_cnt = htod16(bssid_cnt); + +pexit: + if (scanres) + free((char*)scanres); + else + free(destbuf); + return err; +} + +/* wl join <ssid> [key <0-3>:xxxxx] + * [imode bss|ibss] + * [amode open|shared|openshared|wpa|wpapsk|wpa2|wpa2psk|wpanone|ftpsk] + * [options] + * Options: + * -b MAC, --bssid=MAC, where MAC is in xx:xx:xx:xx:xx:xx format + * -c CL, --chanspecs=CL, where CL is a comma or space separated list of chanspecs + * -p, -passive: uses join iovar instead of SET_SSID ioctl to force passive assoc scan + */ + +static int +wl_join(void *wl, cmd_t *cmd, char **argv) +{ + int ret = BCME_OK, idx = 0; + wl_join_params_t *join_params; + uint join_params_size; + wl_wsec_key_t key; + int wsec = 0, auth = 0, infra = 1; + int wpa_auth = WPA_AUTH_DISABLED; + char* cmd_name; + bool prescanned = FALSE; + int passive = 0; + + UNUSED_PARAMETER(cmd); + + cmd_name = *argv++; + + /* allocate the max storage */ + join_params_size = WL_JOIN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(chanspec_t); + if ((join_params = malloc(join_params_size)) == NULL) { + fprintf(stderr, "Error allocating %d bytes for assoc params\n", join_params_size); + return BCME_NOMEM; + } + memset(join_params, 0, join_params_size); + memcpy(&join_params->params.bssid, ðer_bcast, ETHER_ADDR_LEN); + + /* verify that SSID was specified and is a valid length */ + if (!*argv || (strlen(*argv) > DOT11_MAX_SSID_LEN)) { + ret = BCME_USAGE_ERROR; + goto exit; + } + + join_params->ssid.SSID_len = strlen(*argv); + memcpy(join_params->ssid.SSID, *argv, join_params->ssid.SSID_len); + /* default to plain old ioctl */ + join_params_size = sizeof(wlc_ssid_t); + /* get current wsec */ + if (wlu_iovar_getint(wl, "wsec", &wsec) < 0) + wsec = 0; + + while (*++argv) { + if (!stricmp(*argv, "wepkey") || !stricmp(*argv, "wep") || !stricmp(*argv, "key")) { + /* specified wep key */ + memset(&key, 0, sizeof(key)); + if (!*++argv) { + ret = BCME_USAGE_ERROR; + goto exit; + } + /* WEP index specified */ + if (*(argv[0]+1) == ':') { + idx = *argv[0] - 0x30; + if (idx < 0 || idx > 3) { + fprintf(stderr, "Invalid key index %d specified\n", idx); + ret = BCME_BADARG; + goto exit; + } + argv[0] += 2; /* colon + digit */ + } + key.index = idx; + + if (parse_wep(argv, &key, FALSE)) { + ret = BCME_BADARG; + goto exit; + } + + key.index = htod32(key.index); + key.len = htod32(key.len); + key.algo = htod32(key.algo); + key.flags = htod32(key.flags); + + if ((ret = wlu_set(wl, WLC_SET_KEY, &key, sizeof(wl_wsec_key_t))) < 0) { + goto exit; + } + wsec |= WEP_ENABLED; + } + /* specified infrastructure mode */ + else if (!stricmp(*argv, "imode") || + !stricmp(*argv, "infra") || + !stricmp(*argv, "mode")) { + if (!*++argv) { + fprintf(stderr, "%s %s: expected argument after \"infra\" keyword " + "but command line ended.\n", wlu_av0, cmd_name); + ret = BCME_USAGE_ERROR; + goto exit; + } else if (!stricmp(*argv, "ibss") || + !stricmp(*argv, "adhoc") || + !stricmp(*argv, "ad-hoc")) { + infra = 0; + } else if (!stricmp(*argv, "bss") || + !stricmp(*argv, "managed") || + !strnicmp(*argv, "infra", 5)) { + infra = 1; + } else { + fprintf(stderr, "%s %s: unrecongnized parameter \"%s\" after " + "\"infra\" keyword\n", wlu_av0, cmd_name, *argv); + ret = BCME_USAGE_ERROR; + goto exit; + } + } + /* specified authentication mode */ + else if (!stricmp(*argv, "amode") || !strnicmp(*argv, "auth", 4)) { + if (!*++argv) { + ret = BCME_USAGE_ERROR; + goto exit; + } + if (!stricmp(*argv, "open")) + auth = WL_AUTH_OPEN_SYSTEM; + else if (!stricmp(*argv, "shared")) + auth = WL_AUTH_SHARED_KEY; + else if (!stricmp(*argv, "openshared")) + auth = WL_AUTH_OPEN_SHARED; +#ifdef BCMCCX + else if (!stricmp(*argv, "cckm")) + wpa_auth = WPA_AUTH_CCKM; + else if (!stricmp(*argv, "cckmwpa2")) + wpa_auth = WPA2_AUTH_CCKM; +#endif /* BCMCCX */ + else if (!stricmp(*argv, "wpanone")) + wpa_auth = WPA_AUTH_NONE; + else if (!stricmp(*argv, "wpa")) + wpa_auth = WPA_AUTH_UNSPECIFIED; + else if (!stricmp(*argv, "wpapsk")) + wpa_auth = WPA_AUTH_PSK; + else if (!stricmp(*argv, "wpa2")) + wpa_auth = WPA2_AUTH_UNSPECIFIED; + else if (!stricmp(*argv, "wpa2psk")) + wpa_auth = WPA2_AUTH_PSK; +#ifdef BCMWAPI_WAI + else if (!stricmp(*argv, "wapi")) + wpa_auth = WAPI_AUTH_UNSPECIFIED; + else if (!stricmp(*argv, "wapipsk")) + wpa_auth = WAPI_AUTH_PSK; +#endif /* BCMWAPI_WAI */ + else if (!stricmp(*argv, "ftpsk")) + wpa_auth = WPA2_AUTH_PSK | WPA2_AUTH_FT; + else { + ret = BCME_USAGE_ERROR; + goto exit; + } + } + else if (!stricmp(*argv, "-passive") || !stricmp(*argv, "-p")) { + /* Use extended join iovar to assoc_scan passively */ + passive = 1; + } + /* optional assoc params */ + else if ((ret = wl_parse_assoc_params(argv, &join_params->params, &prescanned)) == + BCME_OK) { + join_params_size = WL_JOIN_PARAMS_FIXED_SIZE + + dtoh32(join_params->params.chanspec_num) * sizeof(chanspec_t); + break; + } + else { + fprintf(stderr, "%s %s: unable to parse parameter \"%s\"\n", + wlu_av0, cmd_name, *argv); + goto exit; + } + } + + /* set infrastructure mode */ + infra = htod32(infra); + if ((ret = wlu_set(wl, WLC_SET_INFRA, &infra, sizeof(int))) < 0) + goto exit; + + /* set authentication mode */ + auth = htod32(auth); + if ((ret = wlu_set(wl, WLC_SET_AUTH, &auth, sizeof(int))) < 0) + goto exit; + + /* set wsec mode */ + if ((ret = wlu_iovar_setint(wl, "wsec", wsec)) < 0) + goto exit; + + /* set WPA_auth mode */ + wpa_auth = htod32(wpa_auth); + if ((ret = wlu_set(wl, WLC_SET_WPA_AUTH, &wpa_auth, sizeof(wpa_auth))) < 0) + goto exit; + + if (passive) { + wl_extjoin_params_t *extjoin_params; + int extjoin_size; + int i; + printf("Using passive assoc scan\n"); + extjoin_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); + if ((extjoin_params = malloc(extjoin_size)) == NULL) { + fprintf(stderr, "Error allocating %d bytes for extjoin \n", extjoin_size); + ret = BCME_NOMEM; + goto exit; + } + + /* Copy assoc params from legacy struct into extended struct */ + memset(extjoin_params, 0, extjoin_size); + memcpy(&extjoin_params->ssid.SSID, &join_params->ssid.SSID, DOT11_MAX_SSID_LEN); + extjoin_params->ssid.SSID_len = htod32(join_params->ssid.SSID_len); + + memcpy(&extjoin_params->assoc.bssid, &join_params->params.bssid, ETHER_ADDR_LEN); + extjoin_params->assoc.chanspec_num = join_params->params.chanspec_num; + for (i = 0; i < join_params->params.chanspec_num; i++) { + extjoin_params->assoc.chanspec_list[i] = + join_params->params.chanspec_list[i]; + } + + extjoin_params->scan.scan_type = WL_SCANFLAGS_PASSIVE; + extjoin_params->scan.nprobes = -1; + extjoin_params->scan.active_time = -1; + extjoin_params->scan.passive_time = -1; + extjoin_params->scan.home_time = -1; + + + ret = wlu_var_setbuf(wl, "join", extjoin_params, extjoin_size); + free(extjoin_params); + } else { + /* join parameters starts with the ssid */ + join_params->ssid.SSID_len = htod32(join_params->ssid.SSID_len); + + if (prescanned) { + if ((ret = wl_join_prescanned(wl, join_params, &join_params_size)) < 0) + goto exit; + } + + /* set ssid with extend assoc params (if any) */ + join_params->ssid.SSID_len = htod32(join_params->ssid.SSID_len); + ret = wlu_set(wl, WLC_SET_SSID, join_params, join_params_size); + } + +exit: + free(join_params); + return ret; +} + +/* Set or Get the "bssid" iovar, with an optional config index argument: + * wl bssid [-C N]|[--cfg=N] bssid + * + * Option: + * -C N + * --cfg=N + * --config=N + * --configuration=N + * specify the config index N + * If cfg index not given on a set, the WLC_SET_BSSID ioctl will be used + */ +static int +wl_bssid(void *wl, cmd_t *cmd, char **argv) +{ + struct ether_addr ea; + int bsscfg_idx = 0; + int consumed; + int error; + + UNUSED_PARAMETER(cmd); + + argv++; + + /* parse a bsscfg_idx option if present */ + if ((error = wl_cfg_option(argv, "bssid", &bsscfg_idx, &consumed)) != 0) + return error; + + argv += consumed; + + if (*argv == NULL) { + if (consumed == 0) { + /* no config index, use WLC_GET_BSSID on the interface */ + error = wlu_get(wl, WLC_GET_BSSID, &ea, ETHER_ADDR_LEN); + } else { + /* use "bssid" iovar since a config option was given */ + error = wlu_bssiovar_get(wl, "bssid", bsscfg_idx, &ea, ETHER_ADDR_LEN); + } + if (error < 0) + return error; + printf("%s\n", wl_ether_etoa(&ea)); + + } else { + + if (!wl_ether_atoe(*argv, &ea)) + return BCME_USAGE_ERROR; + + if (consumed == 0) { + /* no config index given, use WLC_SET_BSSID */ + error = wlu_set(wl, WLC_SET_BSSID, &ea, ETHER_ADDR_LEN); + } else { + /* use "bssid" iovar since a config option was given */ + error = wl_bssiovar_set(wl, "bssid", bsscfg_idx, &ea, ETHER_ADDR_LEN); + } + } + return error; +} + +/* Set or Get the "ssid" iovar, with an optional config index argument: + * wl ssid [-C N]|[--cfg=N] ssid + * + * Option: + * -C N + * --cfg=N + * --config=N + * --configuration=N + * specify the config index N + * If cfg index not given on a set, the WLC_SET_SSID ioctl will be used + */ +static int +wl_ssid(void *wl, cmd_t *cmd, char **argv) +{ + char ssidbuf[SSID_FMT_BUF_LEN]; + wlc_ssid_t ssid = { 0, {0} }; + int bsscfg_idx = 0; + int consumed; + int error; + + argv++; + + /* parse a bsscfg_idx option if present */ + if ((error = wl_cfg_option(argv, "ssid", &bsscfg_idx, &consumed)) != 0) + return error; + + argv += consumed; + + if (*argv == NULL) { + if (consumed == 0) { + /* no config index, use WLC_GET_SSID on the interface */ + if (cmd->get == WLC_GET_SSID) + error = wlu_get(wl, WLC_GET_SSID, &ssid, sizeof(ssid)); + else + error = wlu_iovar_get(wl, cmd->name, &ssid, sizeof(ssid)); + } else { + if (cmd->get == WLC_GET_SSID) { + /* use "ssid" iovar since a config option was given */ + error = wlu_bssiovar_get(wl, "ssid", bsscfg_idx, &ssid, + sizeof(ssid)); + } else { + error = wlu_bssiovar_get(wl, cmd->name, bsscfg_idx, &ssid, + sizeof(ssid)); + } + } + if (error < 0) + return error; + + ssid.SSID_len = dtoh32(ssid.SSID_len); + wl_format_ssid(ssidbuf, ssid.SSID, ssid.SSID_len); + printf("Current %s: \"%s\"\n", + (cmd->get == WLC_GET_SSID)? "SSID": cmd->name, + ssidbuf); + } else { + if (strlen(argv[0]) > DOT11_MAX_SSID_LEN) { + fprintf(stderr, "SSID arg \"%s\" must be 32 chars or less\n", argv[0]); + return BCME_BADARG; + } + ssid.SSID_len = strlen(argv[0]); + memcpy(ssid.SSID, argv[0], ssid.SSID_len); + + wl_format_ssid(ssidbuf, ssid.SSID, ssid.SSID_len); + printf("Setting %s: \"%s\"\n", (cmd->set == WLC_SET_SSID)? "SSID": cmd->name, + ssidbuf); + + ssid.SSID_len = htod32(ssid.SSID_len); + if (consumed == 0) { + /* no config index given, use WLC_SET_SSID */ + if (cmd->set == WLC_SET_SSID) { + error = wlu_set(wl, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t)); + } else { + error = wlu_iovar_set(wl, cmd->name, &ssid, sizeof(wlc_ssid_t)); + } + } else { + if (cmd->set == WLC_SET_SSID) { + /* use "ssid" iovar since a config option was given */ + error = wl_bssiovar_set(wl, "ssid", bsscfg_idx, &ssid, + sizeof(wlc_ssid_t)); + } else + error = wl_bssiovar_set(wl, cmd->name, bsscfg_idx, &ssid, + sizeof(wlc_ssid_t)); + } + } + return error; +} + +static const char* +wl_smfs_map_type(uint8 type) +{ + static const struct {uint8 type; char name[32];} type_names[] = { + {SMFS_TYPE_AUTH, "Authentication_Request"}, + {SMFS_TYPE_ASSOC, "Association_Request"}, + {SMFS_TYPE_REASSOC, "Reassociation_Request"}, + {SMFS_TYPE_DISASSOC_TX, "Disassociation_Request_TX"}, + {SMFS_TYPE_DISASSOC_RX, "Disassociation_Request_RX"}, + {SMFS_TYPE_DEAUTH_TX, "Deauthentication_Request_TX"}, + {SMFS_TYPE_DEAUTH_RX, "Deauthentication_Request_RX"} + }; + + const char *tname = "UNKNOWN"; + uint i; + + for (i = 0; i < ARRAYSIZE(type_names); i++) { + if (type_names[i].type == type) + tname = type_names[i].name; + } + return tname; +} + +static int +wl_disp_smfs(char *inbuf) +{ + static const char *codename[] = {"Status_code", "Reason_code"}; + wl_smf_stats_t *smf_stats; + wl_smfs_elem_t *elemt = NULL; + const char *namebuf; + uint32 version; + int count; + + smf_stats = (wl_smf_stats_t *) inbuf; + namebuf = wl_smfs_map_type(smf_stats->type); + + version = dtoh32(smf_stats->version); + if (version != SMFS_VERSION) { + fprintf(stderr, "Sorry, your driver has smfs_version %d " + "but this program supports only version %d.\n", + version, SMFS_VERSION); + return -1; + } + + printf("Frame type: %s\n", namebuf); + printf("\tIgnored Count: %d\n", dtoh32(smf_stats->ignored_cnt)); + printf("\tMalformed Count: %d\n", dtoh32(smf_stats->malformed_cnt)); + + count = dtoh32(smf_stats->count_total); + + if (count) { + namebuf = codename[dtoh32(smf_stats->codetype)]; + printf("\tSuccessful/Failed Count:\n"); + elemt = &smf_stats->elem[0]; + } + + while (count) { + printf("\t\t%s %d Count: %d\n", namebuf, dtoh16(elemt->code), + dtoh32(elemt->count)); + elemt ++; + count --; + } + + return 0; + +} + +/* + * Check for the smfstats parameters. One of defined parameters can be passed in. + */ +static int +wl_smfs_option(char **argv, int* idx, int *consumed, int* clear) +{ + int err = 0; + char *p; + char const * smfs_opt[] = {"auth", "assoc", "reassoc", "disassoc_tx", + "disassoc_rx", "deauth_tx", "deauth_rx"}; + char const * clear_opt = "clear"; + int i; + char const * cur_opt; + + if (*argv == NULL) { + goto exit; + } + + p = *argv++; + + for (i = 0; i < SMFS_TYPE_MAX; i++) { + cur_opt = smfs_opt[i]; + if (!strcmp(p, cur_opt)) { + *idx = i; + *consumed += 1; + goto exit; + } + } + + if (!strcmp(p, clear_opt)) + *clear = 1; + +exit: + return err; +} + +/* Get or Clear (set) the "smfstats" iovar, with an optional config index argument: + * wl smfstats [-C N]|[--cfg=N] 0 + * + * Option: + * -C N + * --cfg=N + * --config=N + * --configuration=N + * specify the config index N + * If cfg index not given on a set, the WLC_SET_SMF_STATS ioctl will be used + */ +static int +wl_smfstats(void *wl, cmd_t *cmd, char **argv) +{ + int bsscfg_idx = 0; + int cfg_consumed = 0, smfs_consumed = 0; + int err; + int i, val; + int smf_index = 0; + int smfs_clear = 0; + + BCM_REFERENCE(cmd); + + argv++; + + /* parse a bsscfg_idx option if present */ + if ((err = wl_cfg_option(argv, "smfstats", &bsscfg_idx, &cfg_consumed)) != 0) + return err; + + argv += cfg_consumed; + + if ((err = wl_smfs_option(argv, &smf_index, &smfs_consumed, &smfs_clear)) != 0) + return err; + + if (!smfs_clear) { + if (cfg_consumed == 0) { + if (smfs_consumed) { + err = wlu_iovar_getbuf(wl, "smfstats", &smf_index, sizeof(int), + buf, WLC_IOCTL_SMLEN); + if (!err) + err = wl_disp_smfs(buf); + } + else { + for (i = 0; i < SMFS_TYPE_MAX; i++) { + smf_index = i; + err = wlu_iovar_getbuf(wl, "smfstats", &smf_index, + sizeof(int), buf, WLC_IOCTL_SMLEN); + if (!err) + err = wl_disp_smfs(buf); + } + } + } else { + /* use "stats" iovar since a config option was given */ + if (smfs_consumed) { + err = wl_bssiovar_getbuf(wl, "smfstats", bsscfg_idx, &smf_index, + sizeof(int), buf, WLC_IOCTL_SMLEN); + if (!err) + err = wl_disp_smfs(buf); + } + else { + for (i = 0; i < SMFS_TYPE_MAX; i++) { + smf_index = i; + err = wl_bssiovar_getbuf(wl, "smfstats", bsscfg_idx, + &smf_index, sizeof(int), buf, WLC_IOCTL_SMLEN); + if (!err) + err = wl_disp_smfs(buf); + } + } + } + if (err < 0) + return err; + } else { + val = 0; + + if (cfg_consumed == 0) + err = wlu_iovar_setint(wl, "smfstats", val); + else + err = wl_bssiovar_setint(wl, "smfstats", bsscfg_idx, val); + + } + return err; +} + +#ifdef BCMCCX +static int +wl_leap(void *wl, cmd_t *cmd, char **argv) +{ + wl_leap_list_t leap_list, *get_list; + wl_leap_info_t *list_item; + size_t len; + int ret, i; + + if (!*++argv) { + /* no parameter means this is a `get'. */ + len = sizeof(wl_leap_list_t) + 42 * sizeof(wl_leap_info_t); + get_list = (wl_leap_list_t *)malloc(len); + if (!get_list) { + fprintf(stderr, "memory alloc failure\n"); + return BCME_NOMEM; + } + get_list->buflen = htod32(len); + if ((ret = wlu_get(wl, cmd->get, get_list, len)) < 0) { + free(get_list); + return ret; + } + get_list->buflen = dtoh32(get_list->buflen); + get_list->version = dtoh32(get_list->version); + get_list->count = dtoh32(get_list->count); + printf("buflen %d version %d count %d\n", + get_list->buflen, get_list->version, get_list->count); + + for (i = 0, list_item = get_list->leap_info; + i < (int) get_list->count; + i++, list_item++) { + + char user[sizeof(leap_list.leap_info[0].user)+1]; + char pw[sizeof(leap_list.leap_info[0].password)+1]; + char dom[sizeof(leap_list.leap_info[0].domain)+1]; + char ssidbuf[SSID_FMT_BUF_LEN]; + + list_item->ssid.SSID_len = dtoh32(list_item->ssid.SSID_len); + wl_format_ssid(ssidbuf, list_item->ssid.SSID, + list_item->ssid.SSID_len); + memcpy(user, list_item->user, list_item->user_len); + user[list_item->user_len] = '\0'; + memcpy(pw, list_item->password, list_item->password_len); + pw[list_item->password_len] = '\0'; + memcpy(dom, list_item->domain, list_item->domain_len); + dom[list_item->domain_len] = '\0'; + + printf(" % 2d: ssid \"%s\", user \"%s\", password \"%s\", domain \"%s\"\n", + i, ssidbuf, user, pw, dom); + + + } + free(get_list); + return 0; + } + len = strlen(*argv); + /* ssid has to be a leagal size */ + if (len > DOT11_MAX_SSID_LEN) + return BCME_BADARG; + + memset(&leap_list, 0, sizeof(leap_list)); + leap_list.buflen = htod32(sizeof(leap_list)); + leap_list.count = htod32(1); + + leap_list.leap_info[0].ssid.SSID_len = htod32(len); + memcpy(leap_list.leap_info[0].ssid.SSID, *argv, len); + + /* user name must follow */ + if (!*++argv) + return BCME_USAGE_ERROR; + + len = strlen(*argv); + if (len > sizeof(leap_list.leap_info[0].user)) + return BCME_BADARG; + leap_list.leap_info[0].user_len = len; + memcpy(leap_list.leap_info[0].user, *argv, len); + + /* password must follow */ + if (!*++argv) + return BCME_USAGE_ERROR; + + len = strlen(*argv); + if (len > sizeof(leap_list.leap_info[0].password)) + return BCME_BADARG; + leap_list.leap_info[0].password_len = len; + memcpy(leap_list.leap_info[0].password, *argv, len); + + /* If there's more, it's a domain name */ + if (*++argv) { + len = strlen(*argv); + if (len > sizeof(leap_list.leap_info[0].domain)) + return BCME_BADARG; + leap_list.leap_info[0].domain_len = len; + memcpy(leap_list.leap_info[0].domain, *argv, len); + } + + return wlu_set(wl, cmd->set, &leap_list, sizeof(leap_list)); +} +#endif /* BCMCCX */ + +static int +wl_tssi(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + + UNUSED_PARAMETER(argv); + + if (cmd->get < 0) + return -1; + if ((ret = wlu_get(wl, cmd->get, &val, sizeof(int))) < 0) + return ret; + + val = dtoh32(val); + printf("CCK %d OFDM %d\n", (val & 0xff), (val >> 8) & 0xff); + return 0; +} + +/* Quarter dBm units to mW + * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 + * Table is offset so the last entry is largest mW value that fits in + * a uint16. + */ + +#define QDBM_OFFSET 153 /* QDBM_OFFSET */ +#define QDBM_TABLE_LEN 40 /* QDBM_TABLE_LEN */ + +/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. + * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 + */ +#define QDBM_TABLE_LOW_BOUND 6493 /* QDBM_TABLE_LOW_BOUND */ + +/* Largest mW value that will round down to the last table entry, + * QDBM_OFFSET + QDBM_TABLE_LEN-1. + * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. + */ +#define QDBM_TABLE_HIGH_BOUND 64938 /* QDBM_TABLE_HIGH_BOUND */ + +static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { +/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ +/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, +/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, +/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, +/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, +/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 +}; + +static uint16 +wl_qdbm_to_mw(uint8 qdbm) +{ + uint factor = 1; + int idx = qdbm - QDBM_OFFSET; + + if (idx >= QDBM_TABLE_LEN) { + /* clamp to max uint16 mW value */ + return 0xFFFF; + } + + /* scale the qdBm index up to the range of the table 0-40 + * where an offset of 40 qdBm equals a factor of 10 mW. + */ + while (idx < 0) { + idx += 40; + factor *= 10; + } + + /* return the mW value scaled down to the correct factor of 10, + * adding in factor/2 to get proper rounding. + */ + return ((nqdBm_to_mW_map[idx] + factor/2) / factor); +} + +static uint8 +wl_mw_to_qdbm(uint16 mw) +{ + uint8 qdbm; + int offset; + uint mw_uint = mw; + uint boundary; + + /* handle boundary case */ + if (mw_uint <= 1) + return 0; + + offset = QDBM_OFFSET; + + /* move mw into the range of the table */ + while (mw_uint < QDBM_TABLE_LOW_BOUND) { + mw_uint *= 10; + offset -= 40; + } + + for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) { + boundary = nqdBm_to_mW_map[qdbm] + + (nqdBm_to_mW_map[qdbm+1] - nqdBm_to_mW_map[qdbm])/2; + if (mw_uint < boundary) break; + } + + qdbm += (uint8)offset; + + return (qdbm); +} + +#define UNIT_MW 1 /* UNIT_MW */ +#define UNIT_QDBM 2 /* UNIT_QDBM */ +#define UNIT_DBM 3 /* UNIT_DBM */ +static int +wl_txpwr1(void *wl, cmd_t *cmd, char **argv) +{ + int ret, val, new_val = 0, unit; + const char *name = "qtxpower"; + bool override = FALSE; + + if (!*++argv) { + if (cmd->get < 0) + return -1; + if ((ret = wlu_iovar_getint(wl, name, &val)) < 0) + return ret; + + override = ((val & WL_TXPWR_OVERRIDE) != 0); + val &= ~WL_TXPWR_OVERRIDE; + printf("TxPower is %d qdbm, %d.%d dbm, %d mW Override is %s\n", + val, DIV_QUO(val, 4), DIV_REM(val, 4), + wl_qdbm_to_mw((uint8)(MIN(val, 0xff))), + override ? "On" : "Off"); + return 0; + } else { + /* for set */ + unit = UNIT_DBM; /* default units */ + + /* override can be used in combo with any unit */ + if (!strcmp(*argv, "-o")) { + override = TRUE; + if (!*++argv) + return BCME_USAGE_ERROR; + } + + if (!strcmp(*argv, "-d")) { + unit = UNIT_DBM; + argv++; + } + else if (!strcmp(*argv, "-q")) { + unit = UNIT_QDBM; + argv++; + } + else if (!strcmp(*argv, "-m")) { + unit = UNIT_MW; + argv++; + } + + /* override can be used in combo with any unit */ + if (!strcmp(*argv, "-o")) { + override = TRUE; + argv++; + } + + if (!*argv) + return BCME_USAGE_ERROR; + + val = atoi(*argv); + + if (val == -1) { + val = 127; /* Max val of 127 qdbm */ + unit = UNIT_QDBM; + } + + if (val <= 0) { + return BCME_BADARG; + } + + switch (unit) { + case UNIT_MW: + new_val = wl_mw_to_qdbm((uint16)MIN(val, 0xffff)); + break; + case UNIT_DBM: + new_val = val * 4; + break; + case UNIT_QDBM: + new_val = val; + break; + } + + if (override) + new_val |= WL_TXPWR_OVERRIDE; + + return wlu_iovar_setint(wl, name, new_val); + } +} + +static int +wl_txpwr(void *wl, cmd_t *cmd, char **argv) +{ + int error; + uint32 val; + char *endptr = NULL; + uint32 override; + const char *name = "qtxpower"; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) { + if ((error = wlu_iovar_getint(wl, name, (int *)&val)) < 0) + return error; + + /* Report power in mw with WL_TXPWR_OVERRIDE + * bit indicating the status + */ + override = ((val & WL_TXPWR_OVERRIDE) != 0); + val &= ~WL_TXPWR_OVERRIDE; + printf("%d.%d dBm = %d mw. %s\n", DIV_QUO(val, 4), DIV_REM(val, 4), + wl_qdbm_to_mw((uint8)(MIN(val, 0xff))), (override ? "(Override ON)" : "")); + return 0; + } else { + if (!strcmp(*argv, "-u")) { + override = 0; + argv++; + } else + override = WL_TXPWR_OVERRIDE; + + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + + val = wl_mw_to_qdbm((uint16)MIN(val, 0xffff)); + + /* wl command input power will override current power set if told so */ + val |= override; + + return wlu_iovar_setint(wl, name, val); + } +} + +static int +wl_get_txpwr_limit(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + uint8 val_qdbm; + uint16 val_mw; + tx_power_legacy_t power; + + UNUSED_PARAMETER(argv); + + ret = wlu_get(wl, cmd->get, &power, sizeof(power)); + if (ret < 0) + return ret; + + val_qdbm = MIN(power.txpwr_band_max[0], power.txpwr_local_max); + val_mw = wl_qdbm_to_mw((uint8)(MIN(val_qdbm, 0xff))); + + printf("%d mW (%d.%d dBm)\n", val_mw, DIV_QUO(val_qdbm, 4), DIV_REM(val_qdbm, 4)); + + return ret; +} + +static int +wl_atten(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + atten_t atten; + char *endptr; + + memset(&atten, 0, sizeof(atten_t)); + + if (!*++argv) { + if (cmd->get < 0) + return -1; + + if ((ret = wlu_get(wl, cmd->get, &atten, sizeof(atten_t))) < 0) + return ret; + + printf("tx %s bb/radio/ctl1 %d/%d/%d\n", + (dtoh16(atten.auto_ctrl) ? "auto" : ""), + dtoh16(atten.bb), dtoh16(atten.radio), dtoh16(atten.txctl1)); + + return 0; + } else { + if (cmd->set < 0) + return -1; + + if (!stricmp(*argv, "auto")) { + atten.auto_ctrl = WL_ATTEN_PCL_ON; + atten.auto_ctrl = htod16(atten.auto_ctrl); + } + else if (!stricmp(*argv, "manual")) { + atten.auto_ctrl = WL_ATTEN_PCL_OFF; + atten.auto_ctrl = htod16(atten.auto_ctrl); + } + else { + atten.auto_ctrl = WL_ATTEN_APP_INPUT_PCL_OFF; + atten.auto_ctrl = htod16(atten.auto_ctrl); + + atten.bb = (uint16)strtoul(*argv, &endptr, 0); + atten.bb = htod16(atten.bb); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + + if (!*++argv) + return BCME_USAGE_ERROR; + + atten.radio = (uint16)strtoul(*argv, &endptr, 0); + atten.radio = htod16(atten.radio); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + + if (!*++argv) + return BCME_USAGE_ERROR; + + atten.txctl1 = (uint16)strtoul(*argv, &endptr, 0); + atten.txctl1 = htod16(atten.txctl1); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + return BCME_USAGE_ERROR; + } + + } + + return wlu_set(wl, cmd->set, &atten, sizeof(atten_t)); + } +} + +static int +wl_maclist(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + struct maclist *maclist = (struct maclist *) buf; + struct ether_addr *ea; + uint i, max = (WLC_IOCTL_MAXLEN - sizeof(int)) / ETHER_ADDR_LEN; + uint len; + + if (!*++argv) { + if (cmd->get < 0) + return -1; + maclist->count = htod32(max); + if ((ret = wlu_get(wl, cmd->get, maclist, WLC_IOCTL_MAXLEN)) < 0) + return ret; + maclist->count = dtoh32(maclist->count); + for (i = 0, ea = maclist->ea; i < maclist->count && i < max; i++, ea++) + printf("%s %s\n", cmd->name, wl_ether_etoa(ea)); + return 0; + } else { + if (cmd->set < 0) + return -1; + /* Clear list */ + maclist->count = htod32(0); + if (!stricmp(*argv, "none") || !stricmp(*argv, "clear")) + return wlu_set(wl, cmd->set, maclist, sizeof(int)); + /* Get old list */ + maclist->count = htod32(max); + if ((ret = wlu_get(wl, cmd->get, maclist, WLC_IOCTL_MAXLEN)) < 0) + return ret; + /* Append to old list */ + maclist->count = dtoh32(maclist->count); + ea = &maclist->ea[maclist->count]; + while (*argv && maclist->count < max) { + if (!wl_ether_atoe(*argv, ea)) { + printf("Problem parsing MAC address \"%s\".\n", *argv); + return BCME_USAGE_ERROR; + } + maclist->count++; + ea++; + argv++; + } + /* Set new list */ + len = sizeof(maclist->count) + maclist->count * sizeof(maclist->ea); + maclist->count = htod32(maclist->count); + return wlu_set(wl, cmd->set, maclist, len); + } +} + +static int +wl_maclist_1(void *wl, cmd_t *cmd, char **argv) +{ + struct maclist *maclist; + struct ether_addr *ea; + uint i; + int ret; + + strcpy(buf, argv[0]); + + if ((ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return ret; + + maclist = (struct maclist *)buf; + + for (i = 0, ea = maclist->ea; i < dtoh32(maclist->count); i++, ea++) + printf("%s %s\n", cmd->name, wl_ether_etoa(ea)); + return 0; +} + +static int +wl_out(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + return wlu_set(wl, WLC_OUT, NULL, 0); +} + +static int +wl_band(void *wl, cmd_t *cmd, char **argv) +{ + uint band; + int error; + + UNUSED_PARAMETER(cmd); + + error = 0; + + argv++; + + if (*argv == NULL) { /* get current band */ + if ((error = wlu_get(wl, WLC_GET_BAND, &band, sizeof(uint))) < 0) + return (error); + band = dtoh32(band); + + if (band == WLC_BAND_AUTO) + printf("auto\n"); + else if (band == WLC_BAND_5G) + printf("a\n"); + else if (band == WLC_BAND_2G) + printf("b\n"); + else { + printf("unrecognized band value %d\n", band); + error = BCME_ERROR; + } + } else { /* set the band */ + if (!stricmp(*argv, "auto")) + band = WLC_BAND_AUTO; + else if (!stricmp(*argv, "a")) + band = WLC_BAND_5G; + else if (!stricmp(*argv, "b")) + band = WLC_BAND_2G; + else { + printf("unsupported band: %s\n", *argv); + return BCME_UNSUPPORTED; + } + + band = htod32(band); + error = wlu_set(wl, WLC_SET_BAND, &band, sizeof(uint)); + + } + return (error); +} + +static int +wl_bandlist(void *wl, cmd_t *cmd, char **argv) +{ + uint list[3]; + int error; + uint i; + + UNUSED_PARAMETER(cmd); + + error = 0; + + argv++; + + if ((error = wlu_get(wl, WLC_GET_BANDLIST, list, sizeof(list))) < 0) + return (error); + list[0] = dtoh32(list[0]); + list[1] = dtoh32(list[1]); + list[2] = dtoh32(list[2]); + + /* list[0] is count, followed by 'count' bands */ + + if (list[0] > 2) + list[0] = 2; + + for (i = 1; i <= list[0]; i++) + if (list[i] == WLC_BAND_5G) + printf("a "); + else if (list[i] == WLC_BAND_2G) + printf("b "); + else + printf("? "); + printf("\n"); + + return (0); +} + +static int +wl_phylist(void *wl, cmd_t *cmd, char **argv) +{ + char phylist_buf[128]; + int error; + char *cp; + + UNUSED_PARAMETER(cmd); + + error = 0; + + argv++; + + if ((error = wlu_get(wl, WLC_GET_PHYLIST, phylist_buf, sizeof(phylist_buf))) < 0) + return (error); + + cp = phylist_buf; + + for (; *cp; cp++) + printf("%c ", *cp); + printf("\n"); + + return (0); +} + +#define UPGRADE_BUFSIZE 512 /* upgrade buffer size */ + +static int +wl_upgrade(void *wl, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv); + return (-1); +#else + FILE *fp; + int ret = 0; + struct { + uint32 offset; + char buf[UPGRADE_BUFSIZE]; + } block; + uint32 offset; + uint len; + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!(fp = fopen(*argv, "rb"))) { + fprintf(stderr, "%s: No such file or directory\n", *argv); + return BCME_BADARG; + } + + printf("Programming %s...", *argv); + fflush(stdout); + offset = 0; + block.offset = htod32(offset); + while ((len = fread(block.buf, 1, sizeof(block.buf), fp))) { + if ((ret = wlu_set(wl, cmd->set, &block, 4 + len)) < 0) + break; + offset += len; + block.offset = htod32(offset); + printf("."); + fflush(stdout); + } + + if (ferror(fp)) { + ret = ferror(fp); + printf("\nerror reading %s\n", *argv); + } else { + long status = WLC_UPGRADE_PENDING; + int retries; + + printf("\nCommitting image to flash...\n"); + while (status == WLC_UPGRADE_PENDING) { + retries = 10; +retry: + if ((ret = wlu_get(wl, WLC_UPGRADE_STATUS, + &status, sizeof(status))) < 0) { + /* the first attempt to get status will + * likely fail due to dev reset + */ + if (retries--) + goto retry; + break; + } + status = dtoh32(status); + } + if (status == WLC_UPGRADE_SUCCESS) + printf("\nDone\n\nSuccessfully downloaded %d bytes\n", block.offset); + else + fprintf(stderr, "\n*** UPGRADE FAILED! *** (status %ld)\n", status); + } + + fclose(fp); + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +#include <bcmnvram.h> + +static int +wl_otpraw(void *wl, cmd_t *cmd, char **argv) +{ + char var[392]; + uint32 offset; + uint32 bits; + uint32 len; + bool get = TRUE; + void *ptr = NULL; + char *endptr; + uint32 i; + + if (argv[1]) { + offset = htod32(strtoul(argv[1], &endptr, 0)); + memcpy(var, (char *)&offset, sizeof(offset)); + len = sizeof(offset); + } + else + return BCME_USAGE_ERROR; + + if (argv[2]) { + bits = htod32(strtoul(argv[2], &endptr, 0)); + if (bits > 3072) + { + printf("bit size (%d) too long or negative!!\n", bits); + return BCME_BADARG; + } + } + else + bits = 1; + + memcpy(&var[len], (char *)&bits, sizeof(bits)); + len += sizeof(bits); + + if (argv[3]) { + unsigned char data[768]; + uint32 patlen; + char *inptr = argv[3]; + + get = FALSE; + + if (*inptr == '0' && toupper((int)(*(inptr + 1))) == 'X') + inptr += 2; + + patlen = strlen(inptr); + if (patlen > 768 || (patlen * 4) < bits) + { + printf("data length (%d) too long or small!!\n", patlen); + return BCME_USAGE_ERROR; + } + + for (i = 1; i <= patlen; i++) + { + int n = (int)((unsigned char)*inptr++); + if (!isxdigit(n)) { + fprintf(stderr, "invalid hex digit %c\n", n); + return BCME_USAGE_ERROR; + } + data[patlen - i] = (unsigned char)(isdigit(n) ? (n - '0') + : ((islower(n) ? (toupper(n)) : n) - 'A' + 10)); + } + + for (i = 0; i < patlen; i += 2) + { + unsigned char v; + v = data[i]; + if (i + 1 < patlen) + v += (data[i+1] * 16); + memcpy(&var[len], (char *)&v, sizeof(v)); + len += sizeof(v); + } + + printf("OTP RAM Write:"); + for (i = 0; i < bits; i += 8) + { + unsigned char v; + v = var[2*sizeof(uint32) + (i/8)]; + + if ((i % 64) == 0) + printf("\nbit %4d:", offset + i); + printf(" 0x%x", v); + } + printf("\n"); + + } + + if (get) { + int ret; + unsigned char v, *cptr; + + if ((ret = wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr)) < 0) { + printf("Error reading from OTP data\n"); + return ret; + } + + cptr = (unsigned char *)ptr; + + printf("OTP RAM Read:"); + for (i = 0; i < bits; i += 8) + { + v = *cptr++; + + if ((i % 64) == 0) + printf("\nbit %4d:", offset + i); + printf(" 0x%02x", v); + } + printf("\n"); + return 0; + } + + return wlu_var_setbuf(wl, cmd->name, &var, sizeof(var)); +} + +static int +wl_otpw(void *wl, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv); + return (-1); +#else + FILE *fp; + int ret = 0; + struct nvram_header *nvr; + char *p, otpw_buf[1024 - 128]; + const char *msg; + int len; + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!(fp = fopen(*argv, "rb"))) { + fprintf(stderr, "%s: No such file or directory\n", *argv); + return BCME_BADARG; + } + + len = fread(otpw_buf, 1, sizeof(otpw_buf) - 1, fp); + if ((ret = ferror(fp))) { + printf("\nerror %d reading %s\n", ret, *argv); + ret = BCME_ERROR; + goto out; + } + if (!feof(fp)) { + printf("\nFile %s too large\n", *argv); + ret = BCME_ERROR; + goto out; + } + + /* Got the bits, do they look like the output of nvserial? */ + nvr = (struct nvram_header *)otpw_buf; + if (nvr->magic == NVRAM_MAGIC) { + if (cmd->set == WLC_OTPW) { + printf("File %s looks like an nvserial file, use nvotpw\n", *argv); + fflush(stdout); + ret = BCME_ERROR; + goto out; + } + len = nvr->len - sizeof(struct nvram_header); + if (len <= 0) { + printf("Invalid length (%d)\n", len); + ret = BCME_ERROR; + goto out; + } + if (len & 1) { + otpw_buf[len++] = '\0'; + } + p = (char *)(nvr + 1); + msg = "nvserial"; + } else { + if (cmd->set == WLC_NVOTPW) { + printf("File %s is not an nvserial file\n", *argv); + ret = BCME_ERROR; + goto out; + } + if (len & 1) { + printf("File %s has an odd length (%d)\n", *argv, len); + ret = BCME_ERROR; + goto out; + } + p = otpw_buf; + msg = "raw"; + } + + printf("Writing %d bytes from %s file %s to otp ...\n", len, msg, *argv); + fflush(stdout); + + if ((ret = wlu_set(wl, cmd->set, p, len)) < 0) { + printf("\nError %d writing %s to otp\n", ret, *argv); + } + +out: + fclose(fp); + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +static int +wl_get_pktcnt(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + get_pktcnt_t pktcnt; + + UNUSED_PARAMETER(argv); + + memset(&pktcnt, 0, sizeof(pktcnt)); + if ((ret = wlu_get(wl, cmd->get, &pktcnt, sizeof(pktcnt))) < 0) + return ret; + + printf("Receive: good packet %d, bad packet %d, othercast good packet %d\n", + dtoh32(pktcnt.rx_good_pkt), dtoh32(pktcnt.rx_bad_pkt), + dtoh32(pktcnt.rx_ocast_good_pkt)); + printf("Transmit: good packet %d, bad packet %d\n", + dtoh32(pktcnt.tx_good_pkt), dtoh32(pktcnt.tx_bad_pkt)); + + return ret; +} + +static int +wl_interfere(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + char *endptr = NULL; + int mode; + + if (!*++argv) { + if (cmd->get < 0) + return -1; + if ((ret = wlu_get(wl, cmd->get, &mode, sizeof(mode))) < 0) + return ret; + mode = dtoh32(mode); + switch (mode & 0x7f) { + case INTERFERE_NONE: + printf("All interference mitigation is disabled. (mode 0)\n"); + break; + case NON_WLAN: + printf("Non-wireless LAN Interference mitigation is enabled. (mode 1)\n"); + break; + case WLAN_MANUAL: + printf("Wireless LAN Interference mitigation is enabled. (mode 2)\n"); + break; + case WLAN_AUTO: + printf("Auto Wireless LAN Interference mitigation is enabled and "); + if (mode & AUTO_ACTIVE) + printf("active. (mode 3)\n"); + else + printf("not active. (mode 3)\n"); + + break; + case WLAN_AUTO_W_NOISE: + printf("Auto Wireless LAN Interference mitigation is enabled and "); + if (mode & AUTO_ACTIVE) + printf("active, "); + else + printf("not active, "); + + printf("and noise reduction is enabled. (mode 4)\n"); + break; + } + return 0; + } else { + mode = INTERFERE_NONE; + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + switch (val) { + case 0: + mode = INTERFERE_NONE; + break; + case 1: + mode = NON_WLAN; + break; + case 2: + mode = WLAN_MANUAL; + break; + case 3: + mode = WLAN_AUTO; + break; + case 4: + mode = WLAN_AUTO_W_NOISE; + break; + default: + return BCME_BADARG; + } + + mode = htod32(mode); + return wlu_set(wl, cmd->set, &mode, sizeof(mode)); + } +} + +static int +wl_interfere_override(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + char *endptr; + int mode; + + if (!*++argv) { + if (cmd->get < 0) + return -1; + if ((ret = wlu_get(wl, cmd->get, &mode, sizeof(mode))) < 0) { + return ret; + } + mode = dtoh32(mode); + switch (mode) { + case INTERFERE_NONE: + printf("Interference override NONE, " + "all mitigation disabled. (mode 0)\n"); + break; + case NON_WLAN: + printf("Interference override enabled. " + " Non-wireless LAN Interference mitigation is enabled. (mode 1)\n"); + break; + case WLAN_MANUAL: + printf("Interference override enabled. " + " Wireless LAN Interference mitigation is enabled. (mode 2)\n"); + break; + case WLAN_AUTO: + printf("Interference override enabled. " + " Interference mitigation is enabled and "); + if (mode & AUTO_ACTIVE) + printf("active. (mode 3)\n"); + else + printf("not active. (mode 3)\n"); + + break; + case WLAN_AUTO_W_NOISE: + printf("Interference override enabled. " + " Interference mitigation is enabled and "); + if (mode & AUTO_ACTIVE) + printf("active, "); + else + printf("not active, "); + + printf("and noise reduction is enabled. (mode 4)\n"); + break; + case INTERFERE_OVRRIDE_OFF: + printf("Interference override disabled. \n"); + break; + } + return 0; + } else { + mode = INTERFERE_NONE; + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + switch (val) { + case 0: + mode = INTERFERE_NONE; + break; + case 1: + mode = NON_WLAN; + break; + case 2: + mode = WLAN_MANUAL; + break; + case 3: + mode = WLAN_AUTO; + break; + case 4: + mode = WLAN_AUTO_W_NOISE; + break; + case INTERFERE_OVRRIDE_OFF: + mode = INTERFERE_OVRRIDE_OFF; + break; + default: + return BCME_BADARG; + } + + mode = htod32(mode); + return wlu_set(wl, cmd->set, &mode, sizeof(mode)); + } +} + +static cntry_name_t * +wlc_cntry_name_to_country(char *long_name) +{ + cntry_name_t *cntry; + for (cntry = cntry_names; cntry->name && + stricmp(long_name, cntry->name); cntry++); + return (!cntry->name ? NULL : cntry); +} + +static cntry_name_t * +wlc_cntry_abbrev_to_country(const char *abbrev) +{ + cntry_name_t *cntry; + if (!*abbrev || strlen(abbrev) > 3 || strlen(abbrev) < 2) + return (NULL); + for (cntry = cntry_names; cntry->name && + strnicmp(abbrev, cntry->abbrev, strlen(abbrev)); cntry++); + return (!cntry->name ? NULL : cntry); +} + +static int +wl_parse_country_spec(const char *spec, char *ccode, int *regrev) +{ + char *revstr; + char *endptr = NULL; + int ccode_len; + int rev = -1; + + revstr = strchr(spec, '/'); + + if (revstr) { + rev = strtol(revstr + 1, &endptr, 10); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + fprintf(stderr, + "Could not parse \"%s\" as a regulatory revision " + "in the country string \"%s\"\n", + revstr + 1, spec); + return BCME_USAGE_ERROR; + } + } + + if (revstr) + ccode_len = (int)(uintptr)(revstr - spec); + else + ccode_len = (int)strlen(spec); + + if (ccode_len > 3) { + fprintf(stderr, + "Could not parse a 2-3 char country code " + "in the country string \"%s\"\n", + spec); + return BCME_USAGE_ERROR; + } + + memcpy(ccode, spec, ccode_len); + ccode[ccode_len] = '\0'; + *regrev = rev; + + return 0; +} + +int +wl_country(void *wl, cmd_t *cmd, char **argv) +{ + cntry_name_t *cntry; + wl_country_t cspec = {{0}, 0, {0}}; + int argc = 0; + int err; + int bcmerr = 1; + + /* skip the command name */ + argv++; + + /* find the arg count */ + while (argv[argc]) + argc++; + + /* check arg list count */ + if (argc > 2) { + fprintf(stderr, "Too many arguments (%d) for command %s\n", argc, cmd->name); + return BCME_USAGE_ERROR; + } + + buf[0] = 0; + if (argc == 0) { + const char* name = "<unknown>"; + + /* first try the country iovar */ + err = wlu_iovar_get(wl, "country", &cspec, sizeof(cspec)); + + if (!err) { + cntry = wlc_cntry_abbrev_to_country(cspec.country_abbrev); + if (cntry) + name = cntry->name; + cspec.rev = dtoh32(cspec.rev); + + printf("%s (%s/%d) %s\n", + cspec.country_abbrev, cspec.ccode, cspec.rev, name); + + return 0; + } + + /* if there was an error other than BCME_UNSUPPORTED, fail now */ + wlu_iovar_getint(wl, "bcmerror", &bcmerr); + if (bcmerr != BCME_UNSUPPORTED) + return err; + + /* if the "country" iovar is unsupported, try the WLC_SET_COUNTRY ioctl */ + if ((err = wlu_get(wl, cmd->get, &buf[0], WLC_IOCTL_SMLEN)) < 0) + return err; + if (strlen(buf) == 0) { + printf("No country set\n"); + return 0; + + } + cntry = wlc_cntry_abbrev_to_country(buf); + if (cntry != NULL) + name = cntry->name; + + printf("%s () %s\n", buf, name); + return 0; + } + + if (!stricmp(*argv, "list")) { + uint i; + const char* abbrev; + wl_country_list_t *cl = (wl_country_list_t *)buf; + + cl->buflen = WLC_IOCTL_MAXLEN; + cl->count = 0; + + /* band may follow */ + if (*++argv) { + cl->band_set = TRUE; + if (!stricmp(*argv, "a")) + cl->band = WLC_BAND_5G; + else if (!stricmp(*argv, "b") || !stricmp(*argv, "g")) + cl->band = WLC_BAND_2G; + else { + printf("unsupported band: %s\n", *argv); + return BCME_UNSUPPORTED; + } + } else { + cl->band_set = FALSE; + } + + cl->buflen = htod32(cl->buflen); + cl->band_set = htod32(cl->band_set); + cl->band = htod32(cl->band); + cl->count = htod32(cl->count); + err = wlu_get(wl, WLC_GET_COUNTRY_LIST, buf, WLC_IOCTL_MAXLEN); + if (err < 0) + return err; + + printf("Supported countries: country code and long name\n"); + for (i = 0; i < dtoh32(cl->count); i++) { + abbrev = &cl->country_abbrev[i*WLC_CNTRY_BUF_SZ]; + cntry = wlc_cntry_abbrev_to_country(abbrev); + printf("%s\t%s\n", abbrev, cntry ? cntry->name : ""); + } + return 0; + } + + memset(&cspec, 0, sizeof(cspec)); + cspec.rev = -1; + + if (argc == 1) { + /* check for the first arg being a country name, e.g. "United States", + * or country spec, "US/1", or just a country code, "US" + */ + if ((cntry = wlc_cntry_name_to_country(argv[0])) != NULL) { + /* arg matched a country name */ + memcpy(cspec.country_abbrev, cntry->abbrev, WLC_CNTRY_BUF_SZ); + err = 0; + } else { + /* parse a country spec, e.g. "US/1", or a country code. + * cspec.rev will be -1 if not specified. + */ + err = wl_parse_country_spec(argv[0], cspec.country_abbrev, &cspec.rev); + } + + if (err) { + fprintf(stderr, + "Argument \"%s\" could not be parsed as a country name, " + "country code, or country code and regulatory revision.\n", + argv[0]); + return BCME_USAGE_ERROR; + } + + /* if the arg was a country spec, then fill out ccdoe and rev, + * and leave country_abbrev defaulted to the ccode + */ + if (cspec.rev != -1) + memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ); + } else { + /* for two args, the first needs to be a country code or country spec */ + err = wl_parse_country_spec(argv[0], cspec.ccode, &cspec.rev); + if (err) { + fprintf(stderr, + "Argument 1 \"%s\" could not be parsed as a country code, or " + "country code and regulatory revision.\n", + argv[0]); + return BCME_USAGE_ERROR; + } + + /* the second arg needs to be a country name or country code */ + if ((cntry = wlc_cntry_name_to_country(argv[1])) != NULL) { + /* arg matched a country name */ + memcpy(cspec.country_abbrev, cntry->abbrev, WLC_CNTRY_BUF_SZ); + } else { + int rev; + err = wl_parse_country_spec(argv[1], cspec.country_abbrev, &rev); + if (rev != -1) { + fprintf(stderr, + "Argument \"%s\" had a revision. Arg 2 must be " + "a country name or country code without a revision\n", + argv[1]); + return BCME_USAGE_ERROR; + } + } + + if (err) { + fprintf(stderr, + "Argument 2 \"%s\" could not be parsed as " + "a country name or country code\n", + argv[1]); + return BCME_USAGE_ERROR; + } + } + + /* first try the country iovar */ + if (cspec.rev == -1 && cspec.ccode[0] == '\0') + err = wlu_iovar_set(wl, "country", &cspec, WLC_CNTRY_BUF_SZ); + else { + cspec.rev = htod32(cspec.rev); + err = wlu_iovar_set(wl, "country", &cspec, sizeof(cspec)); + } + + if (err == 0) + return 0; + + /* if there was an error other than BCME_UNSUPPORTED, fail now */ + wlu_iovar_getint(wl, "bcmerror", &bcmerr); + if (bcmerr != BCME_UNSUPPORTED) + return err; + + /* if the "country" iovar is unsupported, try the WLC_SET_COUNTRY ioctl if possible */ + + if (cspec.rev != -1 || cspec.ccode[0] != '\0') { + fprintf(stderr, + "Driver does not support full country spec interface, " + "only a country name or code may be sepcified\n"); + return err; + } + + /* use the legacy ioctl */ + err = wlu_set(wl, WLC_SET_COUNTRY, cspec.country_abbrev, WLC_CNTRY_BUF_SZ); + + return err; +} + +int +wl_country_ie_override(void *wl, cmd_t *cmd, char **argv) +{ + int argc = 0; + int error, i; + + /* skip the command name */ + argv++; + + /* find the arg count */ + while (argv[argc]) + argc++; + + if (argc == 0) { + void *ptr; + bcm_tlv_t *ie; + + if ((error = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return (error); + + ie = (bcm_tlv_t *)ptr; + + printf("ie tag:0x%x ie len:0x%x ie data:", ie->id, ie->len); + + for (i = 0; i < ie->len; i++) + printf("0x%x ", ie->data[i]); + + printf("\n"); + + return error; + + } else { + /* Set */ + char *endptr = NULL; + uchar *valsp; + int8 ie_len, pad = 0; + + /* retrieve the ie len in advance to check for padding */ + ie_len = (int8)strtol(*(argv + 1), NULL, 0); + if (ie_len & 1) { + fprintf(stderr, "country ie len is odd(%d), padding by 1 octet\n", ie_len); + pad = 1; + } + + valsp = (uchar*)malloc(argc + pad); + if (valsp == NULL) { + fprintf(stderr, "Error allocating %d bytes country ie\n", argc); + return BCME_NOMEM; + } + memset(valsp, 0, argc + pad); + + for (i = 0; i < argc; i++, argv++) { + + valsp[i] = (uchar)strtol(*argv, &endptr, 0); + + /* make sure all the value string was parsed by strtol */ + if (*endptr != '\0') { + free(valsp); + return BCME_USAGE_ERROR; + } + } + + /* update ie len if padded */ + if (pad) { + valsp[1] += 1; + valsp[ie_len + TLV_HDR_LEN] = 0; + } + + error = wlu_var_setbuf(wl, cmd->name, valsp, argc + pad); + + free(valsp); + + return error; + } +} + +#define ACI_SPIN "spin" +#define ACI_ENTER "enter" +#define ACI_EXIT "exit" +#define ACI_GLITCH "glitch" + +#define NPHY_ACI_ADCPWR_ENTER "adcpwr_enter" +#define NPHY_ACI_ADCPWR_EXIT "adcpwr_exit" +#define NPHY_ACI_REPEAT_CTR "repeat" +#define NPHY_ACI_NUM_SAMPLES "samples" +#define NPHY_ACI_UNDETECT "undetect_sz" +#define NPHY_ACI_LOPWR "loaci" +#define NPHY_ACI_MDPWR "mdaci" +#define NPHY_ACI_HIPWR "hiaci" +#define NPHY_ACI_NOISE_NOASSOC_GLITCH_TH_UP "nphy_noise_noassoc_glitch_th_up" +#define NPHY_ACI_NOISE_NOASSOC_GLITCH_TH_DN "nphy_noise_noassoc_glitch_th_dn" +#define NPHY_ACI_NOISE_ASSOC_GLITCH_TH_UP "nphy_noise_assoc_glitch_th_up" +#define NPHY_ACI_NOISE_ASSOC_GLITCH_TH_DN "nphy_noise_assoc_glitch_th_dn" +#define NPHY_ACI_NOISE_ASSOC_ACI_GLITCH_TH_UP "nphy_noise_assoc_aci_glitch_th_up" +#define NPHY_ACI_NOISE_ASSOC_ACI_GLITCH_TH_DN "nphy_noise_assoc_aci_glitch_th_dn" +#define NPHY_ACI_NOISE_NOASSOC_ENTER_TH "nphy_noise_noassoc_enter_th" +#define NPHY_ACI_NOISE_ASSOC_ENTER_TH "nphy_noise_assoc_enter_th" +#define NPHY_ACI_NOISE_ASSOC_RX_GLITCH_BADPLCP_ENTER_TH \ +"nphy_noise_assoc_rx_glitch_badplcp_enter_th" +#define NPHY_ACI_NOISE_ASSOC_CRSIDX_INCR "nphy_noise_assoc_crsidx_incr" +#define NPHY_ACI_NOISE_NOASSOC_CRSIDX_INCR "nphy_noise_noassoc_crsidx_incr" +#define NPHY_ACI_NOISE_CRSIDX_DECR "nphy_noise_crsidx_decr" + + +#if defined(BWL_FILESYSTEM_SUPPORT) +static int +wl_do_samplecollect_lcn40(void *wl, wl_samplecollect_args_t *collect, uint8 *buff, FILE *fp) +{ + uint32 cnt; + int ret = 0; + uint32 *data; + int16 IData, QData; + uint16 wordlength = 14; + uint16 mask = ((0x1 << wordlength) - 1); + uint16 wrap = (0x1 << (wordlength - 1)); + uint16 maxd = (0x1 << wordlength); + + ret = wlu_iovar_getbuf(wl, "sample_collect", collect, sizeof(wl_samplecollect_args_t), + buff, WLC_SAMPLECOLLECT_MAXLEN); + + if (ret) + return ret; + + data = (uint32*)buff; + for (cnt = 0; cnt < collect->nsamps; cnt++) { + + IData = data[cnt] & mask; + QData = ((data[cnt] >> 16) & mask); + + if (IData >= wrap) { + IData = IData - maxd; + } + if (QData >= wrap) { + QData = QData - maxd; + } + fprintf(fp, "%d %d\n", IData, QData); + } + return cnt; +} +static int +wl_do_samplecollect_n(void *wl, wl_samplecollect_args_t *collect, uint8 *buff, FILE *fp) +{ + uint16 nbytes; + int ret = 0; + + ret = wlu_iovar_getbuf(wl, "sample_collect", collect, sizeof(wl_samplecollect_args_t), + buff, WLC_SAMPLECOLLECT_MAXLEN); + + if (ret) + return ret; + + /* bytes 1:0 indicate capture length */ + while ((nbytes = ltoh16_ua(buff))) { + nbytes += 2; + ret = fwrite(buff, 1, nbytes, fp); + if (ret != nbytes) { + fprintf(stderr, "Error writing %d bytes to file, rc %d!\n", + nbytes, ret); + ret = -1; + break; + } else { + fprintf(stderr, "Wrote %d bytes\n", nbytes); + } + buff += nbytes; + } + return (ret); +} +#endif /* defined(BWL_FILESYSTEM_SUPPORT) */ + +#if defined(BWL_FILESYSTEM_SUPPORT) +static int +wl_do_samplecollect(void *wl, wl_samplecollect_args_t *collect, int sampledata_version, + uint32 *buff, FILE *fp) +{ + uint16 nbytes, tag; + uint32 flag, *header, sync; + uint8 *ptr; + int err; + wl_sampledata_t *sample_collect; + wl_sampledata_t sample_data, *psample; + + err = wlu_iovar_getbuf(wl, "sample_collect", collect, sizeof(wl_samplecollect_args_t), + buff, WLC_SAMPLECOLLECT_MAXLEN); + + if (err) + return err; + + sample_collect = (wl_sampledata_t *)buff; + header = (uint32 *)&sample_collect[1]; + tag = ltoh16_ua(&sample_collect->tag); + if (tag != WL_SAMPLEDATA_HEADER_TYPE) { + fprintf(stderr, "Expect SampleData Header type %d, receive type %d\n", + WL_SAMPLEDATA_HEADER_TYPE, tag); + return -1; + } + + nbytes = ltoh16_ua(&sample_collect->length); + flag = ltoh32_ua(&sample_collect->flag); + sync = ltoh32_ua(&header[0]); + if (sync != 0xACDC2009) { + fprintf(stderr, "Header sync word mismatch (0x%08x)\n", sync); + return -1; + } + + err = fwrite((uint8 *)header, 1, nbytes, fp); + if (err != (int)nbytes) + fprintf(stderr, "Failed write file-header to file %d\n", err); + + memset(&sample_data, 0, sizeof(wl_sampledata_t)); + sample_data.version = sampledata_version; + sample_data.size = htol16(sizeof(wl_sampledata_t)); + flag = 0; + /* new format, used in htphy */ + do { + sample_data.tag = htol16(WL_SAMPLEDATA_TYPE); + sample_data.length = htol16(WLC_SAMPLECOLLECT_MAXLEN); + /* mask seq# */ + sample_data.flag = htol32((flag & 0xff)); + + err = wlu_iovar_getbuf(wl, "sample_data", &sample_data, sizeof(wl_sampledata_t), + buff, WLC_SAMPLECOLLECT_MAXLEN); + if (err) { + fprintf(stderr, "Error reading back sample collected data\n"); + err = -1; + break; + } + + ptr = (uint8 *)buff + sizeof(wl_sampledata_t); + psample = (wl_sampledata_t *)buff; + tag = ltoh16_ua(&psample->tag); + nbytes = ltoh16_ua(&psample->length); + flag = ltoh32_ua(&psample->flag); + if (tag != WL_SAMPLEDATA_TYPE) { + fprintf(stderr, "Expect SampleData type %d, receive type %d\n", + WL_SAMPLEDATA_TYPE, tag); + err = -1; + break; + } + if (nbytes == 0) { + fprintf(stderr, "Done retrieving sample data\n"); + err = -1; + break; + } + + err = fwrite(ptr, 1, nbytes, fp); + if (err != (int)nbytes) { + fprintf(stderr, "Error writing %d bytes to file, rc %d!\n", + (int)nbytes, err); + err = -1; + break; + } else { + printf("Wrote %d bytes\n", err); + err = 0; + } + } while (flag & WL_SAMPLEDATA_MORE_DATA); + return err; +} +#endif /* defined(BWL_FILESYSTEM_SUPPORT) */ + +static int +wl_sample_collect(void *wl, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); UNUSED_PARAMETER(argv); + return (-1); +#else + int ret = -1; + uint8 *buff = NULL; + wl_samplecollect_args_t collect; + wlc_rev_info_t revinfo; + uint32 phytype; + uint32 phyrev; + const char *fname = "sample_collect.dat"; + FILE *fp = NULL; + + /* Default setting for sampledata_version */ + int sampledata_version = htol16(WL_SAMPLEDATA_T_VERSION); + + UNUSED_PARAMETER(cmd); + + memset(&revinfo, 0, sizeof(revinfo)); + if ((ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0) + return ret; + + phytype = dtoh32(revinfo.phytype); + phyrev = dtoh32(revinfo.phyrev); + + /* Assign some default params first */ + /* 60us is roughly the max we can store (for NPHY with NREV < 7). */ + collect.coll_us = 60; + collect.cores = -1; + collect.bitStart = -1; + /* extended settings */ + collect.trigger = TRIGGER_NOW; + collect.mode = 1; + collect.post_dur = 10; + collect.pre_dur = 10; + collect.gpio_sel = 0; + collect.downsamp = FALSE; + collect.be_deaf = FALSE; + collect.timeout = 1000; + collect.agc = FALSE; + collect.filter = FALSE; + collect.trigger_state = 0; + collect.module_sel1 = 2; + collect.module_sel2 = 6; + collect.nsamps = 2048; + collect.version = WL_SAMPLECOLLECT_T_VERSION; + collect.length = sizeof(wl_samplecollect_args_t); + + /* Skip the command name */ + argv++; + ret = -1; + while (*argv) { + char *s = *argv; + + if (argv[1] == NULL) { + ret = BCME_USAGE_ERROR; + goto exit; + } + if (!strcmp(s, "-f")) { + fname = argv[1]; + } else if (!strcmp(s, "-u")) + collect.coll_us = atoi(argv[1]); + else if (!strcmp(s, "-c")) + collect.cores = atoi(argv[1]); + /* extended settings */ + else if (!strcmp(s, "-t")) { + /* event trigger */ + if (!strcmp(argv[1], "crs")) + collect.trigger = TRIGGER_CRS; + else if (!strcmp(argv[1], "crs_deassert")) + collect.trigger = TRIGGER_CRSDEASSERT; + else if (!strcmp(argv[1], "good_fcs")) + collect.trigger = TRIGGER_GOODFCS; + else if (!strcmp(argv[1], "bad_fcs")) + collect.trigger = TRIGGER_BADFCS; + else if (!strcmp(argv[1], "bad_plcp")) + collect.trigger = TRIGGER_BADPLCP; + else if (!strcmp(argv[1], "crs_glitch")) + collect.trigger = TRIGGER_CRSGLITCH; + } + else if (!strcmp(s, "-m")) { + if (!strcmp(argv[1], "gpio")) { + if (phytype == WLC_PHY_TYPE_HT) { + collect.mode = 4; + } else { + /* MIMOPHY */ + collect.mode = 0xff; + } + } else { + collect.mode = atoi(argv[1]); + } + } + else if (!strcmp(s, "-k")) + collect.gpioCapMask = atoi(argv[1]); + else if (!strcmp(s, "-s")) + collect.bitStart = atoi(argv[1]); + else if (!strcmp(s, "-b")) + collect.pre_dur = atoi(argv[1]); + else if (!strcmp(s, "-a")) + collect.post_dur = atoi(argv[1]); + else if (!strcmp(s, "-g")) + collect.gpio_sel = atoi(argv[1]); + else if (!strcmp(s, "-d")) + collect.downsamp = atoi(argv[1]); + else if (!strcmp(s, "-e")) + collect.be_deaf = atoi(argv[1]); + else if (!strcmp(s, "-i")) + collect.timeout = atoi(argv[1]); + else if (!strcmp(s, "--agc")) { + /* perform software agc for sample collect */ + collect.agc = atoi(argv[1]); + } + else if (!strcmp(s, "--filter")) { + /* Set HPC for LPF to lowest possible value (0x1) */ + collect.filter = atoi(argv[1]); + } + else if (!strcmp(s, "-v")) + sampledata_version = atoi(argv[1]); + else if (!strcmp(s, "-s")) + collect.trigger_state = atoi(argv[1]); + else if (!strcmp(s, "-x")) + collect.module_sel1 = atoi(argv[1]); + else if (!strcmp(s, "-y")) + collect.module_sel2 = atoi(argv[1]); + else if (!strcmp(s, "-n")) + collect.nsamps = atoi(argv[1]); + else { + ret = BCME_USAGE_ERROR; + goto exit; + } + + argv += 2; + } + + buff = malloc(WLC_SAMPLECOLLECT_MAXLEN); + if (buff == NULL) { + fprintf(stderr, "Failed to allocate dump buffer of %d bytes\n", + WLC_SAMPLECOLLECT_MAXLEN); + return BCME_NOMEM; + } + memset(buff, 0, WLC_SAMPLECOLLECT_MAXLEN); + + if ((fp = fopen(fname, "wb")) == NULL) { + fprintf(stderr, "Problem opening file %s\n", fname); + ret = BCME_BADARG; + goto exit; + } + + if ((phytype == WLC_PHY_TYPE_HT) || (phytype == WLC_PHY_TYPE_AC)) { + ret = wl_do_samplecollect(wl, &collect, sampledata_version, (uint32 *)buff, fp); + } + else if (phytype == WLC_PHY_TYPE_N) { + if (phyrev < 7) { + ret = wl_do_samplecollect_n(wl, &collect, buff, fp); + } else { + ret = wl_do_samplecollect(wl, &collect, sampledata_version, + (uint32 *)buff, fp); + } + } else if (phytype == WLC_PHY_TYPE_LCN40) { + if (collect.nsamps > (WLC_SAMPLECOLLECT_MAXLEN >> 2)) { + fprintf(stderr, "Max number of samples supported = %d\n", + WLC_SAMPLECOLLECT_MAXLEN >> 2); + ret = -1; + goto exit; + } + ret = wl_do_samplecollect_lcn40(wl, &collect, buff, fp); + } +exit: + if (buff) free(buff); + if (fp) fclose(fp); + return ret; +#endif /* !BWL_FILESYSTEM_SUPPORT */ +} + +/* WLOTA_EN START */ +#define WL_OTA_STRING_MAX_LEN 100 +#define WL_OTA_CMDSTREAM_MAX_LEN 200 + +/* test_setup cmd argument ordering */ +enum { + WL_OTA_SYNC_TIMEOUT = 1, /* Timeout in seconds */ + WL_OTA_SYNCFAIL_ACTION, /* Fail actio -1/0/1 */ + WL_OTA_SYNC_MAC, /* Mac address for sync */ + WL_OTA_TX_MAC, /* Mac address for tx test */ + WL_OTA_RX_MAC, /* Mac address for rx test */ + WL_OTA_LOOP_TEST /* Put test into loop mode */ +}; + +/* ota_tx / ota_rx format ordering */ +enum { + WL_OTA_CUR_TEST, /* ota_tx or ota_rx */ + WL_OTA_CHAN, /* cur channel */ + WL_OTA_BW, /* cur bandwidth */ + WL_OTA_CONTROL_BAND, /* cur control band */ + WL_OTA_RATE, /* cur rate */ + WL_OTA_STF_MODE, /* cur stf mode */ + WL_OTA_TXANT, /* tx ant to be used */ + WL_OTA_RXANT, /* rx ant to be used */ + WL_OTA_TX_IFS, /* ifs */ + WL_OTA_TX_PKT_LEN, /* pkt length */ + WL_OTA_TX_NUM_PKT, /* num of packets */ + WL_OTA_PWR_CTRL_ON, /* power control on/off */ + WL_OTA_PWR_SWEEP /* start:delta:stop */ +}; +/* Various error chcking options */ +enum { + WL_OTA_SYNCFAILACTION, + WL_OTA_CTRLBANDVALID, + WL_OTA_TXANTVALID, + WL_OTA_RXANTVALID, + WL_OTA_PWRCTRLVALID +}; +/* Display init test seq */ +static void +wl_ota_display_test_init_info(wl_ota_test_status_t *init_info) +{ + printf("Test Init Summary\n"); + printf("----------------------------------------------------------\n"); + printf("Toatl Number of test req %d\n\n", init_info->test_cnt); + printf("Sync timeout %d synch fail action: %d \n", init_info->sync_timeout, + init_info->sync_fail_action); + printf("Sync Mac address : \t"); + printf("%s\n", wl_ether_etoa(&(init_info->sync_mac))); + printf("Tx Mac address : \t"); + printf("%s\n", wl_ether_etoa(&(init_info->tx_mac))); + printf("Rx Mac address : \t"); + printf("%s\n", wl_ether_etoa(&(init_info->rx_mac))); + printf("Test in Loop mode : %d \n", init_info->loop_test); + printf("\n\n\n"); +} +static void +wl_ota_display_rt_info(uint8 rate) +{ +#ifndef D11AC_IOTYPES + if (rate & NRATE_MCS_INUSE) { + printf("m"); + printf("%d ", rate & NRATE_RATE_MASK); + } else if (rate == 11) { + printf("5.5 "); + } else { + printf("%d ", (rate & NRATE_RATE_MASK) / 2); + } +#else + printf("format changed : fix it %x \n", rate); +#endif +} +/* display nth tesr arg details */ +static void +wl_ota_display_test_option(wl_ota_test_args_t *test_arg, int16 cnt) +{ + uint8 i; + printf("Test cnt %d \n", cnt); + printf("-----------------------------------------------------------\n"); + printf("Curr Test : %s\n", ((test_arg->cur_test == 0) ? "TX" : "RX")); + printf("Wait for sync enabled %d \n", test_arg->wait_for_sync); + printf("Channel : %d", test_arg->chan); + printf("\t Bandwidth : %s ", ((test_arg->bw == WL_OTA_TEST_BW_20MHZ) ? "20" : + ((test_arg->bw == WL_OTA_TEST_BW_40MHZ) ? "40" : "20 in 40"))); + printf("\t Control Band : %c \n", test_arg->control_band); + printf("Rates : "); + for (i = 0; i < test_arg->rt_info.rate_cnt; i++) + wl_ota_display_rt_info(test_arg->rt_info.rate_val_mbps[i]); + printf("\nStf mode : %d \n", test_arg->stf_mode); + printf("Txant: %d rxant: %d \n", test_arg->txant, test_arg->rxant); + printf("Pkt eng Options : ifs %d len: %d num: %d \n", test_arg->pkteng.delay, + test_arg->pkteng.length, test_arg->pkteng.nframes); + printf("Tx power sweep options :\nPower control %d \nstart pwr: %d " + "delta: %d end pwr : %d \n", test_arg->pwr_info.pwr_ctrl_on, + test_arg->pwr_info.start_pwr, test_arg->pwr_info.delta_pwr, + test_arg->pwr_info.end_pwr); +} +/* do minimum string validations possible */ +/* Make stricter conditions in future */ +static int +wl_ota_validate_string(uint8 arg, void* value) +{ + int ret = 0; + switch (arg) { + case WL_OTA_TXANTVALID: + case WL_OTA_RXANTVALID: + if (*(uint8*)value > 3) + ret = -1; + break; + case WL_OTA_CTRLBANDVALID: + if ((strncmp((char *)value, "l", 1)) && (strncmp((char *)value, "u", 1))) + ret = -1; + break; + case WL_OTA_PWRCTRLVALID: + case WL_OTA_SYNCFAILACTION: + if ((*(int8 *)value < -1) || (*(int8 *)value > 1)) + ret = -1; + break; + default: + break; + } + return ret; +} + + +/* convert power info string to integer */ +/* start:delta:end */ +static int +wl_ota_pwrinfo_parse(const char *tok_bkp, wl_ota_test_args_t *test_arg) +{ + char *endptr = NULL; + int ret = 0; + + /* convert string to int */ + /* Read start pwr */ + test_arg->pwr_info.start_pwr = (int8)strtol(tok_bkp, &endptr, 10); + if (*endptr == ':') { + endptr++; + tok_bkp = endptr; + } else { + return -1; + } + /* read delta pwr */ + test_arg->pwr_info.delta_pwr = (int8)strtol(tok_bkp, &endptr, 10); + if (*endptr == ':') { + endptr++; + tok_bkp = endptr; + } else { + return -1; + } + /* read end pwr */ + test_arg->pwr_info.end_pwr = (int8)strtol(tok_bkp, &endptr, 10); + + if ((*endptr != '\0') && (*endptr != '\n') && (*endptr != ' ')) + ret = -1; + + return ret; +} + +/* parsing the test init seq line */ +static int +wl_ota_parse_test_init(wl_ota_test_vector_t * init_info, char * tok, uint16 cnt) +{ + int ret = 0; + char * endptr = NULL; + + switch (cnt) { + case WL_OTA_SYNC_TIMEOUT: + init_info->sync_timeout = (uint8)strtol(tok, &endptr, 10); + if (*endptr != '\0') + ret = -1; + break; + case WL_OTA_SYNCFAIL_ACTION: + init_info->sync_fail_action = (int8)strtol(tok, &endptr, 10); + if (*endptr != '\0') { + ret = -1; + break; + } else { + ret = wl_ota_validate_string(WL_OTA_SYNCFAILACTION, + &(init_info->sync_fail_action)); + } + break; + case WL_OTA_SYNC_MAC: + if (!wl_ether_atoe(tok, &(init_info->sync_mac))) + ret = -1; + break; + case WL_OTA_TX_MAC: + if (!wl_ether_atoe(tok, &(init_info->tx_mac))) + ret = -1; + break; + case WL_OTA_RX_MAC: + if (!wl_ether_atoe(tok, &(init_info->rx_mac))) + ret = -1; + break; + case WL_OTA_LOOP_TEST: + init_info->loop_test = (int8)strtol(tok, &endptr, 10); + + if ((*endptr != '\0') && (*endptr != '\n') && (*endptr != ' ')) + ret = -1; + break; + default: + break; + } + return ret; +} +/* parse test arguments */ +static int +wl_ota_test_parse_test_option(wl_ota_test_args_t *test_arg, char * tok, uint16 cnt, + char rt_string[]) +{ + char * endptr = NULL; + uint16 tok_len = 0; + int ret = 0; + + if (test_arg->cur_test == WL_OTA_TEST_RX) { + switch (cnt) { + case WL_OTA_PWR_CTRL_ON: + case WL_OTA_PWR_SWEEP: + return 0; + break; + default: + break; + } + } + switch (cnt) { + case WL_OTA_CUR_TEST: + if (strncmp(tok, "ota_tx", 6) == 0) + test_arg->cur_test = WL_OTA_TEST_TX; + else if (strncmp(tok, "ota_rx", 6) == 0) + test_arg->cur_test = WL_OTA_TEST_RX; + else + ret = -1; + break; + case WL_OTA_CHAN: + test_arg->chan = (uint8)strtol(tok, &endptr, 10); + if (*endptr != '\0') + ret = -1; + break; + case WL_OTA_BW: + if (strncmp(tok, "20/40", 5) == 0) { + test_arg->bw = WL_OTA_TEST_BW_20_IN_40MHZ; + } else if (strncmp(tok, "20", 2) == 0) { + test_arg->bw = WL_OTA_TEST_BW_20MHZ; + } else if (strncmp(tok, "40", 2) == 0) { + test_arg->bw = WL_OTA_TEST_BW_40MHZ; + } else { + ret = -1; + } + break; + case WL_OTA_CONTROL_BAND: + test_arg->control_band = *tok; + ret = wl_ota_validate_string(WL_OTA_CTRLBANDVALID, tok); + break; + case WL_OTA_RATE: + tok_len = strlen(tok); + if (tok_len > WL_OTA_STRING_MAX_LEN) { + ret = -1; + goto fail; + } + strncpy(rt_string, tok, tok_len); + break; + case WL_OTA_STF_MODE: +#ifndef D11AC_IOTYPES + if (strncmp(tok, "siso", 4) == 0) + test_arg->stf_mode = NRATE_STF_SISO; + else if (strncmp(tok, "cdd", 3) == 0) + test_arg->stf_mode = NRATE_STF_CDD; + else if (strncmp(tok, "stbc", 4) == 0) + test_arg->stf_mode = NRATE_STF_STBC; + else if (strncmp(tok, "sdm", 3) == 0) + test_arg->stf_mode = NRATE_STF_SDM; + else + ret = -1; +#endif + break; + case WL_OTA_TXANT: + test_arg->txant = (uint8)strtol(tok, &endptr, 10); + if (*endptr != '\0') { + ret = -1; + goto fail; + } + ret = wl_ota_validate_string(WL_OTA_TXANTVALID, &test_arg->txant); + break; + case WL_OTA_RXANT: + test_arg->rxant = (uint8)strtol(tok, &endptr, 10); + if (*endptr != '\0') { + ret = -1; + goto fail; + } + ret = wl_ota_validate_string(WL_OTA_RXANTVALID, &test_arg->rxant); + break; + case WL_OTA_TX_IFS: + test_arg->pkteng.delay = (uint16)strtol(tok, &endptr, 10); + if (*endptr != '\0') + ret = -1; + break; + case WL_OTA_TX_PKT_LEN: + test_arg->pkteng.length = (uint16)strtol(tok, &endptr, 10); + if (*endptr != '\0') + ret = -1; + break; + case WL_OTA_TX_NUM_PKT: + test_arg->pkteng.nframes = (uint16)strtol(tok, &endptr, 10); + if ((*endptr != '\0') && (*endptr != '\n') && (*endptr != ' ')) + ret = -1; + break; + case WL_OTA_PWR_CTRL_ON: + test_arg->pwr_info.pwr_ctrl_on = (int8)strtol(tok, &endptr, 10); + if (*endptr != '\0') { + ret = -1; + goto fail; + } + ret = wl_ota_validate_string(WL_OTA_PWRCTRLVALID, + &test_arg->pwr_info.pwr_ctrl_on); + break; + case WL_OTA_PWR_SWEEP: + ret = wl_ota_pwrinfo_parse(tok, test_arg); + default: + break; + } + +fail: + return ret; +} +static int +wl_ota_test_parse_rate_string(wl_ota_test_args_t *test_arg, char rt_string[100]) +{ + + uint8 cnt = 0; + char * tok = NULL; + char rate_st[5] = "\0"; + uint8 int_val = 0; + uint16 tok_len = 0; + int ret = 0; + tok = strtok(rt_string, ","); + + /* convert rate strings to int array */ + while (tok != NULL) { + strncpy(rate_st, " ", 4); + /* skip rate parsing if its rx test case */ + if (test_arg->cur_test == WL_OTA_TEST_RX) { + test_arg->rt_info.rate_val_mbps[cnt] = 0; + cnt = 1; + break; + } + + /* Support a max of 30 rates */ + if (cnt >= WL_OTA_TEST_MAX_NUM_RATE) { + ret = -1; + break; + } + tok_len = strlen(tok); + if (tok_len > 5) { + ret = -1; + break; + } + strncpy(rate_st, tok, tok_len); + if (strncmp(rate_st, "5.5", 3) == 0) { + int_val = 11; + } else { + if (rate_st[0] == 'm') { + rate_st[0] = ' '; + int_val = atoi(rate_st); +#ifndef D11AC_IOTYPES + int_val |= NRATE_MCS_INUSE; +#endif + } else { + int_val = 2 * atoi(rate_st); + } + } + test_arg->rt_info.rate_val_mbps[cnt] = int_val; + tok = strtok(NULL, ","); + cnt++; + } + test_arg->rt_info.rate_cnt = cnt; + return ret; +} +static int +wl_ota_test_parse_arg(char line[], wl_ota_test_vector_t *ota_test_vctr, uint16 *test_cnt, + uint8 *ota_sync_found) +{ + char * tok = NULL; + char rt_string[WL_OTA_STRING_MAX_LEN] = "\0"; + uint16 cnt = 0; + int ret = 0; + tok = strtok(line, " "); + + /* Initialize the power arguments */ + ota_test_vctr->test_arg[*test_cnt].pwr_info.pwr_ctrl_on = -1; + ota_test_vctr->test_arg[*test_cnt].pwr_info.start_pwr = -1; + ota_test_vctr->test_arg[*test_cnt].pwr_info.delta_pwr = -1; + ota_test_vctr->test_arg[*test_cnt].pwr_info.end_pwr = -1; + + if (!strncmp(tok, "test_setup", 10)) { + /* Parse test setup details */ + cnt = 0; + while (tok != NULL) { + if ((ret = wl_ota_parse_test_init(ota_test_vctr, tok, cnt)) != 0) + return ret; + tok = strtok(NULL, " "); + cnt++; + } + } else if (!(strncmp(tok, "ota_tx", 6)) || (!strncmp(tok, "ota_rx", 6))) { + /* parse tx /rx test argumenst */ + cnt = 0; + while (tok != NULL) { + if ((ret = wl_ota_test_parse_test_option + (&(ota_test_vctr->test_arg[*test_cnt]), + tok, cnt, rt_string)) != 0) { + goto fail; + } + tok = strtok(NULL, " "); + cnt++; + } + + /* split rate string into integer array */ + if ((ret = wl_ota_test_parse_rate_string(&(ota_test_vctr->test_arg[*test_cnt]), + rt_string)) != 0) { + goto fail; + } + + /* Add sync option if specified by user */ + ota_test_vctr->test_arg[*test_cnt].wait_for_sync = (*ota_sync_found); + + /* Reset ota_sync_found for next test arg */ + *ota_sync_found = 0; + + /* Increment test cnt */ + *test_cnt = *test_cnt + 1; + } else if (strncmp(tok, "ota_sync", 8) == 0) { + /* detect if a sync packet is required */ + *ota_sync_found = 1; + ret = 0; + } +fail: + return (ret); +} +static int +wl_load_cmd_stream(void *wl, cmd_t *cmd, char **argv) +{ + int ret = -1; + char test_arg[WL_OTA_CMDSTREAM_MAX_LEN] = "\0"; + uint16 test_cnt = 0; + uint8 * ptr1 = NULL; + uint8 i, num_loop = 0; + uint8 ota_sync_found = 0; + + wl_seq_cmd_pkt_t *next_cmd; + wl_ota_test_vector_t *ota_test_vctr = NULL; + + argv++; + + if (*argv == NULL) { + return ret; + } else if (!strncmp(argv[0], "start", 5)) { + ret = wl_seq_start(wl, cmd, argv); + } else if (!strncmp(argv[0], "stop", 4)) { + ret = 0; + /* test info pointer */ + ota_test_vctr = (wl_ota_test_vector_t *)malloc(sizeof(wl_ota_test_vector_t)); + + if (ota_test_vctr == NULL) { + fprintf(stderr, "Failed to allocate %d bytes of memory \n", + (uint16)sizeof(wl_ota_test_vector_t)); + return BCME_NOMEM; + } + + /* Assign a new pointer so that byte wise operation is possible */ + ptr1 = (uint8 *)ota_test_vctr; + + /* Passing test structure to dongle happens in steps */ + /* For OTA implementations its split up into chunks of 1200 bytes */ + num_loop = sizeof(wl_ota_test_vector_t) / WL_OTA_ARG_PARSE_BLK_SIZE; + + if (!cmd_batching_mode) { + printf("calling ota_stream stop when it's already out of batching mode\n"); + ret = BCME_ERROR; + goto fail; + } + cmd_batching_mode = FALSE; + next_cmd = cmd_list.head; + if (next_cmd == NULL) { + printf("no command batched\n"); + ret = 0; + goto fail; + } + test_cnt = 0; + while (next_cmd != NULL) { + /* Max number of test options is ARRAYSIZE(ota_test_vctr->test_arg) */ + if (test_cnt == ARRAYSIZE(ota_test_vctr->test_arg)) + break; + + if ((ret = wl_ota_test_parse_arg(next_cmd->data, ota_test_vctr, &test_cnt, + &ota_sync_found)) != 0) { + printf("Error Parsing the test command \n"); + ret = BCME_BADARG; + goto fail; + } + next_cmd = next_cmd->next; + } + ota_test_vctr->test_cnt = test_cnt; + /* Full size of wl_ota_test_vector_t can not be parse through wl */ + /* max size whihc can be passed from host to dongle is limited by eth size */ + for (i = 0; i <= num_loop; i++) { + /* pass on the test info to wl->test_info structure */ + if ((ret = wlu_var_setbuf(wl, "ota_loadtest", ptr1 + i * + WL_OTA_ARG_PARSE_BLK_SIZE, WL_OTA_ARG_PARSE_BLK_SIZE)) < 0) { + fprintf(stderr, "host to dongle download failed to pass %d" + "bytes in stage %d \n", + WL_OTA_ARG_PARSE_BLK_SIZE, i); + } + } +fail: + clean_up_cmd_list(); + free(ota_test_vctr); + } else { + while (*argv) { + strncat(test_arg, *argv, strlen(*argv)); + strncat(test_arg, " ", 1); + argv++; + } + return add_one_batched_cmd(WLC_SET_VAR, test_arg, strlen(test_arg)); + + } + return ret; +} + +static int +wl_ota_loadtest(void *wl, cmd_t *cmd, char **argv) +{ + int ret = -1; + FILE *fp; + const char *fname = "ota_test.txt"; + char line[WL_OTA_CMDSTREAM_MAX_LEN] = "\0"; + char line_bkp[WL_OTA_CMDSTREAM_MAX_LEN] = "\0"; + uint16 test_cnt = 0; + uint8 * ptr1 = NULL; + uint8 i, num_loop = 0; + uint8 ota_sync_found = 0; + wl_ota_test_vector_t *ota_test_vctr = NULL; + + UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); + + /* Read the file name */ + if (argv[1]) { + fname = argv[1]; + } + + /* test info pointer */ + ota_test_vctr = (wl_ota_test_vector_t *)malloc(sizeof(wl_ota_test_vector_t)); + + if (ota_test_vctr == NULL) { + fprintf(stderr, "Failed to allocate %d bytes of memory \n", + (uint16)sizeof(wl_ota_test_vector_t)); + return BCME_NOMEM; + } + + /* Assign a new pointer so that byte wide operation is possible */ + ptr1 = (uint8 *)ota_test_vctr; + + /* find number of iterations required to parse full block form host to dongle */ + num_loop = sizeof(wl_ota_test_vector_t) / WL_OTA_ARG_PARSE_BLK_SIZE; + + + /* open the flow file */ + if ((fp = fopen(fname, "r")) == NULL) { + fprintf(stderr, "Problem opening file %s\n", fname); + free(ota_test_vctr); + return BCME_BADARG; + } + + test_cnt = 0; + while (1) { + fgets(line, WL_OTA_CMDSTREAM_MAX_LEN - 1, fp); + + if (feof(fp)) { + break; + } + + /* Max number of test options is ARRAYSIZE(ota_test_vctr->test_arg) */ + if (test_cnt == ARRAYSIZE(ota_test_vctr->test_arg)) + break; + + strncpy(line_bkp, line, WL_OTA_CMDSTREAM_MAX_LEN - 1); + + if ((ret = wl_ota_test_parse_arg(line_bkp, ota_test_vctr, + &test_cnt, &ota_sync_found)) != 0) { + printf("Flow File Error: \nError Parsing string : %s \n", line); + ret = BCME_BADARG; + goto fail; + } + } + if (ota_sync_found) { + ret = -1; + printf("Flow File Error : \nFile can not end with ota_sync\n"); + goto fail; + } + ota_test_vctr->test_cnt = test_cnt; + + /* Full size of wl_ota_test_vector_t can not be parse through wl */ + /* max size whihc can be passed from host to dongle is limited by eth size */ + for (i = 0; i <= num_loop; i++) { + /* pass on the test info to wl->test_info structure */ + if ((ret = wlu_var_setbuf(wl, cmd->name, ptr1 + i * WL_OTA_ARG_PARSE_BLK_SIZE, + WL_OTA_ARG_PARSE_BLK_SIZE)) < 0) { + fprintf(stderr, "host to dongle download failed to pass %d" + "bytes in stage %d \n", + WL_OTA_ARG_PARSE_BLK_SIZE, i); + break; + } + } +fail: + /* close the fp */ + if (fp) + fclose(fp); + + free(ota_test_vctr); + return ret; +} +static void +wl_otatest_display_skip_test_reason(int8 skip_test_reason) +{ + switch (skip_test_reason) { + case 0 : + printf("Test successfully finished\n"); + break; + case WL_OTA_SKIP_TEST_CAL_FAIL: + printf("Phy cal Failure \n"); + break; + case WL_OTA_SKIP_TEST_SYNCH_FAIL: + printf("Sync Packet failure \n"); + break; + case WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL: + printf("File download Failure \n"); + break; + case WL_OTA_SKIP_TEST_NO_TEST_FOUND: + printf("No test found in the flow file \n"); + break; + case WL_OTA_SKIP_TEST_WL_NOT_UP: + printf("WL Not UP \n"); + break; + case WL_OTA_SKIP_TEST_UNKNOWN_CALL: + printf("Erroneous scheduling of test. Not intended \n"); + break; + default: + printf("Unknown test state \n"); + break; + } +} +static int +wl_otatest_status(void *wl, cmd_t *cmd, char **argv) +{ + int ret = 0; + int16 cnt = 0; + wl_ota_test_status_t *test_status = NULL; + wl_ota_test_vector_t *ota_test_vctr = NULL; + + UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); + + test_status = (wl_ota_test_status_t *)buf; + if (argv[1]) { + + cnt = atoi(argv[1]); + if ((cnt < 1) || ((uint16)cnt > ARRAYSIZE(ota_test_vctr->test_arg))) { + printf("Error, Out of range \n"); + return BCME_RANGE; + } + /* read nth test arg details */ + if ((ret = wlu_iovar_getbuf(wl, cmd->name, &cnt, sizeof(uint16), + buf, WLC_IOCTL_MAXLEN)) < 0) + return ret; + if (cnt > (test_status->test_cnt)) { + printf("Error : Number of test seq downloaded %d \n", + test_status->test_cnt); + return BCME_RANGE; + } + + /* Display Test init info */ + wl_ota_display_test_init_info(test_status); + + /* Dsiplay test arg info */ + wl_ota_display_test_option(&(test_status->test_arg), cnt); + } else { + /* read back current state */ + if ((ret = wlu_iovar_getbuf(wl, cmd->name, NULL, 0, + buf, WLC_IOCTL_MAXLEN)) < 0) + return ret; + cnt = test_status->cur_test_cnt; + + switch (test_status->test_stage) { + case WL_OTA_TEST_IDLE: /* Idle state */ + printf("Init state \n"); + break; + case WL_OTA_TEST_ACTIVE: /* Active test state */ + /* Read back details for current test arg */ + cnt++; + ret = wlu_iovar_getbuf(wl, cmd->name, &cnt, sizeof(uint16), + buf, WLC_IOCTL_MAXLEN); + if (test_status->sync_status == WL_OTA_SYNC_ACTIVE) + printf("Waiting for sync \n"); + else + wl_ota_display_test_option(&(test_status->test_arg), cnt); + break; + case WL_OTA_TEST_SUCCESS: /* Test Finished */ + printf("Test completed \n"); + break; + case WL_OTA_TEST_FAIL: /* Test Failed to complete */ + wl_otatest_display_skip_test_reason(test_status->skip_test_reason); + break; + default: + printf("Invalid test Phase \n"); + break; + } + } + return ret; +} +/* To stop the ota test suite */ +static int +wl_ota_teststop(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(argv); + return (wlu_iovar_setint(wl, cmd->name, 1)); +} +/* WLOTA_EN END */ + +static int +wl_ampdu_activate_test(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + const char *cmdname = "ampdu_activate_test"; + struct agg { + bool val1; + bool val2; + } x; + int err = 0; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + x.val1 = atoi(param); + if ((param = *++argv)) { + x.val2 = atoi(param); + printf("%d %d\n", x.val1, x.val2); + err = wlu_var_setbuf(wl, cmdname, &x, sizeof(x)); + } + return err; +} + +static int +wl_ampdu_tid(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + const char *cmdname = "ampdu_tid"; + struct ampdu_tid_control atc, *reply; + uint8 tid; + int err; + void *ptr = NULL; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + tid = atoi(param); + if (tid > MAXPRIO) + return BCME_USAGE_ERROR; + atc.tid = tid; + + if ((param = *++argv)) { + atc.enable = atoi(param); + err = wlu_var_setbuf(wl, cmdname, &atc, sizeof(atc)); + } else { + if ((err = wlu_var_getbuf_sm(wl, cmdname, &atc, sizeof(atc), &ptr) < 0)) + return err; + reply = (struct ampdu_tid_control *)ptr; + printf("AMPDU for tid %d: %d\n", tid, reply->enable); + } + return err; +} + +static int +wl_ampdu_retry_limit_tid(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + const char *cmdname = "ampdu_retry_limit_tid"; + struct ampdu_retry_tid retry_limit, *reply; + uint8 tid; + int err; + void *ptr = NULL; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + tid = atoi(param); + if (tid > MAXPRIO) + return BCME_USAGE_ERROR; + retry_limit.tid = tid; + + if ((param = *++argv)) { + retry_limit.retry = atoi(param); + err = wlu_var_setbuf(wl, cmdname, &retry_limit, sizeof(retry_limit)); + } else { + if ((err = wlu_var_getbuf(wl, cmdname, &retry_limit, + sizeof(retry_limit), &ptr)) < 0) + return err; + reply = (struct ampdu_retry_tid *)ptr; + printf("AMPDU retry limit for tid %d: %d\n", tid, reply->retry); + } + return err; +} + +static int +wl_ampdu_rr_retry_limit_tid(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + const char *cmdname = "ampdu_rr_retry_limit_tid"; + struct ampdu_retry_tid retry_limit, *reply; + uint8 tid; + int err; + void *ptr = NULL; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + tid = atoi(param); + if (tid > MAXPRIO) + return BCME_USAGE_ERROR; + retry_limit.tid = tid; + + if ((param = *++argv)) { + retry_limit.retry = atoi(param); + err = wlu_var_setbuf(wl, cmdname, &retry_limit, sizeof(retry_limit)); + } else { + if ((err = wlu_var_getbuf(wl, cmdname, &retry_limit, + sizeof(retry_limit), &ptr)) < 0) + return err; + reply = (struct ampdu_retry_tid *)ptr; + printf("AMPDU regular rate retry limit for tid %d: %d\n", tid, reply->retry); + } + return err; +} + + +static int +wl_ampdu_send_addba(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + const char *cmdname = "ampdu_send_addba"; + struct ampdu_ea_tid aet; + uint8 tid; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + tid = atoi(param); + if (tid > MAXPRIO) + return BCME_USAGE_ERROR; + aet.tid = tid; + + argv++; + if (!*argv) { + printf("error: missing address\n"); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv, &aet.ea)) { + printf("error: could not parse MAC address %s\n", *argv); + return BCME_USAGE_ERROR; + } + + return wlu_var_setbuf(wl, cmdname, &aet, sizeof(aet)); +} + +static int +wl_ampdu_send_delba(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + const char *cmdname = "ampdu_send_delba"; + struct ampdu_ea_tid aet; + uint8 tid; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + tid = atoi(param); + if (tid > MAXPRIO) + return BCME_USAGE_ERROR; + aet.tid = tid; + + argv++; + if (!*argv) { + printf("error: missing address\n"); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv, &aet.ea)) { + printf("error: could not parse MAC address %s\n", *argv); + return BCME_USAGE_ERROR; + } + + return wlu_var_setbuf(wl, cmdname, &aet, sizeof(aet)); +} + +static int +wl_dpt_deny(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "dpt_deny"; + dpt_iovar_t info; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) + return BCME_USAGE_ERROR; + + info.pad = 0; + + if (!strcmp("add", *argv)) + info.mode = DPT_DENY_LIST_ADD; + else if (!strcmp("remove", *argv)) + info.mode = DPT_DENY_LIST_REMOVE; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + argv++; + if (!*argv) { + printf("error: missing mode value\n"); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv, &info.ea)) { + printf("error: could not parse MAC address %s\n", *argv); + return BCME_USAGE_ERROR; + } + + return wlu_var_setbuf(wl, cmdname, &info, sizeof(info)); +} + +static int +wl_dpt_endpoint(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "dpt_endpoint"; + dpt_iovar_t info; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) + return BCME_USAGE_ERROR; + + info.pad = 0; + + if (!strcmp("create", *argv)) + info.mode = DPT_MANUAL_EP_CREATE; + else if (!strcmp("modify", *argv)) + info.mode = DPT_MANUAL_EP_MODIFY; + else if (!strcmp("delete", *argv)) + info.mode = DPT_MANUAL_EP_DELETE; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + argv++; + if (!*argv) { + printf("error: missing ea\n"); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv, &info.ea)) { + printf("error: could not parse MAC address %s\n", *argv); + return BCME_USAGE_ERROR; + } + + return wlu_var_setbuf(wl, cmdname, &info, sizeof(info)); +} + +#ifdef WLTDLS +static int +wl_tdls_endpoint(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname_tdls = "tdls_endpoint"; + tdls_iovar_t info; + chanspec_t chanspec; + + if (strcmp(cmd->name, cmdname_tdls)) { + printf("error: invalid command name.\n"); + return BCME_USAGE_ERROR; + } + + if (!*++argv) + return BCME_USAGE_ERROR; + + memset(&info, 0, sizeof(tdls_iovar_t)); + + if (!strcmp("create", *argv)) + info.mode = TDLS_MANUAL_EP_CREATE; + else if (!strcmp("modify", *argv)) + info.mode = TDLS_MANUAL_EP_MODIFY; + else if (!strcmp("delete", *argv)) + info.mode = TDLS_MANUAL_EP_DELETE; + else if (!strcmp("PM", *argv)) + info.mode = TDLS_MANUAL_EP_PM; + else if (!strcmp("wake", *argv)) + info.mode = TDLS_MANUAL_EP_WAKE; + else if (!strcmp("disc", *argv)) + info.mode = TDLS_MANUAL_EP_DISCOVERY; + else if (!strcmp("cw", *argv)) { + info.mode = TDLS_MANUAL_EP_CHSW; + } + else if (!strcmp("wfd_disc", *argv)) + info.mode = TDLS_MANUAL_EP_WFD_TPQ; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + argv++; + if (!*argv) { + printf("error: missing ea\n"); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv, &info.ea)) { + printf("error: could not parse MAC address %s\n", *argv); + return BCME_USAGE_ERROR; + } + + if (info.mode == TDLS_MANUAL_EP_CHSW) { + argv++; + if (!*argv) { + printf("error: missing target channel number\n"); + return BCME_USAGE_ERROR; + } + if (atoi(*argv) != 0) { + chanspec = wf_chspec_aton(*argv); + if (chanspec == 0) { + printf("error: bad chanspec \"%s\".\n", *argv); + return BCME_USAGE_ERROR; + } + chanspec = wl_chspec_to_driver(chanspec); + if (chanspec == INVCHANSPEC) { + return BCME_USAGE_ERROR; + } + info.chanspec = chanspec; + } + } + + return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info)); +} + +static int +wl_pattern_atoh(char *, char *); + +#define WFD_DEV 0 +#define WFD_DEV_LEN 6 +#define WFD_IP 8 +#define WFD_IP_LEN 5 +#define WFD_ALT_MAC 10 +#define WFD_ALT_MAC_LEN 6 + +static int +wl_tdls_wfd_ie(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname_tdls = "tdls_wfd_ie"; + tdls_wfd_ie_iovar_t info; + tdls_wfd_ie_iovar_t* buf_info = (tdls_wfd_ie_iovar_t*) buf; + int ret; + uint8* ptr; + uint8 element, subelement; + uint16 offset; + uint8 buffer[TDLS_WFD_IE_SIZE - (WFA_OUI_LEN + 3)]; + uint16 length, element_length, current_length; + bcm_tlv_t * ie; + unsigned long value; + struct ether_addr ea; + struct ipv4_addr ipa_set; + + if (strcmp(cmd->name, cmdname_tdls)) { + printf("error: invalid command name.\n"); + return BCME_USAGE_ERROR; + } + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!strcmp(*argv, "clr")) { + memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t)); + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!strcmp("own", *argv)) + info.mode = TDLS_WFD_IE_TX; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info)); + + } else if (!strcmp(*argv, "get")) { + memset(buf_info, 0, sizeof(*buf_info)); + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!strcmp("own", *argv)) + buf_info->mode = TDLS_WFD_IE_TX; + else if (wl_ether_atoe(*argv, &buf_info->ea)) + buf_info->mode = TDLS_WFD_IE_RX; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + if ((ret = wlu_iovar_getbuf(wl, cmd->name, buf_info, + sizeof(*buf_info), buf, WLC_IOCTL_MAXLEN)) < 0) { + return ret; + } + + /* empty */ + if (!buf_info->length) + return ret; + + if (!*++argv) + wl_hexdump((uchar *)buf_info->data, buf_info->length); + else { + if (!strcmp("ip", *argv)) { + element = WFD_IP; + element_length = WFD_IP_LEN; + } else if (!strcmp("port", *argv)) { + element = WFD_DEV; + element_length = WFD_DEV_LEN; + } else { + printf("error: unknown element\n"); + return BCME_USAGE_ERROR; + } + + /* Reassemble the WFD IE (without header) */ + + ptr = buf_info->data; + length = buf_info->length; + offset = 0; + current_length = 0; + + while (length - offset > WFA_OUI_LEN + 3) { + if ((ie = bcm_parse_tlvs(ptr + offset, + length - offset, DOT11_MNG_VS_ID)) != NULL) { + if (ie->len > WFA_OUI_LEN + 1) { + if ((!memcmp(ie->data, WFA_OUI, WFA_OUI_LEN)) && + (*(ie->data + WFA_OUI_LEN) == + WFA_OUI_TYPE_WFD)) { + /* WFD */ + memcpy(buffer + current_length, + ie->data + WFA_OUI_LEN + 1, + ie->len - WFA_OUI_LEN - 1); + current_length += ie->len - WFA_OUI_LEN - 1; + } + } + offset = (uint16)((uint8*)ie - ptr + ie->len + 2); + } + else + break; + } + + /* Find the elements */ + + ptr = buffer; + length = current_length; + + while (length > 3) { + current_length = (ptr[1] << 8) + ptr[2]; + if ((ptr[0] == element) && (current_length == element_length) && + (current_length <= length - 3)) { + + switch (element) { + case WFD_IP: + /* we do not care about the IP version i.e. ptr[3] */ + printf("%u.%u.%u.%u\n", ptr[4], ptr[5], ptr[6], ptr[7]); + break; + + case WFD_DEV: + /* just get the RTSP TCP valid port */ + printf("%u\n", (ptr[5] << 8) + ptr[6]); + break; + } + break; + + } else { + if (current_length + 3 < length) { + length -= current_length + 3; + ptr += current_length + 3; + } else + break; + } + } + } + + return ret; + + } else if (!strcmp(*argv, "set")) { + memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t)); + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!strcmp("own", *argv)) + info.mode = TDLS_WFD_IE_TX; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + argv++; + if (!*argv) { + printf("error: missing IE string\n"); + return BCME_USAGE_ERROR; + } + + if (strlen((char*)*argv) - 2 > sizeof(info.data) * 2) { + printf("error: IE string too long; max is %u bytes\n", + (unsigned int)sizeof(info.data)); + return BCME_BADARG; + } + + ret = wl_pattern_atoh(*argv, (char*)info.data); + + if (ret <= 0) { + printf("error: could not parse IE string address %s\n", *argv); + return BCME_USAGE_ERROR; + } + + info.length = ret; + + if (*++argv) { + /* IP specified */ + + /* watchdog */ + if (info.length != 32) { + printf( + "if one or several set fields are used, " + "the following the IE string must be\n" + "exactly 32 bytes and must have the following order:\n" + "\t6-byte header (0xDD1E506F9A0A)\n" + "\t9-byte subelement 0 (WFD device information)\n" + "\t9-byte subelement 1 (BSSID)\n" + "\t8-byte subelement 8 (IP address)\n"); + return BCME_USAGE_ERROR; + } + + if (!wl_atoip(*argv, &ipa_set)) + return BCME_USAGE_ERROR; + + memcpy(&info.data[28], (uint8*) &ipa_set, sizeof(ipa_set)); + + if (*++argv) { + /* port specified */ + + value = strtoul(*argv, NULL, 0); + info.data[11] = (uint8) (0xFF & (value >> 8)); + info.data[12] = (uint8) (0xFF & value); + + if (*++argv) { + /* WFD type (Source or Primary Sink) specified */ + + element = (uint8) (0x01 & strtoul(*argv, NULL, 0)); + if (element) + info.data[10] |= 0x01; + else + info.data[10] &= ~0x01; + + if (*++argv) { + /* BSSID specified */ + + if (!wl_ether_atoe(*argv, &ea)) + return BCME_USAGE_ERROR; + + memcpy(&info.data[18], (uint8*) &ea, sizeof(ea)); + } + } + } + } + + return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info)); + + } else if (!strcmp(*argv, "clr2")) { + memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t)); + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!strcmp("own", *argv)) + info.mode = TDLS_WFD_PROBE_IE_TX; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info)); + + } else if (!strcmp(*argv, "get2")) { + memset(buf_info, 0, sizeof(*buf_info)); + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!strcmp("own", *argv)) + buf_info->mode = TDLS_WFD_PROBE_IE_TX; + else if (wl_ether_atoe(*argv, &buf_info->ea)) + buf_info->mode = TDLS_WFD_PROBE_IE_RX; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + if ((ret = wlu_iovar_getbuf(wl, cmd->name, buf_info, + sizeof(*buf_info), buf, WLC_IOCTL_MAXLEN)) < 0) { + return ret; + } + + /* empty */ + if (!buf_info->length) + return ret; + + if (!*++argv) + wl_hexdump((uchar *)buf_info->data, buf_info->length); + + else { + if (!strcmp("alt_mac", *argv)) { + element = WFD_ALT_MAC; + element_length = WFD_ALT_MAC_LEN; + } else if (!strcmp("port", *argv)) { + element = WFD_DEV; + element_length = WFD_DEV_LEN; + subelement = 1; + } else if (!strcmp("PC_bit", *argv)) { + element = WFD_DEV; + element_length = WFD_DEV_LEN; + subelement = 0; + } else { + printf("error: unknown element\n"); + return BCME_USAGE_ERROR; + } + + /* Reassemble the WFD IE (without header) */ + + ptr = buf_info->data; + length = buf_info->length; + offset = 0; + current_length = 0; + + while (length - offset > WFA_OUI_LEN + 3) { + if ((ie = bcm_parse_tlvs(ptr + offset, + length - offset, DOT11_MNG_VS_ID)) != NULL) { + if (ie->len > WFA_OUI_LEN + 1) { + if ((!memcmp(ie->data, WFA_OUI, WFA_OUI_LEN)) && + (*(ie->data + WFA_OUI_LEN) == + WFA_OUI_TYPE_WFD)) { + /* WFD */ + memcpy(buffer + current_length, + ie->data + WFA_OUI_LEN + 1, + ie->len - WFA_OUI_LEN - 1); + current_length += ie->len - WFA_OUI_LEN - 1; + } + } + offset = (uint16)((uint8*)ie - ptr + ie->len + 2); + } + else + break; + } + + /* Find the elements */ + + ptr = buffer; + length = current_length; + + while (length > 3) { + current_length = (ptr[1] << 8) + ptr[2]; + if ((ptr[0] == element) && (current_length == element_length) && + (current_length <= length - 3)) { + + switch (element) { + case WFD_ALT_MAC: + printf("%02X:%02X:%02X:%02X:%02X:%02X\n", + ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8]); + break; + case WFD_DEV: + if (subelement) + /* just get the RTSP TCP valid port */ + printf("%u\n", (ptr[5] << 8) + ptr[6]); + else + /* just get the Preferred Connection bit */ + printf("%u\n", ptr[4] >> 7); + break; + } + break; + + } else { + if (current_length + 3 < length) { + length -= current_length + 3; + ptr += current_length + 3; + } else + break; + } + } + } + + return ret; + + } else if (!strcmp(*argv, "set2")) { + memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t)); + + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!strcmp("own", *argv)) + info.mode = TDLS_WFD_PROBE_IE_TX; + else { + printf("error: invalid mode string\n"); + return BCME_USAGE_ERROR; + } + + argv++; + if (!*argv) { + printf("error: missing IE string\n"); + return BCME_USAGE_ERROR; + } + + if (strlen((char*)*argv) - 2 > sizeof(info.data) * 2) { + printf("error: IE string too long; max is %u bytes\n", + (unsigned int)sizeof(info.data)); + return BCME_USAGE_ERROR; + } + + ret = wl_pattern_atoh(*argv, (char*)info.data); + + if (ret <= 0) { + printf("error: could not parse IE string address %s\n", *argv); + return BCME_USAGE_ERROR; + } + + info.length = ret; + + if (*++argv) { + /* alt MAC specified */ + + /* watchdog */ + if (info.length != 24) { + printf( + "if one or several set2 fields are used, " + "the following the IE string must be\n" + "exactly 24 bytes and must have the following order:\n" + "\t6-byte header (0xDD16506F9A0A)\n" + "\t9-byte subelement 0 (WFD device information)\n" + "\t9-byte subelement 10 (alternate MAC address)\n"); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv, &ea)) + return BCME_USAGE_ERROR; + memcpy(&info.data[18], (uint8*) &ea, sizeof(ea)); + + if (*++argv) { + /* port specified */ + + value = strtoul(*argv, NULL, 0); + info.data[11] = (uint8) (0xFF & (value >> 8)); + info.data[12] = (uint8) (0xFF & value); + + if (*++argv) { + /* WFD type (Source or Primary Sink) specified */ + + element = (uint8) (0x01 & strtoul(*argv, NULL, 0)); + if (element) + info.data[10] |= 0x01; + else + info.data[10] &= ~0x01; + } + } + } + + return wlu_var_setbuf(wl, cmd->name, &info, sizeof(info)); + + } else { + printf("error: unknown operation\n"); + return BCME_USAGE_ERROR; + } +} +#endif /* WLTDLS */ + +static int +wl_actframe(void *wl, cmd_t *cmd, char **argv) +{ + wl_action_frame_t * action_frame; + wl_af_params_t * af_params; + struct ether_addr ea; + int argc; + int err = 0; + + UNUSED_PARAMETER(cmd); + + if (!argv[1] || !argv[2]) { + fprintf(stderr, "Too few arguments\n"); + return BCME_USAGE_ERROR; + } + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if ((af_params = (wl_af_params_t *) malloc(WL_WIFI_AF_PARAMS_SIZE)) == NULL) { + printf("wl_actframe: unable to allocate frame \n"); + return BCME_NOMEM; + } + af_params->channel = 0; + af_params->dwell_time = -1; + action_frame = &af_params->action_frame; + + /* Add the packet Id */ + action_frame->packetId = (uint32)(uintptr)action_frame; + + /* convert the ea string into an ea struct */ + if (!wl_ether_atoe(argv[1], &ea)) { + free(af_params); + printf(" ERROR: no valid ether addr provided\n"); + return BCME_USAGE_ERROR; + } + memcpy(&action_frame->da, (char*)&ea, ETHER_ADDR_LEN); + /* set default BSSID */ + memcpy(&af_params->BSSID, (char*)&ea, ETHER_ADDR_LEN); + + /* add the length */ + if (argv[2]) { + action_frame->len = htod16(strlen(argv[2])) / 2; + } + + /* add the channel */ + if (argc > 3 && argv[3]) { + af_params->channel = htod32(atoi(argv[3])); + } + + /* add the dwell_time */ + if (argc > 4 && argv[4]) { + af_params->dwell_time = htod32(atoi(argv[4])); + } + + /* add the BSSID */ + if (argc > 5 && argv[5]) { + if (!wl_ether_atoe(argv[5], &ea)) { + free(af_params); + printf(" ERROR: no valid ether addr provided\n"); + return BCME_USAGE_ERROR; + } + memcpy(&af_params->BSSID, (char*)&ea, ETHER_ADDR_LEN); + } + + if ((err = get_ie_data ((uchar *)argv[2], + &action_frame->data[0], + action_frame->len))) { + free(af_params); + fprintf(stderr, "Error parsing data arg\n"); + return err; + } + err = wlu_var_setbuf(wl, "actframe", af_params, WL_WIFI_AF_PARAMS_SIZE); + + free(af_params); + + return (err); + +} + +static int +wl_dpt_pmk(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "dpt_pmk"; + wsec_pmk_t psk; + size_t key_len; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) + return BCME_USAGE_ERROR; + + key_len = strlen(*argv); + if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) { + fprintf(stderr, "passphrase must be between %d and %d characters long\n", + WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN); + return BCME_BADARG; + } + psk.key_len = htod16((ushort) key_len); + psk.flags = htod16(WSEC_PASSPHRASE); + memcpy(psk.key, *argv, key_len); + + return wlu_var_setbuf(wl, cmdname, &psk, sizeof(wsec_pmk_t)); +} + +static int +wl_dpt_fname(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + const char *cmdname = "dpt_fname"; + int err; + dpt_fname_t fname, *reply; + void *ptr = NULL; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv)) { + fname.len = strlen(param); + if (fname.len >= (DPT_FNAME_LEN - 1)) { + fprintf(stderr, "Name must be less than 32 characters\n"); + return BCME_BADARG; + } + memcpy(fname.name, param, fname.len); + fname.name[fname.len] = '\0'; + err = wlu_var_setbuf(wl, cmdname, &fname, sizeof(fname)); + } else { + if ((err = wlu_var_getbuf(wl, cmdname, &fname, sizeof(fname), &ptr) < 0)) + return err; + reply = (dpt_fname_t *)ptr; + printf("%s\n", reply->name); + } + return err; +} + +static int +wl_dpt_list(void *wl, cmd_t *cmd, char **argv) +{ + int err; + uint32 i; + dpt_list_t *list; + + if (*++argv) + return BCME_USAGE_ERROR; + + strcpy(buf, cmd->name); + if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return err; + + list = (dpt_list_t *) buf; + + printf("List of DPT connections:\n"); + for (i = 0; i < list->num; i++) { + printf("%s: status 0x%x rx %d tx %d rssi %d\n", + list->status[i].name, + list->status[i].status, + list->status[i].sta.rx_ucast_pkts, + list->status[i].sta.tx_pkts, + list->status[i].rssi); + } + return err; +} + +#ifdef WLBTAMP +#define MATCH_OP(op, opstr) (strlen(op) == strlen(opstr) && strncmp(op, opstr, strlen(op)) == 0) + +static int +wl_HCI_cmd(void *wl, cmd_t *cmd, char **argv) +{ + union { + char buf[HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE]; + uint32 alignme; + } cbuf; + amp_hci_cmd_t *cpkt = (amp_hci_cmd_t *)&cbuf.buf[0]; + char *op; + uint8 plen; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) + return BCME_USAGE_ERROR; + + /* recognize and encode operations */ + op = *argv++; + if (MATCH_OP(op, "Read_Link_Quality")) { + cpkt->opcode = HCI_Read_Link_Quality; + } else if (MATCH_OP(op, "Read_Local_AMP_Info")) { + cpkt->opcode = HCI_Read_Local_AMP_Info; + } else if (MATCH_OP(op, "Read_Local_AMP_ASSOC")) { + cpkt->opcode = HCI_Read_Local_AMP_ASSOC; + } else if (MATCH_OP(op, "Write_Remote_AMP_ASSOC")) { + cpkt->opcode = HCI_Write_Remote_AMP_ASSOC; + } else if (MATCH_OP(op, "Create_Physical_Link")) { + cpkt->opcode = HCI_Create_Physical_Link; + } else if (MATCH_OP(op, "Accept_Physical_Link_Request")) { + cpkt->opcode = HCI_Accept_Physical_Link_Request; + } else if (MATCH_OP(op, "Disconnect_Physical_Link")) { + cpkt->opcode = HCI_Disconnect_Physical_Link; + } else if (MATCH_OP(op, "Create_Logical_Link")) { + cpkt->opcode = HCI_Create_Logical_Link; + } else if (MATCH_OP(op, "Accept_Logical_Link")) { + cpkt->opcode = HCI_Accept_Logical_Link; + } else if (MATCH_OP(op, "Disconnect_Logical_Link")) { + cpkt->opcode = HCI_Disconnect_Logical_Link; + } else if (MATCH_OP(op, "Logical_Link_Cancel")) { + cpkt->opcode = HCI_Logical_Link_Cancel; + } else if (MATCH_OP(op, "Short_Range_Mode")) { + cpkt->opcode = HCI_Short_Range_Mode; + } else if (MATCH_OP(op, "Read_Connection_Accept_Timeout")) { + cpkt->opcode = HCI_Read_Connection_Accept_Timeout; + } else if (MATCH_OP(op, "Write_Connection_Accept_Timeout")) { + cpkt->opcode = HCI_Write_Connection_Accept_Timeout; + } else if (MATCH_OP(op, "Read_Link_Supervision_Timeout")) { + cpkt->opcode = HCI_Read_Link_Supervision_Timeout; + } else if (MATCH_OP(op, "Write_Link_Supervision_Timeout")) { + cpkt->opcode = HCI_Write_Link_Supervision_Timeout; + } else if (MATCH_OP(op, "Reset")) { + cpkt->opcode = HCI_Reset; + } else if (MATCH_OP(op, "Enhanced_Flush")) { + cpkt->opcode = HCI_Enhanced_Flush; + } else if (MATCH_OP(op, "Read_Best_Effort_Flush_Timeout")) { + cpkt->opcode = HCI_Read_Best_Effort_Flush_Timeout; + } else if (MATCH_OP(op, "Write_Best_Effort_Flush_Timeout")) { + cpkt->opcode = HCI_Write_Best_Effort_Flush_Timeout; + } else if (MATCH_OP(op, "Read_Logical_Link_Accept_Timeout")) { + cpkt->opcode = HCI_Read_Logical_Link_Accept_Timeout; + } else if (MATCH_OP(op, "Write_Logical_Link_Accept_Timeout")) { + cpkt->opcode = HCI_Write_Logical_Link_Accept_Timeout; + } else if (MATCH_OP(op, "Read_Buffer_Size")) { + cpkt->opcode = HCI_Read_Buffer_Size; + } else if (MATCH_OP(op, "Read_Data_Block_Size")) { + cpkt->opcode = HCI_Read_Data_Block_Size; + } else if (MATCH_OP(op, "Set_Event_Mask_Page_2")) { + cpkt->opcode = HCI_Set_Event_Mask_Page_2; + } else if (MATCH_OP(op, "Flow_Spec_Modify")) { + cpkt->opcode = HCI_Flow_Spec_Modify; + } else if (MATCH_OP(op, "Read_Local_Version_Info")) { + cpkt->opcode = HCI_Read_Local_Version_Info; + } else if (MATCH_OP(op, "Read_Local_Supported_Commands")) { + cpkt->opcode = HCI_Read_Local_Supported_Commands; + } else if (MATCH_OP(op, "Read_Failed_Contact_Counter")) { + cpkt->opcode = HCI_Read_Failed_Contact_Counter; + } else if (MATCH_OP(op, "Reset_Failed_Contact_Counter")) { + cpkt->opcode = HCI_Reset_Failed_Contact_Counter; + } else { + printf("unsupported HCI command: %s\n", op); + return BCME_UNSUPPORTED; + } + + plen = 0; + while (*argv && (plen < HCI_CMD_DATA_SIZE)) { + cpkt->parms[plen++] = (uint8)strtol(*argv++, NULL, 0); + } + cpkt->plen = plen; + + return wlu_var_setbuf(wl, cmd->name, cpkt, HCI_CMD_PREAMBLE_SIZE + plen); +} + +static int +wl_HCI_ACL_data(void *wl, cmd_t *cmd, char **argv) +{ + amp_hci_ACL_data_t *dpkt; + uint16 dlen; + int ret; + + if (!*++argv) + return BCME_USAGE_ERROR; + + dpkt = (amp_hci_ACL_data_t *) malloc(HCI_ACL_DATA_PREAMBLE_SIZE + 2048); + if (!dpkt) + return BCME_NOMEM; + + /* get logical link handle */ + dpkt->handle = (HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS); + dpkt->handle |= (uint16)strtol(*argv++, NULL, 0); + + /* get data */ + dlen = 0; + while (*argv && (dlen < 2048)) { + dpkt->data[dlen++] = (uint8)strtol(*argv++, NULL, 0); + } + dpkt->dlen = dlen; + + ret = wlu_var_setbuf(wl, cmd->name, dpkt, HCI_ACL_DATA_PREAMBLE_SIZE + dlen); + + free(dpkt); + return ret; +} + +static int +wl_get_btamp_log(void *wl, cmd_t *cmd, char **argv) +{ + int err, i, j; + char *val_name; + uint8 *state; + uint8 idx = 0; + void *ptr = buf; + + UNUSED_PARAMETER(cmd); + + /* command name */ + val_name = *argv++; + + if (!*argv) { + if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr))) + return err; + state = (uint8 *)ptr; + idx = *state++; + + for (i = 0; i < BTA_STATE_LOG_SZ; i++, idx--) { + j = (idx & (BTA_STATE_LOG_SZ - 1)); + switch (state[j]) { + case HCIReset: + printf("%2d: HCI Reset\n", state[j]); + break; + case HCIReadLocalAMPInfo: + printf("%2d: HCI Read Local AMPInfo\n", state[j]); + break; + case HCIReadLocalAMPASSOC: + printf("%2d: HCI Read Local AMPASSOC\n", state[j]); + break; + case HCIWriteRemoteAMPASSOC: + printf("%2d: HCI Write Remote AMPASSOC\n", state[j]); + break; + case HCICreatePhysicalLink: + printf("%2d: HCI Create Physical Link\n", state[j]); + break; + case HCIAcceptPhysicalLinkRequest: + printf("%2d: HCI Accept Physical Link Request\n", state[j]); + break; + case HCIDisconnectPhysicalLink: + printf("%2d: HCI Disconnect Physical Link\n", state[j]); + break; + case HCICreateLogicalLink: + printf("%2d: HCI Create Logical Link\n", state[j]); + break; + case HCIAcceptLogicalLink: + printf("%2d: HCI Accept Logical Link\n", state[j]); + break; + case HCIDisconnectLogicalLink: + printf("%2d: HCI Disconnect Logical Link\n", state[j]); + break; + case HCILogicalLinkCancel: + printf("%2d: HCI Logical Link Cancel\n", state[j]); + break; + case HCIAmpStateChange: + printf("%2d: HCI Amp State Change\n", state[j]); + break; + default: + break; + } + } + return 0; + } else + err = wlu_iovar_setint(wl, val_name, (int)idx); + + return err; +} +#endif /* WLBTAMP */ + +/* + * RADAR detection parameter control + */ +static int +wl_radar_args(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + wl_radar_args_t ra; + + /* Skip the command name */ + argv++; + + if (*argv == NULL) { + /* Get */ + + if ((ret = wlu_iovar_get(wl, cmd->name, &ra, sizeof(ra))) < 0) + return ret; + + if (ra.version != WL_RADAR_ARGS_VERSION) { + printf("\tIncorrect version of RADAR_ARGS struct: expected %d; got %d\n", + WL_RADAR_ARGS_VERSION, ra.version); + return -1; + } + printf("version %d npulses %d ncontig %d min_pw %d max_pw %d thresh0 0x%x " + "thresh1 0x%x\n", + ra.version, ra.npulses, ra.ncontig, ra.min_pw, + ra.max_pw, ra.thresh0, ra.thresh1); + printf("blank 0x%x fmdemodcfg 0x%x npulses_lp %d min_pw_lp %d " + "max_pw_lp %d\n", + ra.blank, ra.fmdemodcfg, ra.npulses_lp, ra.min_pw_lp, + ra.max_pw_lp); + printf("min_fm_lp %d max_span_lp %d min_deltat %d max_deltat %d\n", + ra.min_fm_lp, ra.max_span_lp, ra.min_deltat, ra.max_deltat); + + printf("autocorr 0x%x st_level_time 0x%x t2_min %d fra_pulse_err %d\n", + ra.autocorr, ra.st_level_time, ra.t2_min, ra.fra_pulse_err); + printf("npulses_fra %d npulses_stg2 %d npulses_stg3 %d percal_mask 0x%x quant %d\n", + ra.npulses_fra, ra.npulses_stg2, ra.npulses_stg3, ra.percal_mask, + ra.quant); + printf("min_burst_intv_lp %d max_burst_intv_lp %d nskip_rst_lp %d max_pw_tol %d " + "feature_mask 0x%x\n", + ra.min_burst_intv_lp, ra.max_burst_intv_lp, ra.nskip_rst_lp, + ra.max_pw_tol, ra.feature_mask); + /* this part prints only param values */ + printf("%d %d %d %d %d 0x%x " + "0x%x", + ra.version, ra.npulses, ra.ncontig, ra.min_pw, + ra.max_pw, ra.thresh0, ra.thresh1); + printf(" 0x%x 0x%x %d %d " + "%d", + ra.blank, ra.fmdemodcfg, ra.npulses_lp, ra.min_pw_lp, + ra.max_pw_lp); + printf(" %d %d %d %d", + ra.min_fm_lp, ra.max_span_lp, ra.min_deltat, ra.max_deltat); + + printf(" 0x%x 0x%x %d %d", + ra.autocorr, ra.st_level_time, ra.t2_min, ra.fra_pulse_err); + printf(" %d %d %d 0x%x %d", + ra.npulses_fra, ra.npulses_stg2, ra.npulses_stg3, ra.percal_mask, + ra.quant); + printf(" %d %d %d %d " + "0x%x\n", + ra.min_burst_intv_lp, ra.max_burst_intv_lp, ra.nskip_rst_lp, + ra.max_pw_tol, ra.feature_mask); + + + } else { + /* Set */ + char *endptr = NULL; + int val_count = 30; + long vals[30]; + long *pval; + int i; + + for (i = 0; i < val_count; i++, argv++) { + /* verify that there is another arg */ + if (*argv == NULL) + return BCME_USAGE_ERROR; + + vals[i] = strtol(*argv, &endptr, 0); + + /* make sure all the value string was parsed by strtol */ + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + + pval = vals; + + ra.version = *pval++; + ra.npulses = *pval++; + ra.ncontig = *pval++; + ra.min_pw = *pval++; + ra.max_pw = *pval++; + ra.thresh0 = (uint16)*pval++; + ra.thresh1 = (uint16)*pval++; + ra.blank = (uint16)*pval++; + ra.fmdemodcfg = (uint16)*pval++; + ra.npulses_lp = *pval++; + ra.min_pw_lp = *pval++; + ra.max_pw_lp = *pval++; + ra.min_fm_lp = *pval++; + ra.max_span_lp = *pval++; + ra.min_deltat = *pval++; + ra.max_deltat = *pval++; + ra.autocorr = (uint16)*pval++; + ra.st_level_time = (uint16)*pval++; + ra.t2_min = (uint16)*pval++; + ra.fra_pulse_err = (uint32)*pval++; + ra.npulses_fra = (int)*pval++; + ra.npulses_stg2 = (int)*pval++; + ra.npulses_stg3 = (int)*pval++; + ra.percal_mask = (int)*pval++; + ra.quant = (int)*pval++; + ra.min_burst_intv_lp = (uint32)*pval++; + ra.max_burst_intv_lp = (uint32)*pval++; + ra.nskip_rst_lp = (int)*pval++; + ra.max_pw_tol = (int)*pval++; + ra.feature_mask = (uint16)*pval++; + + return wlu_var_setbuf(wl, cmd->name, &ra, sizeof(wl_radar_args_t)); + } + return ret; +} + +static int +wl_radar_thrs(void *wl, cmd_t *cmd, char **argv) +{ + int ret = -1; + wl_radar_thr_t radar_thrs; + + if (*++argv) { + /* Set */ + char *endptr; + int val_count = 12; + uint16 vals[12]; + uint16 *pval; + int i; + + for (i = 0; i < val_count; i++, argv++) { + /* verify that there is another arg */ + if (*argv == NULL) + return BCME_USAGE_ERROR; + + vals[i] = (uint16)strtol(*argv, &endptr, 0); + + /* make sure all the value string was parsed by strtol */ + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + + radar_thrs.version = WL_RADAR_THR_VERSION; + + /* Order thresh0_20_lo, thresh1_20_lo, thresh0_40_lo, thresh1_40_lo + * thresh0_20_hi, thresh1_20_hi, thresh0_40_hi, thresh1_40_hi + */ + pval = vals; + radar_thrs.thresh0_20_lo = (uint16)*pval++; + radar_thrs.thresh1_20_lo = (uint16)*pval++; + radar_thrs.thresh0_40_lo = (uint16)*pval++; + radar_thrs.thresh1_40_lo = (uint16)*pval++; + radar_thrs.thresh0_80_lo = (uint16)*pval++; + radar_thrs.thresh1_80_lo = (uint16)*pval++; + radar_thrs.thresh0_20_hi = (uint16)*pval++; + radar_thrs.thresh1_20_hi = (uint16)*pval++; + radar_thrs.thresh0_40_hi = (uint16)*pval++; + radar_thrs.thresh1_40_hi = (uint16)*pval++; + radar_thrs.thresh0_80_hi = (uint16)*pval++; + radar_thrs.thresh1_80_hi = (uint16)*pval++; + + return wlu_var_setbuf(wl, cmd->name, &radar_thrs, sizeof(wl_radar_thr_t)); + } + return ret; +} + +static int +wl_dfs_status(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + wl_dfs_status_t *dfs_status_ptr; + char chanspec_str[CHANSPEC_STR_LEN]; + + const char *dfs_cacstate_str[WL_DFS_CACSTATES] = { + "IDLE", + "PRE-ISM Channel Availability Check(CAC)", + "In-Service Monitoring(ISM)", + "Channel Switching Announcement(CSA)", + "POST-ISM Channel Availability Check", + "PRE-ISM Ouf Of Channels(OOC)", + "POST-ISM Out Of Channels(OOC)" + }; + + void *ptr; + + UNUSED_PARAMETER(argv); + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + dfs_status_ptr = (wl_dfs_status_t *)ptr; + + dfs_status_ptr->state = dtoh32(dfs_status_ptr->state); + dfs_status_ptr->duration = dtoh32(dfs_status_ptr->duration); + dfs_status_ptr->chanspec_cleared = wl_chspec_from_driver(dfs_status_ptr->chanspec_cleared); + + if (dfs_status_ptr->state >= WL_DFS_CACSTATES) { + printf("Unknown dfs state %d.\n", dfs_status_ptr->state); + return -1; + } + + printf("state %s time elapsed %dms radar channel cleared by dfs ", + dfs_cacstate_str[dfs_status_ptr->state], dfs_status_ptr->duration); + + if (dfs_status_ptr->chanspec_cleared) { + printf("channel %s (0x%04X)\n", + wf_chspec_ntoa(dfs_status_ptr->chanspec_cleared, chanspec_str), + dfs_status_ptr->chanspec_cleared); + } + else { + printf("none\n"); + } + + return ret; +} + +static int +wl_wds_wpa_role_old(void *wl, cmd_t *cmd, char **argv) +{ + uint remote[2]; + uint *sup = remote; + int ret = 0; + + UNUSED_PARAMETER(argv); + + if ((ret = wlu_get(wl, WLC_WDS_GET_REMOTE_HWADDR, remote, sizeof(remote))) < 0) { + printf("Unable to get remote endpoint's hwaddr\n"); + return ret; + } + if ((ret = wlu_get(wl, cmd->get, remote, sizeof(remote))) < 0) { + printf("Unable to get local endpoint's WPA role\n"); + return ret; + } + printf("Local endpoing's WPA role: %s\n", dtoh32(*sup) ? "supplicant" : "authenticator"); + return 0; +} + + +/* + * wlu_reg2args is a generic function that is used for setting/getting + * WL_IOVAR variables that require address for read, and + * address + data for write. + */ +static int +wlu_reg2args(void *wl, cmd_t *cmd, char **argv) +{ + char var[256]; + uint32 int_val; + bool get = TRUE; + uint32 len; + void *ptr = NULL; + char *endptr; + int ret = 0; + + if (argv[1]) { + len = sizeof(int_val); + int_val = htod32(strtoul(argv[1], &endptr, 0)); + memcpy(var, (char *)&int_val, sizeof(int_val)); + } + else + return BCME_USAGE_ERROR; + + if (argv[2]) { + get = FALSE; + int_val = htod32(strtoul(argv[2], &endptr, 0)); + memcpy(&var[len], (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + } + if (get) { + if ((ret = wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr)) < 0) + return ret; + + printf("0x%x\n", dtoh32(*(int *)ptr)); + } + else + ret = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var)); + return ret; +} + +/* + * wlu_reg3args is a generic function that is used for setting/getting + * WL_IOVAR variables that require address + offset for read, and + * address + offset + data for write. + */ +static int +wlu_reg3args(void *wl, cmd_t *cmd, char **argv) +{ + char var[256]; + uint32 int_val; + bool get = TRUE; + uint32 len, i; + void *ptr = NULL; + char *endptr; + uint numargs; + int ret = 0; + + len = 0; + + if (!argv[1] || !argv[2]) { + printf("Wrong syntax => dev offset [val]\n"); + return BCME_USAGE_ERROR; + } + + if (argv[3]) { + numargs = 3; + get = FALSE; + } else + numargs = 2; + + for (i = 1; i <= numargs; i++) { + int_val = htod32(strtoul(argv[i], &endptr, 0)); + memcpy(&var[len], (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + } + + if (get) { + if ((ret = wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr)) < 0) + return ret; + + printf("0x%x\n", dtoh32(*(int *)ptr)); + } + else + ret = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var)); + return ret; +} + + +static int +wl_tpc_lm(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + uint16 val; + int8 aplm, stalm; + + UNUSED_PARAMETER(argv); + + if ((ret = wlu_iovar_getint(wl, cmd->name, (int *)(uintptr)&val)) < 0) + return ret; + + stalm = val & 0xff; + aplm = (val >> 8) & 0xff; + + printf("TPC: APs link margin:%d\t STAs link margin:%d\n", aplm, stalm); + + return 0; +} + + +static int +wl_wds_wpa_role(void *wl, cmd_t *cmd, char **argv) +{ + char var[256]; + char *mac; + char *sup; + int len; + int ret; + if (strlen("wds_wpa_role") + 1 + ETHER_ADDR_LEN + 1 > sizeof(var)) + return -1; + /* build var required by WLC_GET|SET_VAR */ + len = sprintf(var, "%s", "wds_wpa_role") + 1; + mac = var + len; + if ((ret = wlu_get(wl, WLC_WDS_GET_REMOTE_HWADDR, mac, ETHER_ADDR_LEN)) < 0) { + printf("Unable to get remote endpoint's hwaddr\n"); + return ret; + } + len += ETHER_ADDR_LEN + 1; + if (argv[1]) { + sup = mac + ETHER_ADDR_LEN; + switch ((uchar)(*sup = atoi(argv[1]))) { + case WL_WDS_WPA_ROLE_AUTH: + case WL_WDS_WPA_ROLE_SUP: + case WL_WDS_WPA_ROLE_AUTO: + if ((ret = wlu_set(wl, cmd->set, var, len)) < 0) + printf("Unable to set local endpoint's WPA role\n"); + break; + default: + printf("Invalid WPA role %s. %u:authenticator, %u:supplicant, %u:auto\n", + argv[1], WL_WDS_WPA_ROLE_AUTH, + WL_WDS_WPA_ROLE_SUP, WL_WDS_WPA_ROLE_AUTO); + break; + } + } + else if ((ret = wlu_get(wl, cmd->get, var, len)) < 0) { + printf("Unable to get local endpoint's WPA role\n"); + return ret; + } + else { + sup = var; + printf("Local endpoint's WPA role: %s\n", *sup ? "supplicant" : "authenticator"); + } + return ret; +} + +static int +wl_measure_req(void *wl, cmd_t *cmd, char **argv) +{ + uint32 val; + struct ether_addr ea; + + if (!*++argv) { + printf("error: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + if (!stricmp(*argv, "tpc")) + val = WLC_MEASURE_TPC; + else if (!stricmp(*argv, "basic")) + val = WLC_MEASURE_CHANNEL_BASIC; + else if (!stricmp(*argv, "cca")) + val = WLC_MEASURE_CHANNEL_CCA; + else if (!stricmp(*argv, "rpi")) + val = WLC_MEASURE_CHANNEL_RPI; + else { + printf("error: unknown measurement type %s\n", *argv); + return BCME_USAGE_ERROR; + } + argv++; + + if (!*argv) { + printf("error: missing target address\n"); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv, &ea)) { + printf("error: could not parse MAC address %s\n", *argv); + return BCME_USAGE_ERROR; + } + + val = htod32(val); + memcpy(&buf[0], &val, sizeof(uint32)); + memcpy(&buf[4], ea.octet, ETHER_ADDR_LEN); + + return wlu_set(wl, cmd->set, buf, sizeof(uint32) + ETHER_ADDR_LEN); +} + +static int +wl_send_quiet(void *wl, cmd_t *cmd, char **argv) +{ + dot11_quiet_t quiet; + + if (!*++argv) { + printf("error: missing arguments\n"); + return BCME_USAGE_ERROR; + } + /* Order is count, duration, offset */ + quiet.count = atoi(*argv); + if (!*++argv) { + printf("error: missing arguments\n"); + return BCME_USAGE_ERROR; + } + quiet.duration = atoi(*argv); + if (!*++argv) { + printf("error: missing arguments\n"); + return BCME_USAGE_ERROR; + } + quiet.offset = atoi(*argv); + quiet.period = 0; + + quiet.duration = htod16(quiet.duration); + quiet.offset = htod16(quiet.offset); + return (wlu_set(wl, cmd->set, &quiet, sizeof(quiet))); +} + +static int +wl_send_csa(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_chan_switch_t csa_arg; + + /* Order is mode, count channel */ + if (!*++argv) { + printf("error: missing arguments\n"); + return BCME_USAGE_ERROR; + } + csa_arg.mode = atoi(*argv) ? 1 : 0; + if (!*++argv) { + printf("error: missing count\n"); + return BCME_USAGE_ERROR; + } + csa_arg.count = atoi(*argv); + if (!*++argv) { + printf("error: missing channel\n"); + return BCME_USAGE_ERROR; + } + csa_arg.reg = 0; + + if ((csa_arg.chspec = wf_chspec_aton(*argv))) { + csa_arg.chspec = wl_chspec_to_driver(csa_arg.chspec); + if (csa_arg.chspec == INVCHANSPEC) { + return BCME_USAGE_ERROR; + } + /* csa action frame type */ + if (*++argv) { + if (strcmp(*argv, "u") == 0) + csa_arg.frame_type = CSA_UNICAST_ACTION_FRAME; + else { + printf("error: invalid frame type: %s\n", *argv); + return BCME_USAGE_ERROR; + } + } else + csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME; + + err = wlu_var_setbuf(wl, cmd->name, &csa_arg, sizeof(csa_arg)); + } else { + printf("Error: bad parameters \"%s\"\n", *argv); + return BCME_BADARG; + } + + return err; +} + +static int +wl_var_setint(void *wl, cmd_t *cmd, char **argv) +{ + int32 val; + char *varname; + char *endptr = NULL; + + UNUSED_PARAMETER(cmd); + + if (!*argv) { + printf("set: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + varname = *argv++; + + if (!*argv) { + printf("set: missing value argument for set of \"%s\"\n", varname); + return BCME_USAGE_ERROR; + } + + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n", + *argv, varname); + return BCME_USAGE_ERROR; + } + + return wlu_iovar_setint(wl, varname, val); +} + +static int +wl_var_get(void *wl, cmd_t *cmd, char **argv) +{ + char *varname; + char *p; + + UNUSED_PARAMETER(cmd); + + if (!*argv) { + printf("get: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + varname = *argv++; + + if (*argv) { + printf("get: error, extra arg \"%s\"\n", *argv); + return BCME_USAGE_ERROR; + } + + strcpy(buf, varname); + p = buf; + while (*p != '\0') { + *p = tolower((int)*p); + p++; + } + return (wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN)); +} + +static int +wl_var_getinthex(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int32 val; + + if ((err = wl_var_get(wl, cmd, argv))) + return (err); + + val = dtoh32(*(int32*)buf); + + printf("0x%08x\n", val); + + return 0; +} +static int +wl_var_getint(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int32 val; + char *varname; + + UNUSED_PARAMETER(cmd); + + if (!*argv) { + printf("get: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + varname = *argv++; + + if ((err = wlu_iovar_getint(wl, varname, &val))) + return (err); + + if (val < 10) + printf("%d\n", val); + else + printf("%d (0x%x)\n", val, val); + + return (0); +} + +static int +wl_var_getandprintstr(void *wl, cmd_t *cmd, char **argv) +{ + int err; + + if ((err = wl_var_get(wl, cmd, argv))) + return (err); + + printf("%s\n", buf); + return (0); +} + +/* Variation: Like getandprint, but allow an int arg to be passed */ +static int +wl_var_setintandprintstr(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int32 val; + char *varname; + char *endptr = NULL; + + UNUSED_PARAMETER(cmd); + + if (!*argv) { + printf("set: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + varname = *argv++; + + if (!*argv) { + val = 0; + } else { + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n", + *argv, varname); + return BCME_USAGE_ERROR; + } + } + + val = htod32(val); + err = wlu_iovar_getbuf(wl, varname, &val, sizeof(int), buf, WLC_IOCTL_MAXLEN); + + if (err) + return (err); + + printf("%s\n", buf); + return (0); +} + +void +wl_printlasterror(void *wl) +{ + char error_str[128]; + + if (wlu_iovar_get(wl, "bcmerrorstr", error_str, sizeof(error_str)) != 0) { + fprintf(stderr, "%s: \nError getting the last error\n", wlu_av0); + } else { + fprintf(stderr, "%s: %s\n", wlu_av0, error_str); + } +} + +/* just issue a wl_var_setint() or a wl_var_getint() if there is a 2nd arg */ +int +wl_varint(void *wl, cmd_t *cmd, char *argv[]) +{ + if (argv[1]) + return (wl_var_setint(wl, cmd, argv)); + else + return (wl_var_getint(wl, cmd, argv)); +} + +int +wlu_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr) +{ + int len; + + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&buf[len], param, param_len); + + *bufptr = buf; + + return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN); +} + +/* get buffer for smaller sizes upto 256 bytes */ +int +wlu_var_getbuf_sm(void *wl, const char *iovar, void *param, int param_len, void **bufptr) +{ + int len; + + memset(buf, 0, WLC_IOCTL_SMLEN); + strcpy(buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&buf[len], param, param_len); + + *bufptr = buf; + + return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_SMLEN); +} + +/* Get buffer for medium sizes upto 1500 bytes */ +int +wlu_var_getbuf_med(void *wl, const char *iovar, void *param, int param_len, void **bufptr) +{ + int len; + + memset(buf, 0, WLC_IOCTL_MEDLEN); + strcpy(buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&buf[len], param, param_len); + + *bufptr = buf; + + return wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MEDLEN); +} + + +int +wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len) +{ + int len; + + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&buf[len], param, param_len); + + len += param_len; + + return wlu_set(wl, WLC_SET_VAR, &buf[0], len); +} + +int +wlu_var_setbuf_sm(void *wl, const char *iovar, void *param, int param_len) +{ + int len; + + memset(buf, 0, WLC_IOCTL_SMLEN); + strcpy(buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&buf[len], param, param_len); + + len += param_len; + + return wlu_set(wl, WLC_SET_VAR, &buf[0], WLC_IOCTL_SMLEN); +} + +int +wlu_var_setbuf_med(void *wl, const char *iovar, void *param, int param_len) +{ + int len; + + memset(buf, 0, WLC_IOCTL_MEDLEN); + strcpy(buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&buf[len], param, param_len); + + len += param_len; + + return wlu_set(wl, WLC_SET_VAR, &buf[0], WLC_IOCTL_MEDLEN); +} + +static int +wl_var_void(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(argv); + + if (cmd->set < 0) + return -1; + + return wlu_var_setbuf(wl, cmd->name, NULL, 0); +} + +/* + * format a "prefix" indexed iovar buffer + */ +static int +wl_prefixiovar_mkbuf(const char *iovar, const char *prefix, int prefix_index, void *param, + int paramlen, void *bufptr, int buflen, int *perr) +{ + int8* p; + uint prefixlen; + uint namelen; + uint iolen; + + prefixlen = strlen(prefix); /* length of iovar prefix "bsscfg:ssid %d wlc:counter %d" */ + namelen = strlen(iovar) + 1; /* length of iovar name + null */ + iolen = prefixlen + namelen + sizeof(int) + paramlen; + + /* check for overflow */ + if (buflen < 0 || iolen > (uint)buflen) { + *perr = BCME_BUFTOOSHORT; + return 0; + } + + p = (int8*)bufptr; + + /* copy prefix, no null */ + memcpy(p, prefix, prefixlen); + p += prefixlen; + + /* copy iovar name including null */ + memcpy(p, iovar, namelen); + p += namelen; + + /* send index as first param */ + prefix_index = htod32(prefix_index); + memcpy(p, &prefix_index, sizeof(int32)); + p += sizeof(int32); + + /* parameter buffer follows */ + if (paramlen) + memcpy(p, param, paramlen); + + *perr = 0; + return iolen; +} + +static int +wl_bssiovar_mkbuf(const char *iovar, int bssidx, void *param, + int paramlen, void *bufptr, int buflen, int *perr) +{ + const char *prefix = "bsscfg:"; + return wl_prefixiovar_mkbuf(iovar, prefix, bssidx, param, paramlen, bufptr, buflen, perr); +} +/* + * set named & bss indexed driver iovar providing both parameter and i/o buffers + */ +int +wlu_bssiovar_setbuf(void* wl, const char *iovar, int bssidx, + void *param, int paramlen, void *bufptr, int buflen) +{ + int err; + int iolen; + + iolen = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &err); + if (err) + return err; + + return wlu_set(wl, WLC_SET_VAR, bufptr, iolen); +} + +/* + * get named & bss indexed driver iovar providing both parameter and i/o buffers + */ +static int +wl_bssiovar_getbuf(void* wl, const char *iovar, int bssidx, + void *param, int paramlen, void *bufptr, int buflen) +{ + int err; + + wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &err); + if (err) + return err; + + return wlu_get(wl, WLC_GET_VAR, bufptr, buflen); +} + +/* + * get named & bss indexed driver variable to buffer value + */ +int +wlu_bssiovar_get(void *wl, const char *iovar, int bssidx, void *outbuf, int len) +{ + char smbuf[WLC_IOCTL_SMLEN]; + int err; + + /* use the return buffer if it is bigger than what we have on the stack */ + if (len > (int)sizeof(smbuf)) { + err = wl_bssiovar_getbuf(wl, iovar, bssidx, NULL, 0, outbuf, len); + } else { + memset(smbuf, 0, sizeof(smbuf)); + err = wl_bssiovar_getbuf(wl, iovar, bssidx, NULL, 0, smbuf, sizeof(smbuf)); + if (err == 0) + memcpy(outbuf, smbuf, len); + } + + return err; +} + +/* + * set named & bss indexed driver variable to buffer value + */ +static int +wl_bssiovar_set(void *wl, const char *iovar, int bssidx, void *param, int paramlen) +{ + char smbuf[WLC_IOCTL_SMLEN]; + + memset(smbuf, 0, sizeof(smbuf)); + + return wlu_bssiovar_setbuf(wl, iovar, bssidx, param, paramlen, smbuf, sizeof(smbuf)); +} + +/* + * get named & bsscfg indexed driver variable as an int value + */ +static int +wl_bssiovar_getint(void *wl, const char *iovar, int bssidx, int *pval) +{ + int ret; + + ret = wlu_bssiovar_get(wl, iovar, bssidx, pval, sizeof(int)); + if (ret == 0) + { + *pval = dtoh32(*pval); + } + return ret; +} + +/* + * set named & bsscfg indexed driver variable to int value + */ +static int +wl_bssiovar_setint(void *wl, const char *iovar, int bssidx, int val) +{ + val = htod32(val); + return wl_bssiovar_set(wl, iovar, bssidx, &val, sizeof(int)); +} + +static int +wl_nvdump(void *wl, cmd_t *cmd, char **argv) +{ + int err; + const char *iovar = "nvram_dump"; + void *p = NULL; + + UNUSED_PARAMETER(cmd); + + /* skip the "nvdump/nvram_dump" command name */ + argv++; + + if (*argv) { + printf("nvdump error: extra arg \"%s\"\n", *argv); + return BCME_USAGE_ERROR; + } + + if ((err = wlu_var_getbuf(wl, iovar, NULL, 0, &p)) < 0) { + if ((err = wlu_get(wl, WLC_NVRAM_DUMP, &buf[0], WLC_IOCTL_MAXLEN)) < 0) + return err; + p = (void *)buf; + } + printf("%s\n", (char *)p); + + return err; +} + +/** Queries the driver for the value of a caller supplied nvram variable */ +static int +wl_nvget(void *wl, cmd_t *cmd, char **argv) +{ + int err; + char *varname; + const char *iovar = "nvram_get"; + void *p; + + UNUSED_PARAMETER(cmd); + + /* skip the "nvget/nvram_get" command name */ + argv++; + + if (!*argv) { + printf("nvget: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + varname = *argv++; + + if (*argv) { + printf("nvget error: extra arg \"%s\"\n", *argv); + return BCME_USAGE_ERROR; + } + + if ((err = wlu_var_getbuf(wl, iovar, varname, strlen(varname) + 1, &p)) < 0) { + + strcpy(buf, varname); + if ((err = wlu_get(wl, WLC_NVRAM_GET, &buf[0], WLC_IOCTL_MAXLEN)) < 0) + return err; + } + + printf("%s\n", buf); + + return err; +} + +static int +wl_nvset(void *wl, cmd_t *cmd, char **argv) +{ + char *varname; + + UNUSED_PARAMETER(cmd); + + /* skip the "nvset" command name if present */ + if (!strcmp("nvset", *argv)) + argv++; + + if (!*argv) { + printf("nvset: missing arguments\n"); + return BCME_USAGE_ERROR; + } + + varname = *argv++; + + if (*argv) { + fprintf(stderr, + "nvset error: extra arg \"%s\"; format is name=value (no spaces around '=')\n", + *argv); + return BCME_USAGE_ERROR; + } + + if (!strchr(varname, '=')) { + fprintf(stderr, + "nvset error: no '=' in \"%s\", format is name=value (no spaces around '=')\n", + *argv); + return BCME_USAGE_ERROR; + } + + strcpy(buf, varname); + + return (wlu_set(wl, WLC_NVRAM_SET, &buf[0], strlen(buf) + 1)); +} + +static int +wl_chan_info(void *wl, cmd_t *cmd, char **argv) +{ + uint bitmap; + uint channel; + uint32 chanspec_arg; + int buflen, err, first, last, minutes; + char *param; + bool all; + + if (!*++argv) { + first = 0; + last = MAXCHANNEL; + all = TRUE; + } else { + last = first = atoi(*argv); + if (last <= 0) { + printf(" Usage: %s [channel | All ]\n", cmd->name); + return BCME_USAGE_ERROR; + } + all = FALSE; + } + + for (; first <= last; first++) { + channel = first; + chanspec_arg = CH20MHZ_CHSPEC(channel); + + strcpy(buf, "per_chan_info"); + buflen = strlen(buf) + 1; + param = (char *)(buf + buflen); + /* there should be no problem if converting to a legacy chanspec + * since chanspec_arg is created as 20MHz + */ + chanspec_arg = wl_chspec32_to_driver(chanspec_arg); + memcpy(param, (char*)&chanspec_arg, sizeof(chanspec_arg)); + + if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return err; + + bitmap = dtoh32(*(uint *)buf); + minutes = (bitmap >> 24) & 0xff; + + if (!(bitmap & WL_CHAN_VALID_HW)) { + if (!all) + printf("Invalid Channel\n"); + continue; + } + + if (!(bitmap & WL_CHAN_VALID_SW)) { + if (!all) + printf("Not supported in current locale\n"); + continue; + } + + printf("Channel %d\t", channel); + + if (bitmap & WL_CHAN_BAND_5G) + printf("A Band"); + else + printf("B Band"); + + if (bitmap & WL_CHAN_RADAR) { + printf(", RADAR Sensitive"); + } + if (bitmap & WL_CHAN_RESTRICTED) { + printf(", Restricted"); + } + if (bitmap & WL_CHAN_PASSIVE) { + printf(", Passive"); + } + if (bitmap & WL_CHAN_INACTIVE) { + printf(", Temporarily Out of Service for %d minutes", minutes); + } + printf("\n"); + } + + return (0); +} + +static int +wl_test_tssi(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + char* endptr = NULL; + + /* toss the command name */ + argv++; + + if (!*argv) + return BCME_USAGE_ERROR; + + val = htod32(strtol(*argv, &endptr, 0)); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + printf("set: error parsing value \"%s\" as an integer\n", *argv); + return BCME_USAGE_ERROR; + } + + ret = wlu_iovar_getbuf(wl, cmd->name, &val, sizeof(val), + buf, WLC_IOCTL_MAXLEN); + + if (ret) + return ret; + + val = dtoh32(*(int*)buf); + + wl_printint(val); + + return ret; +} + +static int +wl_test_tssi_offs(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + char* endptr = NULL; + + /* toss the command name */ + argv++; + + if (!*argv) + return BCME_USAGE_ERROR; + + val = htod32(strtol(*argv, &endptr, 0)); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + printf("set: error parsing value \"%s\" as an integer\n", *argv); + return BCME_USAGE_ERROR; + } + + ret = wlu_iovar_getbuf(wl, cmd->name, &val, sizeof(val), + buf, WLC_IOCTL_MAXLEN); + + if (ret) + return ret; + + val = dtoh32(*(int*)buf); + + wl_printint(val); + + return ret; +} + +static int +wl_test_idletssi(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int val; + char* endptr = NULL; + + /* toss the command name */ + argv++; + + if (!*argv) + return BCME_USAGE_ERROR; + + val = htod32(strtol(*argv, &endptr, 0)); + if (*endptr != '\0') { + /* not all the value string was parsed by strtol */ + printf("set: error parsing value \"%s\" as an integer\n", *argv); + return -1; + } + + if ((ret = wlu_iovar_getbuf(wl, cmd->name, &val, sizeof(val), + buf, WLC_IOCTL_MAXLEN)) >= 0) { + val = dtoh32(*(int*)buf); + wl_printint(val); + } + + return ret; +} + +static int +wl_sta_info(void *wl, cmd_t *cmd, char **argv) +{ + sta_info_t *sta; + struct ether_addr ea; + char *param; + int buflen, err; + int i; + + /* convert the ea string into an ea struct */ + if (!*++argv || !wl_ether_atoe(*argv, &ea)) { + printf(" ERROR: no valid ether addr provided\n"); + return BCME_USAGE_ERROR; + } + + strcpy(buf, "sta_info"); + buflen = strlen(buf) + 1; + param = (char *)(buf + buflen); + memcpy(param, (char*)&ea, ETHER_ADDR_LEN); + + if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MEDLEN)) < 0) + return err; + + /* display the sta info */ + sta = (sta_info_t *)buf; + sta->ver = dtoh16(sta->ver); + + /* Report unrecognized version */ + if (sta->ver > WL_STA_VER) { + printf(" ERROR: unknown driver station info version %d\n", sta->ver); + return BCME_ERROR; + } + + sta->len = dtoh16(sta->len); + sta->cap = dtoh16(sta->cap); + sta->aid = dtoh16(sta->aid); + sta->flags = dtoh32(sta->flags); + sta->idle = dtoh32(sta->idle); + sta->rateset.count = dtoh32(sta->rateset.count); + sta->in = dtoh32(sta->in); + sta->listen_interval_inms = dtoh32(sta->listen_interval_inms); + sta->ht_capabilities = dtoh16(sta->ht_capabilities); + sta->vht_flags = dtoh16(sta->vht_flags); + + printf(" STA %s:\n", *argv); + printf("\t aid:%d ", WL_STA_AID(sta->aid)); + printf("\n\t rateset "); + dump_rateset(sta->rateset.rates, sta->rateset.count); + printf("\n\t idle %d seconds\n", sta->idle); + printf("\t in network %d seconds\n", sta->in); + printf("\t state:%s%s%s\n", + (sta->flags & WL_STA_AUTHE) ? " AUTHENTICATED" : "", + (sta->flags & WL_STA_ASSOC) ? " ASSOCIATED" : "", + (sta->flags & WL_STA_AUTHO) ? " AUTHORIZED" : ""); + + printf("\t flags 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + sta->flags, + (sta->flags & WL_STA_BRCM) ? " BRCM" : "", + (sta->flags & WL_STA_WME) ? " WME" : "", + (sta->flags & WL_STA_PS) ? " PS" : "", + (sta->flags & WL_STA_NONERP) ? " No-ERP" : "", + (sta->flags & WL_STA_APSD_BE) ? " APSD_BE" : "", + (sta->flags & WL_STA_APSD_BK) ? " APSD_BK" : "", + (sta->flags & WL_STA_APSD_VI) ? " APSD_VI" : "", + (sta->flags & WL_STA_APSD_VO) ? " APSD_VO" : "", + (sta->flags & WL_STA_N_CAP) ? " N_CAP" : "", + (sta->flags & WL_STA_VHT_CAP) ? " VHT_CAP" : "", + (sta->flags & WL_STA_AMPDU_CAP) ? " AMPDU" : "", + (sta->flags & WL_STA_AMSDU_CAP) ? " AMSDU" : "", + (sta->flags & WL_STA_MIMO_PS) ? " MIMO-PS" : "", + (sta->flags & WL_STA_MIMO_RTS) ? " MIMO-PS-RTS" : "", + (sta->flags & WL_STA_RIFS_CAP) ? " RIFS" : ""); + + printf("\t HT caps 0x%x:%s%s%s%s%s%s%s%s%s\n", + sta->ht_capabilities, + (sta->ht_capabilities & WL_STA_CAP_LDPC_CODING) ? " LDPC" : "", + (sta->ht_capabilities & WL_STA_CAP_40MHZ) ? " 40MHz" : " ", + (sta->ht_capabilities & WL_STA_CAP_GF) ? " GF" : "", + (sta->ht_capabilities & WL_STA_CAP_SHORT_GI_20) ? " SGI20" : "", + (sta->ht_capabilities & WL_STA_CAP_SHORT_GI_40) ? " SGI40" : "", + (sta->ht_capabilities & WL_STA_CAP_TX_STBC) ? " STBC-Tx" : "", + (sta->ht_capabilities & WL_STA_CAP_RX_STBC_MASK) ? " STBC-Rx" : "", + (sta->ht_capabilities & WL_STA_CAP_DELAYED_BA) ? " D-BlockAck" : "", + (sta->ht_capabilities & WL_STA_CAP_40MHZ_INTOLERANT) ? " 40-Intl" : ""); + + if (sta->flags & WL_STA_VHT_CAP) { + printf("\t VHT caps 0x%x:%s%s%s%s%s%s%s%s%s%s%s\n", + sta->vht_flags, + (sta->vht_flags & WL_STA_VHT_LDPCCAP) ? " LDPC" : "", + (sta->vht_flags & WL_STA_SGI80) ? " SGI80" : "", + (sta->vht_flags & WL_STA_SGI160) ? " SGI160" : "", + (sta->vht_flags & WL_STA_VHT_TX_STBCCAP) ? " STBC-Tx" : "", + (sta->vht_flags & WL_STA_VHT_RX_STBCCAP) ? " STBC-Rx" : "", + (sta->vht_flags & WL_STA_SU_BEAMFORMER) ? " SU-BFR" : "", + (sta->vht_flags & WL_STA_SU_BEAMFORMEE) ? " SU-BFE" : "", + (sta->vht_flags & WL_STA_MU_BEAMFORMER) ? " MU-BFR" : "", + (sta->vht_flags & WL_STA_MU_BEAMFORMEE) ? " MU-BFE" : "", + (sta->vht_flags & WL_STA_VHT_TXOP_PS) ? " TXOPPS" : "", + (sta->vht_flags & WL_STA_HTC_VHT_CAP) ? " VHT-HTC" : ""); + } + + /* Driver didn't return extended station info */ + if (sta->len < sizeof(sta_info_t)) + return 0; + + if (sta->flags & WL_STA_SCBSTATS) + { + printf("\t tx data pkts: %d\n", dtoh32(sta->tx_tot_pkts)); + printf("\t tx data bytes: %llu\n", dtoh64(sta->tx_tot_bytes)); + printf("\t tx ucast pkts: %d\n", dtoh32(sta->tx_pkts)); + printf("\t tx ucast bytes: %llu\n", dtoh64(sta->tx_ucast_bytes)); + printf("\t tx mcast/bcast pkts: %d\n", dtoh32(sta->tx_mcast_pkts)); + printf("\t tx mcast/bcast bytes: %llu\n", dtoh64(sta->tx_mcast_bytes)); + printf("\t tx failures: %d\n", dtoh32(sta->tx_failures)); + printf("\t rx data pkts: %d\n", dtoh32(sta->rx_tot_pkts)); + printf("\t rx data bytes: %llu\n", dtoh64(sta->rx_tot_bytes)); + printf("\t rx ucast pkts: %d\n", dtoh32(sta->rx_ucast_pkts)); + printf("\t rx ucast bytes: %llu\n", dtoh64(sta->rx_ucast_bytes)); + printf("\t rx mcast/bcast pkts: %d\n", dtoh32(sta->rx_mcast_pkts)); + printf("\t rx mcast/bcast bytes: %llu\n", dtoh64(sta->rx_mcast_bytes)); + printf("\t rate of last tx pkt: %d kbps\n", dtoh32(sta->tx_rate)); + printf("\t rate of last rx pkt: %d kbps\n", dtoh32(sta->rx_rate)); + printf("\t rx decrypt succeeds: %d\n", dtoh32(sta->rx_decrypt_succeeds)); + printf("\t rx decrypt failures: %d\n", dtoh32(sta->rx_decrypt_failures)); + printf("\t tx data pkts retried: %d\n", dtoh32(sta->tx_pkts_retried)); + printf("\t tx data pkts retry exhausted: %d\n", + dtoh32(sta->tx_pkts_retry_exhausted)); + for (i = WL_ANT_IDX_1; i < WL_RSSI_ANT_MAX; i++) { + if (i == WL_ANT_IDX_1) + printf("\t per antenna rssi of last rx data frame:"); + printf(" %d", dtoh32(sta->rx_lastpkt_rssi[i])); + if (i == WL_RSSI_ANT_MAX-1) + printf("\n"); + } + for (i = WL_ANT_IDX_1; i < WL_RSSI_ANT_MAX; i++) { + if (i == WL_ANT_IDX_1) + printf("\t per antenna average rssi of rx data frames:"); + printf(" %d", dtoh32(sta->rssi[i])); + if (i == WL_RSSI_ANT_MAX-1) + printf("\n"); + } + for (i = WL_ANT_IDX_1; i < WL_RSSI_ANT_MAX; i++) { + if (i == WL_ANT_IDX_1) + printf("\t per antenna noise floor:"); + printf(" %d", dtoh32(sta->nf[i])); + if (i == WL_RSSI_ANT_MAX-1) + printf("\n"); + } + } + + return (0); +} + +static int +wl_revinfo(void *wl, cmd_t *cmd, char **argv) +{ + char b[8]; + int err; + wlc_rev_info_t revinfo; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + memset(&revinfo, 0, sizeof(revinfo)); + + if ((err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0) + return err; + + printf("vendorid 0x%x\n", dtoh32(revinfo.vendorid)); + printf("deviceid 0x%x\n", dtoh32(revinfo.deviceid)); + printf("radiorev 0x%x\n", dtoh32(revinfo.radiorev)); + printf("chipnum 0x%x\n", dtoh32(revinfo.chipnum)); + printf("chiprev 0x%x\n", dtoh32(revinfo.chiprev)); + printf("chippackage 0x%x\n", dtoh32(revinfo.chippkg)); + printf("corerev 0x%x\n", dtoh32(revinfo.corerev)); + printf("boardid 0x%x\n", dtoh32(revinfo.boardid)); + printf("boardvendor 0x%x\n", dtoh32(revinfo.boardvendor)); + printf("boardrev %s\n", bcm_brev_str(dtoh32(revinfo.boardrev), b)); + printf("driverrev 0x%x\n", dtoh32(revinfo.driverrev)); + printf("ucoderev 0x%x\n", dtoh32(revinfo.ucoderev)); + printf("bus 0x%x\n", dtoh32(revinfo.bus)); + printf("phytype 0x%x\n", dtoh32(revinfo.phytype)); + printf("phyrev 0x%x\n", dtoh32(revinfo.phyrev)); + printf("anarev 0x%x\n", dtoh32(revinfo.anarev)); + printf("nvramrev %d\n", dtoh32(revinfo.nvramrev)); + + return 0; +} + +static int +wl_rm_request(void *wl, cmd_t *cmd, char **argv) +{ + miniopt_t to; + const char* fn_name = "wl_rm_request"; + wl_rm_req_t *rm_ptr; + wl_rm_req_t rm; + wl_rm_req_elt_t req; + int buflen = 0; + int err, opt_err; + int type; + bool in_measure = FALSE; + + UNUSED_PARAMETER(cmd); + + memset(buf, 0, WLC_IOCTL_MAXLEN); + memset(&rm, 0, WL_RM_REQ_FIXED_LEN); + memset(&req, 0, sizeof(wl_rm_req_elt_t)); + + strcpy(buf, "rm_req"); + buflen = strlen(buf) + 1; + + rm_ptr = (wl_rm_req_t*)(buf + buflen); + buflen += WL_RM_REQ_FIXED_LEN; + + /* toss the command name */ + argv++; + + miniopt_init(&to, fn_name, "p", FALSE); + while ((opt_err = miniopt(&to, argv)) != -1) { + if (opt_err == 1) { + err = BCME_USAGE_ERROR; + goto exit; + } + argv += to.consumed; + + if (to.opt == 't') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for the token\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + + if (!in_measure) + rm.token = to.val; + else + req.token = to.val; + } + if (to.opt == 'c') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for channel\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + + req.chanspec = CH20MHZ_CHSPEC(to.val); + } + if (to.opt == 'd') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for duration\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + req.dur = to.val; + } + + if (to.opt == 'p') { + req.flags = WL_RM_FLAG_PARALLEL; + } + + if (to.positional) { + if (!strcmp(to.valstr, "basic")) { + type = WL_RM_TYPE_BASIC; + } else if (!strcmp(to.valstr, "cca")) { + type = WL_RM_TYPE_CCA; + } else if (!strcmp(to.valstr, "rpi")) { + type = WL_RM_TYPE_RPI; + } else { + fprintf(stderr, + "%s: could not parse \"%s\" as a measurement type\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + /* complete the previous measurement */ + if (in_measure) { + req.chanspec = wl_chspec_to_driver(req.chanspec); + req.token = htod32(req.token); + req.tsf_h = htod32(req.tsf_h); + req.tsf_l = htod32(req.tsf_l); + req.dur = htod32(req.dur); + memcpy(buf + buflen, &req, sizeof(wl_rm_req_elt_t)); + buflen += sizeof(wl_rm_req_elt_t); + rm.count++; + req.chanspec = wl_chspec_from_driver(req.chanspec); + req.token = dtoh32(req.token); + req.tsf_h = dtoh32(req.tsf_h); + req.tsf_l = dtoh32(req.tsf_l); + req.dur = dtoh32(req.dur); + /* measure to measure default param update */ + req.token++; /* each measure gets a new token */ + req.flags = 0; /* measure flags are cleared between measures */ + } + in_measure = TRUE; + req.type = (int8)type; + } + } + + /* complete the last measurement */ + if (in_measure) { + req.chanspec = wl_chspec_to_driver(req.chanspec); + req.token = htod32(req.token); + req.tsf_h = htod32(req.tsf_h); + req.tsf_l = htod32(req.tsf_l); + req.dur = htod32(req.dur); + memcpy(buf + buflen, &req, sizeof(wl_rm_req_elt_t)); + buflen += sizeof(wl_rm_req_elt_t); + rm.count++; + } + + if (rm.count == 0) { + fprintf(stderr, "%s: no measurement requests specified\n", + fn_name); + err = BCME_USAGE_ERROR; + goto exit; + } + + rm.token = htod32(rm.token); + rm.count = htod32(rm.count); + memcpy(rm_ptr, &rm, WL_RM_REQ_FIXED_LEN); + + err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen); + +exit: + return err; +} + +static int +wl_rm_report(void *wl, cmd_t *cmd, char **argv) +{ + wl_rm_rep_t *rep_set; + wl_rm_rep_elt_t rep; + char extra[128]; + char* p; + const char* name; + uint8* data; + int err, bin; + uint32 val; + uint16 channel; + bool aband; + int len; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + strcpy(buf, "rm_rep"); + + if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], WLC_IOCTL_MAXLEN)) < 0) + return err; + + rep_set = (wl_rm_rep_t *)buf; + rep_set->token = dtoh32(rep_set->token); + rep_set->len = dtoh32(rep_set->len); + + printf("Measurement Report: token %d, length %d\n", rep_set->token, rep_set->len); + + len = rep_set->len; + data = (uint8*)rep_set->rep; + for (; len > 0; (len -= rep.len), (data += rep.len)) { + if (len >= WL_RM_REP_ELT_FIXED_LEN) + memcpy(&rep, data, WL_RM_REP_ELT_FIXED_LEN); + else + break; + + rep.chanspec = wl_chspec_from_driver(rep.chanspec); + rep.token = dtoh32(rep.token); + rep.tsf_h = dtoh32(rep.tsf_h); + rep.tsf_l = dtoh32(rep.tsf_l); + rep.dur = dtoh32(rep.dur); + rep.len = dtoh32(rep.len); + + data += WL_RM_REP_ELT_FIXED_LEN; + len -= WL_RM_REP_ELT_FIXED_LEN; + + if (rep.type == WL_RM_TYPE_BASIC) + name = "Basic"; + else if (rep.type == WL_RM_TYPE_CCA) + name = "CCA"; + else if (rep.type == WL_RM_TYPE_RPI) + name = "RPI"; + else + name = NULL; + + if (name) + printf("\nReport : %s\n", name); + else + printf("\nReport : %d <unknown>\n", rep.type); + + p = extra; + if (rep.flags & WL_RM_FLAG_PARALLEL) { + if (p != extra) + p += sprintf(p, " | "); + p += sprintf(p, "Parallel"); + } + if (rep.flags & WL_RM_FLAG_LATE) { + if (p != extra) + p += sprintf(p, " | "); + p += sprintf(p, "Late"); + } + if (rep.flags & WL_RM_FLAG_INCAPABLE) { + if (p != extra) + p += sprintf(p, " | "); + p += sprintf(p, "Incapable"); + } + if (rep.flags & WL_RM_FLAG_REFUSED) { + if (p != extra) + p += sprintf(p, " | "); + p += sprintf(p, "Refused"); + } + + if (p != extra) { + printf("flags : 0x%02x (%s)\n", rep.flags, extra); + } else { + printf("flags : 0x%02x\n", rep.flags); + } + printf("token : %4d\n", rep.token); + + if (rep.flags & (WL_RM_FLAG_LATE | + WL_RM_FLAG_INCAPABLE | + WL_RM_FLAG_REFUSED)) { + continue; + } + + channel = CHSPEC_CHANNEL(rep.chanspec); + aband = CHSPEC_IS5G(rep.chanspec); + + printf("channel : %4d %s\n", channel, + aband ? "(a)":"(b)"); + printf("start tsf: 0x%x:%08x\n", rep.tsf_h, rep.tsf_l); + printf("duration : %4d TU\n", rep.dur); + + if (len < (int)rep.len) { + printf("Error: partial report element, %d report bytes " + "remain, element claims %d\n", + len, rep.len); + break; + } + + if (rep.type == WL_RM_TYPE_BASIC) { + if (rep.len >= 4) { + memcpy(&val, data, sizeof(uint32)); + val = dtoh32(val); + printf("Basic bits: 0x%08x\n", val); + } + } else if (rep.type == WL_RM_TYPE_CCA) { + if (rep.len >= 4) { + memcpy(&val, data, sizeof(uint32)); + val = dtoh32(val); + printf("Carrier Fraction: %d / 255\n", val); + } + } else if (rep.type == WL_RM_TYPE_RPI) { + if (rep.len >= sizeof(wl_rm_rpi_rep_t)) { + wl_rm_rpi_rep_t rpi_rep; + int8 min = -128; + int8 max; + + memcpy(&rpi_rep, data, sizeof(wl_rm_rpi_rep_t)); + + for (bin = 0; bin < 8; bin++) { + max = rpi_rep.rpi_max[bin]; + if (bin == 0) + printf(" Power <= %3d: ", + max); + else if (bin < 7) + printf(" %3d < Power <= %3d: ", + min, max); + else + printf(" %3d < Power : ", + min); + min = max; + printf("%3d\n", rpi_rep.rpi[bin]); + } + } + } + } + + return err; +} + +static int +wl_join_pref(void *wl, cmd_t *cmd, char **argv) +{ + char* data; + int err; + int len; + int remaining_bytes; + int i; + bcm_tlv_t *ie; + + UNUSED_PARAMETER(cmd); + + strcpy(buf, "join_pref"); + + /* set */ + if (argv[1]) { + len = strlen(buf); + data = argv[1]; + for (i = len + 1, len += 1 + strlen(data) / 2; + (i < len) && (i < (int)WLC_IOCTL_MAXLEN); i ++) { + char hex[] = "XX"; + hex[0] = *data++; + hex[1] = *data++; + buf[i] = (uint8)strtoul(hex, NULL, 16); + } + err = wlu_set(wl, WLC_SET_VAR, buf, i); + } + /* get */ + else if (!(err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MAXLEN))) { + len = dtoh32(*(int *)buf); + data = buf + sizeof(int); + for (i = 0; i < len; i ++) + printf("%02x", (uint8)(data[i])); + printf("\n"); + /* pretty print the join pref elements */ + remaining_bytes = len; + ie = (bcm_tlv_t*)data; + if (!bcm_valid_tlv(ie, remaining_bytes)) + ie = NULL; + while (ie) { + wl_join_pref_print_ie(ie); + ie = bcm_next_tlv(ie, &remaining_bytes); + } + } + return err; +} + +static void +wl_join_pref_print_ie(bcm_tlv_t *ie) +{ + int i; + uint8 band; + uint8 count; + int suite_len; + uint8 *suite; + int data_bytes; + + + switch (ie->id) { + case WL_JOIN_PREF_RSSI: + printf("Pref RSSI\n"); + if (ie->len > 2) + printf("\t<%d extra bytes in pref data>\n", ie->len); + break; + case WL_JOIN_PREF_BAND: + printf("Pref BAND: "); + if (ie->len < 2) { + printf("len = %d <band pref data truncated>\n", ie->len); + break; + } + + band = ie->data[1]; + if (band == WLC_BAND_AUTO) + printf("0x%x AUTO (no preference)\n", band); + else if (band == WLC_BAND_5G) + printf("0x%x 5 GHz\n", band); + else if (band == WLC_BAND_2G) + printf("0x%x 2.4 GHz\n", band); + else if (band == WLJP_BAND_ASSOC_PREF) + printf("0x%x Use ASSOC_PREFER value\n", band); + else + printf("0x%x\n", band); + + if (ie->len > 2) + printf("\t<%d extra bytes in pref data>\n", ie->len - 1); + + break; + case WL_JOIN_PREF_WPA: + printf("Pref WPA: "); + if (ie->len < 2) { + printf("len = %d <WPA pref data truncated>\n", ie->len); + break; + } + count = ie->data[1]; + printf("%d ACP Specs\n", count); + + data_bytes = ie->len - 2; + suite_len = 4; /* WPA Suite Selector length, OUI + type */ + suite = ie->data + 2; + + for (i = 0; i < (int)count; i++) { + if (data_bytes < 3 * suite_len) + break; + printf("\t"); + /* AKM Suite */ + wl_join_pref_print_akm(suite); + printf(","); + + suite = suite + suite_len; + /* Unicast Cipher Suite */ + printf("U:"); + wl_join_pref_print_cipher_suite(suite); + printf(","); + + suite = suite + suite_len; + /* Multicast Cipher Suite */ + printf("M:"); + if (!memcmp(suite, WL_WPA_ACP_MCS_ANY, suite_len)) + printf("Any"); + else + wl_join_pref_print_cipher_suite(suite); + printf("\n"); + + suite = suite + suite_len; + data_bytes -= 3 * suite_len; + } + + if (i != count) + printf("\t<expected %d more specs, %d bytes>\n", + count - i, suite_len * (count - i)); + if (data_bytes > 0) + printf("\t<%d extra bytes>\n", data_bytes); + break; + case WL_JOIN_PREF_RSSI_DELTA: + printf("RSSI Delta for Pref BAND: "); + if (ie->len < 2) { + printf("len = %d <rssi delta pref data truncated>\n", ie->len); + break; + } + + band = ie->data[1]; + if (band == WLC_BAND_AUTO) + printf("0x%x AUTO (no preference)\n", band); + else if (band == WLC_BAND_5G) + printf("0x%x 5 GHz\n", band); + else if (band == WLC_BAND_2G) + printf("0x%x 2.4 GHz\n", band); + else + printf("0x%x\n", band); + + printf("RSSI boost %ddb\n", ie->data[0]); + + break; + default: + printf("Pref 0x%x: len = %d\n", ie->id, ie->len); + for (i = 0; i < ie->len; i++) + printf("%02x", ie->data[i]); + printf("\n"); + break; + + } + +} + +static void +wl_join_pref_print_akm(uint8* suite) +{ + uint8 type = suite[3]; + const char *oui_name; + + if (!memcmp(suite, WPA_OUI, 3)) + oui_name = "WPA"; + else if (!memcmp(suite, WPA2_OUI, 3)) + oui_name = "WPA2"; + else + oui_name = NULL; + + if (oui_name) { + if (type == RSN_AKM_NONE) + printf("%s-NONE", oui_name); + else if (type == RSN_AKM_UNSPECIFIED) + printf("%s", oui_name); + else if (type == RSN_AKM_UNSPECIFIED) + printf("%s-PSK", oui_name); + else + printf("%s/0x%x", oui_name, type); + } else { + printf("0x%02x%02x%02x/0x%02x", suite[0], suite[1], suite[2], suite[3]); + } +} + +static void +wl_join_pref_print_cipher_suite(uint8* suite) +{ + uint8 type = suite[3]; + const char *oui_name; + + if (!memcmp(suite, WPA_OUI, 3)) + oui_name = "WPA"; + else if (!memcmp(suite, WPA2_OUI, 3)) + oui_name = "WPA2"; + else + oui_name = NULL; + + if (oui_name) { + if (type == WPA_CIPHER_NONE) + printf("%s/NONE", oui_name); + else if (type == WPA_CIPHER_WEP_40) + printf("%s/WEP40", oui_name); + else if (type == WPA_CIPHER_TKIP) + printf("%s/TKIP", oui_name); + else if (type == WPA_CIPHER_AES_CCM) + printf("%s/AES", oui_name); + else if (type == WPA_CIPHER_WEP_104) + printf("%s/WEP104", oui_name); + else + printf("%s/0x%x", oui_name, type); + } else { + printf("0x%02x%02x%02x/0x%02x", suite[0], suite[1], suite[2], suite[3]); + } +} + +static int +wl_assoc_pref(void *wl, cmd_t *cmd, char **argv) +{ + uint assoc_pref; + int err; + + /* set */ + if (argv[1]) { + if (!strcmp(argv[1], "auto") || !strcmp(argv[1], "0")) + assoc_pref = WLC_BAND_AUTO; + else if (!strcmp(argv[1], "a") || !strcmp(argv[1], "1")) + assoc_pref = WLC_BAND_5G; + else if (!strcmp(argv[1], "b") || !strcmp(argv[1], "g") || !strcmp(argv[1], "2")) + assoc_pref = WLC_BAND_2G; + else + return BCME_USAGE_ERROR; + assoc_pref = htod32(assoc_pref); + err = wlu_set(wl, cmd->set, &assoc_pref, sizeof(assoc_pref)); + } + /* get */ + else if (!(err = wlu_get(wl, cmd->get, &assoc_pref, sizeof(assoc_pref)))) { + assoc_pref = dtoh32(assoc_pref); + switch (assoc_pref) { + case WLC_BAND_AUTO: + printf("auto\n"); + break; + case WLC_BAND_5G: + printf("a\n"); + break; + case WLC_BAND_2G: + printf("b/g\n"); + break; + } + } + return err; +} + +static const char ac_names[AC_COUNT][6] = {"AC_BE", "AC_BK", "AC_VI", "AC_VO"}; + +/* + * Get or set WME per-AC transmit parameters + */ +static int +wme_tx_params(void *wl, cmd_t *cmd, char **argv) +{ + char *val_p, *ac_str, *param; + int buflen; + int aci; + wme_tx_params_t cur_params[AC_COUNT], new_params[AC_COUNT]; + int err; + int val; + + UNUSED_PARAMETER(cmd); + + argv++; + + buflen = WLC_IOCTL_MAXLEN; + + /* + * Get current acparams, using buf as an input buffer. + * Return data is array of 4 ACs of wme params. + */ + + strcpy(buf, "wme_tx_params"); + if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen)) < 0) { + return err; + } + memcpy(&cur_params, buf, WL_WME_TX_PARAMS_IO_BYTES); + + if ((ac_str = *argv++) == NULL) { + printf("WME TX params: \n"); + for (aci = 0; aci < AC_COUNT; aci++) { + printf("%s: short %d. sfb %d. long %d. lfb %d. max %d\n", ac_names[aci], + cur_params[aci].short_retry, + cur_params[aci].short_fallback, + cur_params[aci].long_retry, + cur_params[aci].long_fallback, + cur_params[aci].max_rate); + } + } else { + int chk_lim; + if (strcmp(ac_str, "be") == 0) { + aci = AC_BE; + } else if (strcmp(ac_str, "bk") == 0) { + aci = AC_BK; + } else if (strcmp(ac_str, "vi") == 0) { + aci = AC_VI; + } else if (strcmp(ac_str, "vo") == 0) { + aci = AC_VO; + } else { + printf("Unknown access class: %s\n", ac_str); + return BCME_USAGE_ERROR; + } + + /* Preload new values with current values */ + memcpy(&new_params, &cur_params, sizeof(new_params)); + while ((param = *argv++) != NULL) { + if ((val_p = *argv++) == NULL) { + printf("Need value following %s\n", param); + return BCME_USAGE_ERROR; + } + chk_lim = 15; + val = (int)strtoul(val_p, NULL, 0); + /* All values must fit in uint8 */ + if (!strcmp(param, "short")) { + new_params[aci].short_retry = (uint8)val; + } else if (!strcmp(param, "sfb")) { + new_params[aci].short_fallback = (uint8)val; + } else if (!strcmp(param, "long")) { + new_params[aci].long_retry = (uint8)val; + } else if (!strcmp(param, "lfb")) { + new_params[aci].long_fallback = (uint8)val; + } else if ((!strcmp(param, "max_rate")) || (!strcmp(param, "max")) || + (!strcmp(param, "rate"))) { + chk_lim = 255; + new_params[aci].max_rate = (uint8)val; + } else { + printf("Unknown parameter: %s\n", param); + return BCME_USAGE_ERROR; + } + if (val > chk_lim) { + printf("Value for %s must be < %d\n", param, chk_lim + 1); + return BCME_USAGE_ERROR; + } + } + strcpy(buf, "wme_tx_params"); + memcpy(buf + strlen(buf) + 1, new_params, WL_WME_TX_PARAMS_IO_BYTES); + err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen); + } + + return err; +} + +/* + * Get or Set WME Access Class (AC) parameters + * wl wme_ac ap|sta [be|bk|vi|vo [ecwmax|ecwmin|txop|aifsn|acm <value>] ...] + * Without args past ap|sta, print current values + */ +static int +wl_wme_ac_req(void *wl, cmd_t *cmd, char **argv) +{ + const char *iovar_name; + int err; + edcf_acparam_t acparam_cur[AC_COUNT], acparam_new[AC_COUNT], *acp; + char *ac_str, *param, *val; + bool acm; + int aci, aifsn, ecwmin, ecwmax, txop; + + UNUSED_PARAMETER(cmd); + + argv++; + + if ((param = *argv++) == NULL) + return BCME_USAGE_ERROR; + + if (!strcmp(param, "ap")) + iovar_name = "wme_ac_ap"; + else if (!strcmp(param, "sta")) + iovar_name = "wme_ac_sta"; + else + return BCME_USAGE_ERROR; + + /* + * Get current acparams into an array of 4 ACs of wme params. + */ + err = wlu_iovar_get(wl, iovar_name, &acparam_cur, sizeof(acparam_cur)); + if (err < 0) + return err; + + if ((ac_str = *argv++) == NULL) { + printf("AC Parameters\n"); + + for (aci = 0; aci < AC_COUNT; aci++) { + acp = &acparam_cur[aci]; + acp->TXOP = dtoh16(acp->TXOP); + if (((acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT) != aci) + printf("Warning: AC params out of order\n"); + acm = (acp->ACI & EDCF_ACM_MASK) ? 1 : 0; + aifsn = acp->ACI & EDCF_AIFSN_MASK; + ecwmin = acp->ECW & EDCF_ECWMIN_MASK; + ecwmax = (acp->ECW & EDCF_ECWMAX_MASK) >> EDCF_ECWMAX_SHIFT; + txop = acp->TXOP; + printf("%s: raw: ACI 0x%x ECW 0x%x TXOP 0x%x\n", + ac_names[aci], + acp->ACI, acp->ECW, acp->TXOP); + printf(" dec: aci %d acm %d aifsn %d " + "ecwmin %d ecwmax %d txop 0x%x\n", + aci, acm, aifsn, ecwmin, ecwmax, txop); + /* CWmin = 2^(ECWmin) - 1 */ + /* CWmax = 2^(ECWmax) - 1 */ + /* TXOP = number of 32 us units */ + printf(" eff: CWmin %d CWmax %d TXop %dusec\n", + EDCF_ECW2CW(ecwmin), EDCF_ECW2CW(ecwmax), EDCF_TXOP2USEC(txop)); + } + + err = 0; + } else { + if (strcmp(ac_str, "be") == 0) + aci = AC_BE; + else if (strcmp(ac_str, "bk") == 0) + aci = AC_BK; + else if (strcmp(ac_str, "vi") == 0) + aci = AC_VI; + else if (strcmp(ac_str, "vo") == 0) + aci = AC_VO; + else + return BCME_USAGE_ERROR; + + /* Preload new values with current values */ + memcpy(&acparam_new, &acparam_cur, sizeof(acparam_new)); + + acp = &acparam_new[aci]; + + while ((param = *argv++) != NULL) { + if ((val = *argv++) == NULL) + return BCME_USAGE_ERROR; + + if (!strcmp(param, "acm")) { + if (!stricmp(val, "on") || !stricmp(val, "1")) + acp->ACI |= EDCF_ACM_MASK; + else if (!stricmp(val, "off") || !stricmp(val, "0")) + acp->ACI &= ~EDCF_ACM_MASK; + else { + fprintf(stderr, "acm value must be 1|0\n"); + return BCME_USAGE_ERROR; + } + } else if (!strcmp(param, "aifsn")) { + aifsn = (int)strtol(val, NULL, 0); + if (aifsn >= EDCF_AIFSN_MIN && aifsn <= EDCF_AIFSN_MAX) + acp->ACI = + (acp->ACI & ~EDCF_AIFSN_MASK) | + (aifsn & EDCF_AIFSN_MASK); + else { + fprintf(stderr, "aifsn %d out of range (%d-%d)\n", + aifsn, EDCF_AIFSN_MIN, EDCF_AIFSN_MAX); + return BCME_USAGE_ERROR; + } + } else if (!strcmp(param, "ecwmax")) { + ecwmax = (int)strtol(val, NULL, 0); + if (ecwmax >= EDCF_ECW_MIN && ecwmax <= EDCF_ECW_MAX) + acp->ECW = + ((ecwmax << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK) | + (acp->ECW & EDCF_ECWMIN_MASK); + else { + fprintf(stderr, "ecwmax %d out of range (%d-%d)\n", + ecwmax, EDCF_ECW_MIN, EDCF_ECW_MAX); + return BCME_USAGE_ERROR; + } + } else if (!strcmp(param, "ecwmin")) { + ecwmin = (int)strtol(val, NULL, 0); + if (ecwmin >= EDCF_ECW_MIN && ecwmin <= EDCF_ECW_MAX) + acp->ECW = + ((acp->ECW & EDCF_ECWMAX_MASK) | + (ecwmin & EDCF_ECWMIN_MASK)); + else { + fprintf(stderr, "ecwmin %d out of range (%d-%d)\n", + ecwmin, EDCF_ECW_MIN, EDCF_ECW_MAX); + return BCME_USAGE_ERROR; + } + } else if (!strcmp(param, "txop")) { + txop = (int)strtol(val, NULL, 0); + if (txop >= EDCF_TXOP_MIN && txop <= EDCF_TXOP_MAX) + acp->TXOP = htod16(txop); + else { + fprintf(stderr, "txop %d out of range (%d-%d)\n", + txop, EDCF_TXOP_MIN, EDCF_TXOP_MAX); + return BCME_USAGE_ERROR; + } + } else { + fprintf(stderr, "unexpected param %s\n", param); + return BCME_USAGE_ERROR; + } + } + + /* + * Now set the new acparams + * NOTE: only one of the four ACs can be set at a time. + */ + err = wlu_iovar_set(wl, iovar_name, acp, sizeof(edcf_acparam_t)); + } + + return err; +} + +/* + * Get or Set WME APSD control parameters + * wl wme_apsd_sta <max_sp_len> <be> <bk> <vi> <vo> + * <max_sp_len> is 0 (all), 2, 4, or 6 + * <be>, <bk>, <vi>, <vo> are each 0 or 1 for APSD enable + * with no args, print current values + */ +static int +wl_wme_apsd_sta(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int buflen; + char *param; + int ap_mode; + int qosinfo; + int msp, max_sp_len, be, bk, vi, vo; + + if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))) < 0) + return err; + + if (ap_mode) { + printf("%s: STA only\n", cmd->name); + return -1; + } + + /* Display current params if no args, else set params */ + + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(buf, "wme_qosinfo"); + buflen = WLC_IOCTL_MAXLEN; + + param = *++argv; + + if (param == NULL) { + if ((err = wlu_get(wl, cmd->get, &buf[0], buflen)) < 0) + return err; + + memcpy(&qosinfo, buf, sizeof(qosinfo)); + qosinfo = dtoh32(qosinfo); + + msp = (qosinfo & WME_QI_STA_MAXSPLEN_MASK) >> WME_QI_STA_MAXSPLEN_SHIFT; + be = (qosinfo & WME_QI_STA_APSD_BE_MASK) >> WME_QI_STA_APSD_BE_SHIFT; + bk = (qosinfo & WME_QI_STA_APSD_BK_MASK) >> WME_QI_STA_APSD_BK_SHIFT; + vi = (qosinfo & WME_QI_STA_APSD_VI_MASK) >> WME_QI_STA_APSD_VI_SHIFT; + vo = (qosinfo & WME_QI_STA_APSD_VO_MASK) >> WME_QI_STA_APSD_VO_SHIFT; + + max_sp_len = msp * 2; + + printf("Max SP Length = %d, APSD: BE=%d BK=%d VI=%d VO=%d\n", + max_sp_len, be, bk, vi, vo); + } else { + max_sp_len = (int)strtol(param, 0, 0); + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + be = (int)strtol(param, 0, 0); + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + bk = (int)strtol(param, 0, 0); + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + vi = (int)strtol(param, 0, 0); + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + vo = (int)strtol(param, 0, 0); + + if (((be | bk | vi | vo) & ~1) | (max_sp_len & ~6)) { + printf("%s: Invalid parameter\n", cmd->name); + return BCME_BADARG; + } + + msp = max_sp_len / 2; + + qosinfo = (msp << WME_QI_STA_MAXSPLEN_SHIFT) & WME_QI_STA_MAXSPLEN_MASK; + qosinfo |= (be << WME_QI_STA_APSD_BE_SHIFT) & WME_QI_STA_APSD_BE_MASK; + qosinfo |= (bk << WME_QI_STA_APSD_BK_SHIFT) & WME_QI_STA_APSD_BK_MASK; + qosinfo |= (vi << WME_QI_STA_APSD_VI_SHIFT) & WME_QI_STA_APSD_VI_MASK; + qosinfo |= (vo << WME_QI_STA_APSD_VO_SHIFT) & WME_QI_STA_APSD_VO_MASK; + + qosinfo = htod32(qosinfo); + memcpy(&buf[strlen(buf) + 1], &qosinfo, sizeof(qosinfo)); + + err = wlu_set(wl, cmd->set, &buf[0], buflen); + } + + return err; +} + +/* + * Get or Set WME discard policy + * wl wme_dp <be> <bk> <vi> <vo> + * <be>, <bk>, <vi>, <vo> are each 0/1 for discard newest/oldest first + * with no args, print current values + */ +static int +wl_wme_dp(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int buflen; + char *param; + int dp; + int be, bk, vi, vo; + + /* Display current params if no args, else set params */ + + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(buf, "wme_dp"); + buflen = WLC_IOCTL_MAXLEN; + + param = *++argv; + + if (param == NULL) { + if ((err = wlu_get(wl, cmd->get, &buf[0], buflen)) < 0) + return err; + + memcpy(&dp, buf, sizeof(dp)); + dp = dtoh32(dp); + + be = (dp >> AC_BE) & 1; + bk = (dp >> AC_BK) & 1; + vi = (dp >> AC_VI) & 1; + vo = (dp >> AC_VO) & 1; + + printf("Discard oldest first: BE=%d BK=%d VI=%d VO=%d\n", be, bk, vi, vo); + } else { + be = (int)strtol(param, 0, 0); + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + bk = (int)strtol(param, 0, 0); + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + vi = (int)strtol(param, 0, 0); + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + vo = (int)strtol(param, 0, 0); + + if ((be | bk | vi | vo) & ~1) { + printf("%s: Invalid parameter\n", cmd->name); + return BCME_BADARG; + } + + dp = (be << AC_BE) | (bk << AC_BK) | (vi << AC_VI) | (vo << AC_VO); + + dp = htod32(dp); + memcpy(&buf[strlen(buf) + 1], &dp, sizeof(dp)); + + err = wlu_set(wl, cmd->set, &buf[0], buflen); + } + + return err; +} + +/* + * Get or Set WME lifetime parameter + * "wl lifetime be|bk|vi|vo [<value>]"}, + * with no args, print current values + */ +static int +wl_lifetime(void *wl, cmd_t *cmd, char **argv) +{ + int err; + uint8 ac; + char *param, *val; + const char *cmdname = "lifetime"; + wl_lifetime_t lifetime, *reply; + void *ptr = NULL; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + if (strcmp(param, "be") == 0) + ac = AC_BE; + else if (strcmp(param, "bk") == 0) + ac = AC_BK; + else if (strcmp(param, "vi") == 0) + ac = AC_VI; + else if (strcmp(param, "vo") == 0) + ac = AC_VO; + else { + fprintf(stderr, "unexpected param %s\n", param); + return BCME_USAGE_ERROR; + } + + if ((val = *++argv) == NULL) { + lifetime.ac = htod32(ac); + if ((err = wlu_var_getbuf(wl, cmdname, &lifetime, sizeof(lifetime), + &ptr)) < 0) + return err; + reply = (wl_lifetime_t *) ptr; + reply->ac = dtoh32(reply->ac); + reply->lifetime = dtoh32(reply->lifetime); + printf("Lifetime for access class '%s' is %dms\n", param, reply->lifetime); + } + else { + lifetime.ac = htod32(ac); + lifetime.lifetime = htod32((uint)strtol(val, 0, 0)); + err = wlu_var_setbuf(wl, cmdname, &lifetime, sizeof(lifetime)); + } + + return err; +} + +#define VNDR_IE_OK_FLAGS \ + (VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | VNDR_IE_ASSOCRSP_FLAG | \ + VNDR_IE_AUTHRSP_FLAG | VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG | \ + VNDR_IE_IWAPID_FLAG) + +static int +wl_add_ie(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(cmd); + + return (wl_vndr_ie(wl, "add", VNDR_IE_OK_FLAGS, argv)); +} + +static int +wl_del_ie(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(cmd); + + return (wl_vndr_ie(wl, "del", VNDR_IE_OK_FLAGS, argv)); +} + +int +wl_mk_ie_setbuf(const char *command, uint32 pktflag_ok, char **argv, + vndr_ie_setbuf_t **buf, int *buf_len) +{ + vndr_ie_setbuf_t *ie_setbuf; + uint32 pktflag; + int ielen, datalen, buflen, iecount; + int err = 0; + + if (!argv[1] || !argv[2] || !argv[3]) { + fprintf(stderr, "Too few arguments\n"); + return BCME_USAGE_ERROR; + } + + pktflag = (uint)strtol(argv[1], 0, 0); + + if (pktflag & ~pktflag_ok) { + fprintf(stderr, "Invalid packet flag 0x%x (%d)\n", pktflag, pktflag); + return BCME_BADARG; + } + + ielen = atoi(argv[2]); + if (ielen > VNDR_IE_MAX_LEN) { + fprintf(stderr, "IE length is %d, should be <= %d\n", ielen, VNDR_IE_MAX_LEN); + return BCME_BADARG; + } + else if (ielen < VNDR_IE_MIN_LEN) { + fprintf(stderr, "IE length is %d, should be >= %d\n", ielen, VNDR_IE_MIN_LEN); + return BCME_BADARG; + } + + if (strlen(argv[3]) != OUI_STR_SIZE) { + fprintf(stderr, "Invalid OUI length %d\n", (int)strlen(argv[3])); + return BCME_BADARG; + } + + datalen = ielen - VNDR_IE_MIN_LEN; + if (datalen > 0) { + if (!argv[4]) { + fprintf(stderr, "Data bytes should be specified for IE of length %d\n", + ielen); + return BCME_USAGE_ERROR; + } + else { + /* Ensure each data byte is 2 characters long */ + if ((int)strlen (argv[4]) < (datalen * 2)) { + fprintf(stderr, "Please specify all the data bytes for this IE\n"); + return BCME_USAGE_ERROR; + } + } + } + + if (datalen == 0 && (argv[4] != NULL)) + fprintf(stderr, "Ignoring data bytes for IE of length %d", ielen); + + buflen = sizeof(vndr_ie_setbuf_t) + datalen - 1; + + ie_setbuf = (vndr_ie_setbuf_t *) malloc(buflen); + + if (ie_setbuf == NULL) { + fprintf(stderr, "memory alloc failure\n"); + return BCME_NOMEM; + } + + /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ + strncpy(ie_setbuf->cmd, command, VNDR_IE_CMD_LEN - 1); + ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + + /* Buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int)); + + /* + * The packet flag bit field indicates the packets that will + * contain this IE + */ + pktflag = htod32(pktflag); + memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag, + &pktflag, sizeof(uint32)); + + /* Now, add the IE to the buffer */ + ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID; + ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen; + + if ((err = get_oui_bytes ((uchar *)argv[3], + &ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0]))) { + free(ie_setbuf); + fprintf(stderr, "Error parsing OUI arg\n"); + return BCME_BADARG; + } + + if (datalen > 0) { + if ((err = get_ie_data ((uchar *)argv[4], + &ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0], + datalen))) { + free(ie_setbuf); + fprintf(stderr, "Error parsing data arg\n"); + return BCME_BADARG; + } + } + + /* Copy-out */ + if (buf) { + *buf = ie_setbuf; + ie_setbuf = NULL; + } + if (buf_len) + *buf_len = buflen; + + /* Clean-up */ + if (ie_setbuf) + free(ie_setbuf); + + return (err); +} + +static int +wl_vndr_ie(void *wl, const char *command, uint32 pktflag_ok, char **argv) +{ + vndr_ie_setbuf_t *ie_setbuf; + int buflen; + int err = 0; + int ret; + int bsscfg_idx = 0; + int consumed = 0; + + /* parse a bsscfg_idx option if present */ + if ((ret = wl_cfg_option(argv + 1, argv[0], &bsscfg_idx, &consumed)) != 0) + return ret; + if (consumed) + argv = argv + consumed; + else + bsscfg_idx = -1; + + if ((err = wl_mk_ie_setbuf(command, pktflag_ok, argv, &ie_setbuf, &buflen)) != 0) + return err; + + if (bsscfg_idx == -1) + err = wlu_var_setbuf(wl, "ie", ie_setbuf, buflen); + else + err = wlu_bssiovar_setbuf(wl, "ie", bsscfg_idx, + ie_setbuf, buflen, buf, WLC_IOCTL_MAXLEN); + + free(ie_setbuf); + + return (err); +} + +int +wl_list_ie(void *wl, cmd_t *cmd, char **argv) +{ + int err; + void *ptr; + ie_getbuf_t param; + + BCM_REFERENCE(argv); + + param.pktflag = (uint32) -1; + param.id = (uint8) DOT11_MNG_PROPR_ID; + err = wlu_var_getbuf(wl, cmd->name, ¶m, sizeof(param), &ptr); + if (err == 0) { + wl_dump_ie_buf((vndr_ie_buf_t *)ptr); + } else { + fprintf(stderr, "Error %d getting IOVar\n", err); + } + + return err; +} + +static int +_wl_list_ie(void *wl, cmd_t *cmd, char **argv) +{ + int err; + const char *old = cmd->name; + + cmd->name = "ie"; + err = wl_list_ie(wl, cmd, argv); + cmd->name = old; + + return err; +} + +static void +wl_dump_ie_buf(vndr_ie_buf_t *ie_getbuf) +{ + uchar *iebuf; + uchar *data; + int tot_ie, pktflag, iecount, count, datalen, col; + vndr_ie_info_t *ie_info; + vndr_ie_t *ie; + + memcpy(&tot_ie, (void *)&ie_getbuf->iecount, sizeof(int)); + tot_ie = dtoh32(tot_ie); + printf("Total IEs %d\n", tot_ie); + + iebuf = (uchar *)&ie_getbuf->vndr_ie_list[0]; + + for (iecount = 0; iecount < tot_ie; iecount++) { + ie_info = (vndr_ie_info_t *) iebuf; + memcpy(&pktflag, (void *)&ie_info->pktflag, sizeof(uint32)); + pktflag = dtoh32(pktflag); + iebuf += sizeof(uint32); + + printf("\n"); + + ie = &ie_info->vndr_ie_data; + printf("IE index = %d\n", iecount); + printf("-----------------\n"); + printf("Pkt Flg = 0x%x\n", pktflag); + printf("Length = %d\n", ie->len); + printf("OUI = %02x:%02x:%02x\n", + ie->oui[0], ie->oui[1], ie->oui[2]); + printf("Data:\n"); + + data = &ie->data[0]; + datalen = ie->len - VNDR_IE_MIN_LEN; + for (count = 0; (count < datalen);) { + for (col = 0; (col < MAX_DATA_COLS) && + (count < datalen); col++, count++) { + printf("%02x ", *data++); + } + printf("\n"); + } + + iebuf += ie->len + VNDR_IE_HDR_LEN; + } +} + +static int +wl_rand(void *wl, cmd_t *cmd, char **argv) +{ + char *randbuf; + uint16 randnum; + int err; + void *ptr; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf (wl, cmd->name, NULL, 0, &ptr))) + return (err); + + randbuf = (char *)ptr; + memcpy(&randnum, randbuf, sizeof(uint16)); + printf("%d\n", randnum); + + return (0); +} + +#define PRVAL(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh32(cnt->name)) +#define PRVALSIX(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh32(cnt_six->name)) +#define PRNL() pbuf += sprintf(pbuf, "\n") + +#define WL_CNT_VERSION_SIX 6 +static int +wl_counters(void *wl, cmd_t *cmd, char **argv) +{ + char *statsbuf; + wl_cnt_t *cnt; + wl_cnt_ver_six_t *cnt_six; + int err; + uint i; + char *pbuf = buf; + void *ptr; + uint16 ver; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr))) + return (err); + + statsbuf = (char *)ptr; + + ver = *(uint16*)statsbuf; + + if ((ver > WL_CNT_T_VERSION) && (ver != WL_CNT_T_VERSION_7001)) { + printf("\tIncorrect version of counters struct: expected %d; got %d\n", + WL_CNT_T_VERSION, ver); + return -1; + } + else if (ver == WL_CNT_VERSION_SIX) { + printf("\tUse version 6 counters struct\n"); + } + else { + if ((ver != WL_CNT_T_VERSION) && (ver != WL_CNT_T_VERSION_7001)) { + printf("\tIncorrect version of counters struct: expected %d; got %d\n", + WL_CNT_T_VERSION, ver); + printf("\tDisplayed values may be incorrect\n"); + } + } + + cnt_six = (wl_cnt_ver_six_t*)malloc(sizeof(wl_cnt_ver_six_t)); + if (cnt_six == NULL) { + printf("\tCan not allocate %d bytes for counters six struct\n", + (int)sizeof(wl_cnt_ver_six_t)); + return BCME_NOMEM; + } else + memcpy(cnt_six, statsbuf, sizeof(wl_cnt_ver_six_t)); + + cnt = (wl_cnt_t*)malloc(sizeof(wl_cnt_t)); + if (cnt == NULL) { + if (cnt_six) free(cnt_six); + printf("\tCan not allocate %d bytes for counters struct\n", + (int)sizeof(wl_cnt_t)); + return BCME_NOMEM; + } else + memcpy(cnt, statsbuf, sizeof(wl_cnt_t)); + + /* summary stat counter line */ + PRVAL(txframe); PRVAL(txbyte); PRVAL(txretrans); PRVAL(txerror); + PRVAL(rxframe); PRVAL(rxbyte); PRVAL(rxerror); PRNL(); + + PRVAL(txprshort); PRVAL(txdmawar); PRVAL(txnobuf); PRVAL(txnoassoc); + PRVAL(txchit); PRVAL(txcmiss); PRNL(); + + PRVAL(reset); PRVAL(txserr); PRVAL(txphyerr); PRVAL(txphycrs); + PRVAL(txfail); PRVAL(tbtt); PRNL(); + + pbuf += sprintf(pbuf, "d11_txfrag %u d11_txmulti %u d11_txretry %u d11_txretrie %u\n", + dtoh32(cnt->txfrag), dtoh32(cnt->txmulti), dtoh32(cnt->txretry), + dtoh32(cnt->txretrie)); + + pbuf += sprintf(pbuf, "d11_txrts %u d11_txnocts %u d11_txnoack %u d11_txfrmsnt %u\n", + dtoh32(cnt->txrts), dtoh32(cnt->txnocts), dtoh32(cnt->txnoack), + dtoh32(cnt->txfrmsnt)); + + PRVAL(rxcrc); PRVAL(rxnobuf); PRVAL(rxnondata); PRVAL(rxbadds); + PRVAL(rxbadcm); PRVAL(rxdup); PRVAL(rxfragerr); PRNL(); + + PRVAL(rxrunt); PRVAL(rxgiant); PRVAL(rxnoscb); PRVAL(rxbadproto); + PRVAL(rxbadsrcmac); PRNL(); + + pbuf += sprintf(pbuf, "d11_rxfrag %u d11_rxmulti %u d11_rxundec %u\n", + dtoh32(cnt->rxfrag), dtoh32(cnt->rxmulti), dtoh32(cnt->rxundec)); + + PRVAL(rxctl); PRVAL(rxbadda); PRVAL(rxfilter); PRNL(); + + pbuf += sprintf(pbuf, "rxuflo: "); + for (i = 0; i < NFIFO; i++) + pbuf += sprintf(pbuf, "%u ", dtoh32(cnt->rxuflo[i])); + pbuf += sprintf(pbuf, "\n"); + PRVAL(txallfrm); PRVAL(txrtsfrm); PRVAL(txctsfrm); PRVAL(txackfrm); PRNL(); + PRVAL(txdnlfrm); PRVAL(txbcnfrm); PRVAL(txtplunfl); PRVAL(txphyerr); PRNL(); + pbuf += sprintf(pbuf, "txfunfl: "); + for (i = 0; i < NFIFO; i++) + pbuf += sprintf(pbuf, "%u ", dtoh32(cnt->txfunfl[i])); + pbuf += sprintf(pbuf, "\n"); + + /* WPA2 counters */ + PRNL(); + if ((cnt->version == WL_CNT_VERSION_SIX) && (cnt->version != WL_CNT_T_VERSION)) { + PRVALSIX(tkipmicfaill); PRVALSIX(tkipicverr); PRVALSIX(tkipcntrmsr); PRNL(); + PRVALSIX(tkipreplay); PRVALSIX(ccmpfmterr); PRVALSIX(ccmpreplay); PRNL(); + PRVALSIX(ccmpundec); PRVALSIX(fourwayfail); PRVALSIX(wepundec); PRNL(); + PRVALSIX(wepicverr); PRVALSIX(decsuccess); PRVALSIX(rxundec); PRNL(); + } else { + PRVAL(tkipmicfaill); PRVAL(tkipicverr); PRVAL(tkipcntrmsr); PRNL(); + PRVAL(tkipreplay); PRVAL(ccmpfmterr); PRVAL(ccmpreplay); PRNL(); + PRVAL(ccmpundec); PRVAL(fourwayfail); PRVAL(wepundec); PRNL(); + PRVAL(wepicverr); PRVAL(decsuccess); PRVAL(rxundec); PRNL(); + } + PRNL(); + PRVAL(rxfrmtoolong); PRVAL(rxfrmtooshrt); + PRVAL(rxinvmachdr); PRVAL(rxbadfcs); PRNL(); + PRVAL(rxbadplcp); PRVAL(rxcrsglitch); + PRVAL(rxstrt); PRVAL(rxdfrmucastmbss); PRNL(); + PRVAL(rxmfrmucastmbss); PRVAL(rxcfrmucast); + PRVAL(rxrtsucast); PRVAL(rxctsucast); PRNL(); + PRVAL(rxackucast); PRVAL(rxdfrmocast); + PRVAL(rxmfrmocast); PRVAL(rxcfrmocast); PRNL(); + PRVAL(rxrtsocast); PRVAL(rxctsocast); + PRVAL(rxdfrmmcast); PRVAL(rxmfrmmcast); PRNL(); + PRVAL(rxcfrmmcast); PRVAL(rxbeaconmbss); + PRVAL(rxdfrmucastobss); PRVAL(rxbeaconobss); PRNL(); + PRVAL(rxrsptmout); PRVAL(bcntxcancl); + PRVAL(rxf0ovfl); PRVAL(rxf1ovfl); PRNL(); + PRVAL(rxf2ovfl); PRVAL(txsfovfl); PRVAL(pmqovfl); + if (cnt->version == WL_CNT_T_VERSION_7001) + PRVAL(rxbcnlossmbss); + PRNL(); + PRVAL(rxcgprqfrm); PRVAL(rxcgprsqovfl); + PRVAL(txcgprsfail); PRVAL(txcgprssuc); PRNL(); + PRVAL(prs_timeout); PRVAL(rxnack); PRVAL(frmscons); + PRVAL(txnack); PRVAL(txglitch_nack); PRNL(); + PRVAL(txburst); PRVAL(txphyerror); PRNL(); + + if ((cnt->version == WL_CNT_VERSION_SIX) && (cnt->version != WL_CNT_T_VERSION)) { + PRVALSIX(txchanrej); PRNL(); + /* per-rate receive counters */ + PRVALSIX(rx1mbps); PRVALSIX(rx2mbps); PRVALSIX(rx5mbps5); PRNL(); + PRVALSIX(rx6mbps); PRVALSIX(rx9mbps); PRVALSIX(rx11mbps); PRNL(); + PRVALSIX(rx12mbps); PRVALSIX(rx18mbps); PRVALSIX(rx24mbps); PRNL(); + PRVALSIX(rx36mbps); PRVALSIX(rx48mbps); PRVALSIX(rx54mbps); PRNL(); + + PRVALSIX(pktengrxducast); PRVALSIX(pktengrxdmcast); PRNL(); + + PRVALSIX(txmpdu_sgi); PRVALSIX(rxmpdu_sgi); PRVALSIX(txmpdu_stbc); + PRVALSIX(rxmpdu_stbc); PRNL(); + } else { + PRVAL(txchanrej); PRNL(); + if (cnt->version >= 4) { + /* per-rate receive counters */ + PRVAL(rx1mbps); PRVAL(rx2mbps); PRVAL(rx5mbps5); PRNL(); + PRVAL(rx6mbps); PRVAL(rx9mbps); PRVAL(rx11mbps); PRNL(); + PRVAL(rx12mbps); PRVAL(rx18mbps); PRVAL(rx24mbps); PRNL(); + PRVAL(rx36mbps); PRVAL(rx48mbps); PRVAL(rx54mbps); PRNL(); + } + + if (cnt->version >= 5) { + PRVAL(pktengrxducast); PRVAL(pktengrxdmcast); PRNL(); + } + + if (cnt->version >= 6) { + PRVAL(txmpdu_sgi); PRVAL(rxmpdu_sgi); PRVAL(txmpdu_stbc); + PRVAL(rxmpdu_stbc); PRNL(); + } + } + + pbuf += sprintf(pbuf, "\n"); + fputs(buf, stdout); + + if (cnt) + free(cnt); + + if (cnt_six) + free(cnt_six); + + return (0); +} + +static int +wl_delta_stats(void *wl, cmd_t *cmd, char **argv) +{ + char *statsbuf; + wl_delta_stats_t *cnt; + int err; + char *pbuf = buf; + void *ptr; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr))) + return (err); + + statsbuf = (char *)ptr; + + cnt = (wl_delta_stats_t*)malloc(sizeof(wl_delta_stats_t)); + if (cnt == NULL) { + printf("\tCan not allocate %d bytes for wl delta stats struct\n", + (int)sizeof(wl_delta_stats_t)); + return BCME_NOMEM; + } + memcpy(cnt, statsbuf, sizeof(wl_delta_stats_t)); + cnt->version = dtoh16(cnt->version); + cnt->length = dtoh16(cnt->length); + + if (cnt->version != WL_DELTA_STATS_T_VERSION) { + printf("\tIncorrect version of delta stats struct: expected %d; got %d\n", + WL_DELTA_STATS_T_VERSION, cnt->version); + free(cnt); + return -1; + } + + PRVAL(txframe); PRVAL(txbyte); PRVAL(txretrans); PRVAL(txfail); PRNL(); + + PRVAL(rxframe); PRVAL(rxbyte); PRNL(); + + PRVAL(rx1mbps); PRVAL(rx2mbps); PRVAL(rx5mbps5); PRVAL(rx6mbps); PRNL(); + PRVAL(rx9mbps); PRVAL(rx11mbps); PRVAL(rx12mbps); PRVAL(rx18mbps); PRNL(); + PRVAL(rx24mbps); PRVAL(rx36mbps); PRVAL(rx48mbps); PRVAL(rx54mbps); PRNL(); + pbuf += sprintf(pbuf, "\n"); + + PRVAL(rxbadplcp); PRVAL(rxcrsglitch); PRVAL(bphy_rxcrsglitch); PRVAL(bphy_badplcp); + pbuf += sprintf(pbuf, "\n"); + + fputs(buf, stdout); + + if (cnt != NULL) + free(cnt); + + return (0); +} + +static int +wl_wme_counters(void *wl, cmd_t *cmd, char **argv) +{ + char *statsbuf; + wl_wme_cnt_t cnt; + int err; + void *ptr; + char *pbuf = buf; + uint ac; + int ap_mode = 0; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr))) + return (err); + + statsbuf = (char *)ptr; + memcpy(&cnt, statsbuf, sizeof(cnt)); + cnt.version = dtoh16(cnt.version); + cnt.length = dtoh16(cnt.length); + + if (cnt.version != WL_WME_CNT_VERSION) { + printf("\tIncorrect version of counters struct: expected %d; got %d\n", + WL_WME_CNT_VERSION, cnt.version); + return -1; + } + + if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))) < 0) { + return err; + } + ap_mode = dtoh32(ap_mode); + + /* summary stat counter line */ + for (ac = AC_BE; ac < AC_COUNT; ac++) { + pbuf += sprintf(pbuf, "\n%s: tx frames: %u bytes: %u failed frames: %u " + "failed bytes: %u\n", + ac_names[ac], dtoh32(cnt.tx[ac].packets), dtoh32(cnt.tx[ac].bytes), + dtoh32(cnt.tx_failed[ac].packets), dtoh32(cnt.tx_failed[ac].bytes)); + pbuf += sprintf(pbuf, " rx frames: %u bytes: %u failed frames: %u " + "failed bytes: %u\n", dtoh32(cnt.rx[ac].packets), + dtoh32(cnt.rx[ac].bytes), dtoh32(cnt.rx_failed[ac].packets), + dtoh32(cnt.rx_failed[ac].bytes)); + + if (ap_mode) + pbuf += sprintf(pbuf, " foward frames: %u bytes: %u \n", + dtoh32(cnt.forward[ac].packets), + dtoh32(cnt.forward[ac].bytes)); + + pbuf += sprintf(pbuf, " tx frames time expired: %u \n", + dtoh32(cnt.tx_expired[ac].packets)); + } + pbuf += sprintf(pbuf, "\n"); + fputs(buf, stdout); + return (0); +} + +static int +wl_devpath(void *wl, cmd_t *cmd, char **argv) +{ + int err; + void *ptr; + char *pbuf = buf; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf_sm (wl, cmd->name, NULL, 0, &ptr))) + return (err); + + pbuf += strlen(buf); + sprintf(pbuf, "\n"); + fputs(buf, stdout); + return (0); +} + +static int +wl_diag(void *wl, cmd_t *cmd, char **argv) +{ + uint testindex; + int buflen, err; + char *param; + uint32 testresult; + + if (!*++argv) { + printf(" Usage: %s testindex[1-4]\n", cmd->name); + return BCME_USAGE_ERROR; + } + + testindex = atoi(*argv); + + strcpy(buf, "diag"); + buflen = strlen(buf) + 1; + param = (char *)(buf + buflen); + testindex = htod32(testindex); + memcpy(param, (char*)&testindex, sizeof(testindex)); + + if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return err; + + testresult = *(uint32 *)buf; + testindex = dtoh32(testindex); + testresult = dtoh32(testresult); + if (testresult != 0) { + printf("\ndiag test %d failed(error code %d)\n", testindex, testresult); + } else + printf("\ndiag test %d passed\n", testindex); + + return (0); +} + +static int +wl_phy_rssiant(void *wl, cmd_t *cmd, char **argv) +{ + uint32 antindex; + int buflen, err; + char *param; + int16 antrssi; + + if (!*++argv) { + printf(" Usage: %s antenna_index[0-3]\n", cmd->name); + return BCME_USAGE_ERROR; + } + + antindex = htod32(atoi(*argv)); + + strcpy(buf, "nphy_rssiant"); + buflen = strlen(buf) + 1; + param = (char *)(buf + buflen); + memcpy(param, (char*)&antindex, sizeof(antindex)); + + if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return err; + + antindex = dtoh32(antindex); + antrssi = dtoh16(*(int16 *)buf); + printf("\nnphy_rssiant ant%d = %d\n", antindex, antrssi); + + return (0); +} + +static int +get_oui_bytes(uchar *oui_str, uchar *oui) +{ + int idx; + uchar val; + uchar *src, *dest; + char hexstr[3]; + + src = oui_str; + dest = oui; + + for (idx = 0; idx < MAX_OUI_SIZE; idx++) { + hexstr[0] = src[0]; + hexstr[1] = src[1]; + hexstr[2] = '\0'; + + val = (uchar) strtoul(hexstr, NULL, 16); + + *dest++ = val; + src += 2; + + if ((idx < (MAX_OUI_SIZE - 1)) && (*src++ != ':')) + return -1; + } + + return 0; +} + +static int +get_ie_data(uchar *data_str, uchar *ie_data, int len) +{ + uchar *src, *dest; + uchar val; + int idx; + char hexstr[3]; + + src = data_str; + dest = ie_data; + + for (idx = 0; idx < len; idx++) { + hexstr[0] = src[0]; + hexstr[1] = src[1]; + hexstr[2] = '\0'; + + val = (uchar) strtoul(hexstr, NULL, 16); + + *dest++ = val; + src += 2; + } + + return 0; +} + +static int +hexstrtobitvec(const char *cp, uchar *bitvec, int veclen) +{ + uchar value = 0; + int nibble; /* index of current hex-format nibble to process */ + int even; /* 1 if even number of nibbles, 0 if odd number */ + int i = 0; + + if (cp[0] == '0' && cp[1] == 'x') + cp += 2; + + memset(bitvec, '\0', veclen); + nibble = strlen(cp); + if (!nibble) + return -1; + even = ((nibble % 2) == 0); + + /* convert from right to left (lsb is rightmost byte) */ + --nibble; + while (nibble >= 0 && i < veclen && (isxdigit((int)cp[nibble]) && + (value = isdigit((int)cp[nibble]) ? cp[nibble]-'0' : + (islower((int)cp[nibble]) ? toupper((int)cp[nibble]) : cp[nibble])-'A'+10) < 16)) { + if (even == ((nibble+1) % 2)) { + bitvec[i] += value*16; + ++i; + } else + bitvec[i] = value; + --nibble; + } + + return ((nibble == -1 && i <= veclen) ? 0 : -1); +} + +static int +wl_eventbitvec(void *wl, cmd_t *cmd, char **argv) +{ + char *vbuf; + int err; + uchar bitvec[WL_EVENTING_MASK_LEN]; + bool skipzeros; + int i; + + err = 0; + skipzeros = TRUE; + + /* set */ + if (argv[1]) { + memset(bitvec, '\0', sizeof(bitvec)); + if (!(err = hexstrtobitvec(argv[1], bitvec, sizeof(bitvec)))) + err = wlu_var_setbuf(wl, cmd->name, bitvec, sizeof(bitvec)); + else + return BCME_BADARG; + } + /* get */ + else { + void *ptr; + + memset(buf, '\0', WLC_IOCTL_MAXLEN); + if (!(err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr))) { + vbuf = (char *)ptr; + printf("0x"); + for (i = (sizeof(bitvec) - 1); i >= 0; i--) { + if (vbuf[i] || (i == 0)) + skipzeros = FALSE; + if (skipzeros) + continue; + printf("%02x", vbuf[i] & 0xff); + } + printf("\n"); + } + } + + return (err); +} + +static int +wl_auto_channel_sel(void *wl, cmd_t *cmd, char **argv) +{ + /* + * The following condition(s) must be met when Auto Channel Selection + * is enabled. + * - the I/F is up (change radio channel requires it is up?) + * - the AP must not be associated (setting SSID to empty should + * make sure it for us) + */ + int chosen = 0; + wl_uint32_list_t request; + int ret = 0; + + if (!*++argv) { + ret = wlu_get(wl, cmd->get, &chosen, sizeof(chosen)); + chosen = wl_chspec32_from_driver(chosen); + if (ret >= 0 && chosen != 0) { + wf_chspec_ntoa((chanspec_t)chosen, buf); + printf("%s (0x%x)\n", buf, chosen); + return 0; + } + else { + if (chosen == 0) + printf("invalid chanspec (0x%x)\n", chosen); + } + } else { + if (atoi(*argv) == 1) { + request.count = htod32(0); + ret = wlu_set(wl, cmd->set, &request, sizeof(request)); + } else if (atoi(*argv) == 2) { + ret = wlu_get(wl, cmd->get, &chosen, sizeof(chosen)); + if (ret >= 0 && chosen != 0) + ret = wlu_iovar_setint(wl, "chanspec", (int)chosen); + } else { + ret = BCME_BADARG; + } + } + return ret; +} + +static int +wl_varstr(void *wl, cmd_t *cmd, char **argv) +{ + int error; + char *str; + + if (!*++argv) { + void *ptr; + + if ((error = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return (error); + + str = (char *)ptr; + printf("%s\n", str); + return (0); + } else { + str = *argv; + /* str length include NULL */ + return wlu_var_setbuf(wl, cmd->name, str, (strlen(str)+1)); + } +} + +/* Return TRUE if it's one of the wc cmds. If WC_TOOL is not defined, + * it'll return TRUE by default so all the commands are allowed. + */ +bool wc_cmd_check(const char *cmd_name) +{ + uint j; + if (wc_cmds == NULL) + return TRUE; + + for (j = 0; j < ARRAYSIZE(wc_cmds); j++) + if (strcmp(wc_cmds[j], cmd_name) == 0) + return TRUE; + return FALSE; +} + +#define NUM_TSLIST_ARG 3 /* minimum number of arguments required for TSLIST */ +#define NUM_TSLIST_PER_EA_ARG 3 /* minimum number of arguments required for TSLIST */ +#define MIN_NUM_DELTS_ARG 4 /* minimum number of arguments required for DELTS */ +#define MIN_NUM_DELTS_EA_ARG 5 /* minimum number of arguments required for DELTS */ +#define MIN_NUM_ADDTS_ARG 20 /* minimum number of arguments required for ADDTS */ +#define PERIODIC_TRAFFIC 1 /* Periodic traffic type */ +#define VO_TID (0 << 1) /* voice TID */ +#define VI_TID (1 << 1) /* signal TID */ +#define UPLINK_DIRECTION (0 << 5) /* uplink direction traffic stream */ +#define DOWNLINK_DIRECTION (1 << 5) /* downlink direction traffic stream */ +#define BI_DIRECTION (3 << 5) /* bi direction traffic stream */ +#define EDCA_ACCESS (1 << 7) /* EDCA access policy */ +#define UAPSD_PSB (1 << 2) /* U-APSD power saving behavior */ +#define VO_USER_PRIO (6 << 3) /* voice user priority */ +#define VI_USER_PRIO (4 << 3) /* signal user priority */ +#define TID_SHIFT 1 /* TID Shift */ +#define UP_SHIFT 3 /* UP Shift */ + +static void +wl_cac_format_tspec_htod(tspec_arg_t *tspec_arg) +{ + tspec_arg->version = htod16(tspec_arg->version); + tspec_arg->length = htod16(tspec_arg->length); + tspec_arg->flag = htod32(tspec_arg->flag); + tspec_arg->nom_msdu_size = htod16(tspec_arg->nom_msdu_size); + tspec_arg->max_msdu_size = htod16(tspec_arg->max_msdu_size); + tspec_arg->min_srv_interval = htod32(tspec_arg->min_srv_interval); + tspec_arg->max_srv_interval = htod32(tspec_arg->max_srv_interval); + tspec_arg->inactivity_interval = htod32(tspec_arg->inactivity_interval); + tspec_arg->suspension_interval = htod32(tspec_arg->suspension_interval); + tspec_arg->srv_start_time = htod32(tspec_arg->srv_start_time); + tspec_arg->min_data_rate = htod32(tspec_arg->min_data_rate); + tspec_arg->mean_data_rate = htod32(tspec_arg->mean_data_rate); + tspec_arg->peak_data_rate = htod32(tspec_arg->peak_data_rate); + tspec_arg->max_burst_size = htod32(tspec_arg->max_burst_size); + tspec_arg->delay_bound = htod32(tspec_arg->delay_bound); + tspec_arg->min_phy_rate = htod32(tspec_arg->min_phy_rate); + tspec_arg->surplus_bw = htod16(tspec_arg->surplus_bw); + tspec_arg->medium_time = htod16(tspec_arg->medium_time); +} + +static void +wl_cac_format_tspec_dtoh(tspec_arg_t *tspec_arg) +{ + tspec_arg->version = dtoh16(tspec_arg->version); + tspec_arg->length = dtoh16(tspec_arg->length); + tspec_arg->flag = dtoh32(tspec_arg->flag); + tspec_arg->nom_msdu_size = dtoh16(tspec_arg->nom_msdu_size); + tspec_arg->max_msdu_size = dtoh16(tspec_arg->max_msdu_size); + tspec_arg->min_srv_interval = dtoh32(tspec_arg->min_srv_interval); + tspec_arg->max_srv_interval = dtoh32(tspec_arg->max_srv_interval); + tspec_arg->inactivity_interval = dtoh32(tspec_arg->inactivity_interval); + tspec_arg->suspension_interval = dtoh32(tspec_arg->suspension_interval); + tspec_arg->srv_start_time = dtoh32(tspec_arg->srv_start_time); + tspec_arg->min_data_rate = dtoh32(tspec_arg->min_data_rate); + tspec_arg->mean_data_rate = dtoh32(tspec_arg->mean_data_rate); + tspec_arg->peak_data_rate = dtoh32(tspec_arg->peak_data_rate); + tspec_arg->max_burst_size = dtoh32(tspec_arg->max_burst_size); + tspec_arg->delay_bound = dtoh32(tspec_arg->delay_bound); + tspec_arg->min_phy_rate = dtoh32(tspec_arg->min_phy_rate); + tspec_arg->surplus_bw = dtoh16(tspec_arg->surplus_bw); + tspec_arg->medium_time = dtoh16(tspec_arg->medium_time); + +} + +static void wl_cac_addts_usage(void) +{ + fprintf(stderr, "Too few arguments\n"); + fprintf(stderr, "wl cac_addts ver dtoken tid dir psb up a b c d e ...\n"); + fprintf(stderr, "\twhere ver is the structure version\n"); + fprintf(stderr, "\twhere dtoken is the dialog token [range 1-255]\n"); + fprintf(stderr, "\twhere tid is the tspec identifier [range 0-7]\n"); + fprintf(stderr, "\twhere dir is direction [uplink | downlink | bi-directional]\n"); + fprintf(stderr, "\twhere psb is power save mode [legacy|U-APSD]\n"); + fprintf(stderr, "\twhere up is user priority [range 0-7]\n"); + fprintf(stderr, "\twhere a is the nominal MSDU size\n"); + fprintf(stderr, "\twhere b is bool for fixed size msdu [ 0 and 1]\n"); + fprintf(stderr, "\twhere c is the maximum MSDU size\n"); + fprintf(stderr, "\twhere d is the minimum service interval\n"); + fprintf(stderr, "\twhere e is the maximum service interval\n"); + fprintf(stderr, "\twhere f is the inactivity interval\n"); + fprintf(stderr, "\twhere g is the suspension interval\n"); + fprintf(stderr, "\twhere h is the minimum data rate\n"); + fprintf(stderr, "\twhere i is the mean data rate\n"); + fprintf(stderr, "\twhere j is the peak data rate\n"); + fprintf(stderr, "\twhere k is the max burst size\n"); + fprintf(stderr, "\twhere l is the delay bound\n"); + fprintf(stderr, "\twhere m is the surplus bandwidth [fixed point notation]\n"); + fprintf(stderr, "\twhere n is the minimum PHY rate\n"); +} + +static void wl_cac_delts_usage(void) +{ + fprintf(stderr, "Too few arguments\n"); + fprintf(stderr, "wl cac_delts ver a b c \n"); + fprintf(stderr, "\twhere ver is the tspec version\n"); + fprintf(stderr, "\twhere a is byte[0] of tsinfo (bits 0-7)\n"); + fprintf(stderr, "\twhere b is byte[1] of tsinfo (bits 8-15)\n"); + fprintf(stderr, "\twhere c is byte[2] of tsinfo (bits 16-23)\n"); +} + +static int +wl_cac(void *wl, cmd_t *cmd, char **argv) +{ + int err = -1; + int ap_mode = 0; + int apsta_mode = 0; + int cmd_type = 0; + tspec_arg_t tspec_arg; + char *endptr = NULL; + uint buflen; + char *arg1, *user_argv; + uint8 direction = BI_DIRECTION; + uint8 user_tid, user_prio, user_psb; + uint fixed; + + + if ((err = wlu_iovar_get(wl, "apsta", &apsta_mode, sizeof(apsta_mode)))) + return err; + + if (!apsta_mode) { + if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode)))) + return err; + else { + if (dtoh32(ap_mode)) { + fprintf(stderr, + "This command can ONLY be executed on a STA or APSTA\n"); + return err; + } + } + } + + if (!strcmp(*argv, "cac_addts")) + cmd_type = 1; + else if (!strcmp(*argv, "cac_delts")) + cmd_type = 2; + else { + fprintf(stderr, "unknown command\n"); + return BCME_USAGE_ERROR; + } + + /* eat command name */ + if (!*++argv) { + (cmd_type == 1) ? wl_cac_addts_usage():wl_cac_delts_usage(); + return BCME_BADARG; + } + + buflen = sizeof(tspec_arg_t); + memset((uint8 *)&tspec_arg, 0, buflen); + + /* get direction option */ + arg1 = *argv; + + /* Unidirectional DL/UL */ + if (!strcmp(arg1, "UDL") || (!strcmp(arg1, "UUL"))) + direction = DOWNLINK_DIRECTION; + + if (cmd_type == 1) { + uint argc = 0; + + /* arg count */ + while (argv[argc]) + argc++; + + /* required argments */ + if (argc < MIN_NUM_ADDTS_ARG) { + wl_cac_addts_usage(); + return BCME_USAGE_ERROR; + } + + tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16)); + tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.dialog_token = (uint8)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + user_tid = (uint8)strtol(*argv++, &endptr, 0); + user_tid <<= TID_SHIFT; + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + /* store the pointer for parsing */ + user_argv = *argv++; + + if (!strcmp(user_argv, "uplink")) + direction = UPLINK_DIRECTION; + else if (!strcmp(user_argv, "downlink")) + direction = DOWNLINK_DIRECTION; + else if (!strcmp(user_argv, "bi-directional")) + direction = BI_DIRECTION; + else + return BCME_USAGE_ERROR; + + /* store the pointer for parsing */ + user_argv = *argv++; + + if (!strcmp(user_argv, "legacy")) + user_psb = 0; + else if (!strcmp(user_argv, "U-APSD")) + user_psb = UAPSD_PSB; + else + return BCME_USAGE_ERROR; + + user_prio = (uint8)strtol(*argv++, &endptr, 0); + user_prio <<= UP_SHIFT; + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.tsinfo.octets[0] = (uint8)(user_tid | + direction | EDCA_ACCESS); + + tspec_arg.tsinfo.octets[1] = (uint8)(user_prio | user_psb); + tspec_arg.tsinfo.octets[2] = 0x00; + + tspec_arg.nom_msdu_size = (uint16)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + fixed = (uint)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + if (fixed == 1) + tspec_arg.nom_msdu_size |= 0x8000; + + tspec_arg.max_msdu_size = (uint16)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.min_srv_interval = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.max_srv_interval = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.inactivity_interval = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.suspension_interval = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.min_data_rate = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.mean_data_rate = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.peak_data_rate = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.max_burst_size = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.delay_bound = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.surplus_bw = (uint16)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.min_phy_rate = strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + printf("Setting min_phy_rate to 0x%x\n", tspec_arg.min_phy_rate); + } else { + uint argc = 0; + + /* arg count */ + while (argv[argc]) + argc++; + + /* required argments */ + if (argc < MIN_NUM_DELTS_ARG) { + wl_cac_delts_usage(); + return BCME_USAGE_ERROR; + } + + tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16)); + tspec_arg.version = (uint16)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + + wl_cac_format_tspec_htod(&tspec_arg); + err = wlu_var_setbuf(wl, cmd->name, &tspec_arg, buflen); + + return err; +} + +/* get a list of traffic stream (TSINFO) in driver */ +static int +wl_tslist(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + int i; + int ap_mode, err = -1; + int apsta_mode = 0; + struct tslist *tslist; + + UNUSED_PARAMETER(argv); + + + if ((err = wlu_iovar_get(wl, "apsta", &apsta_mode, sizeof(apsta_mode)))) + return err; + + if (!apsta_mode) { + if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode)))) + return err; + else { + if (dtoh32(ap_mode)) { + fprintf(stderr, + "This command can ONLY be executed on a STA or APSTA\n"); + return err; + } + } + } + + if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return err; + + tslist = (struct tslist *)ptr; + tslist->count = dtoh32(tslist->count); + for (i = 0; i < tslist->count; i++) + printf("tsinfo 0x%02X 0x%02X 0x%02X TID %d User Prio %d Direction %d\n", + tslist->tsinfo[i].octets[0], + tslist->tsinfo[i].octets[1], + tslist->tsinfo[i].octets[2], + WLC_CAC_GET_TID(tslist->tsinfo[i]), + WLC_CAC_GET_USER_PRIO(tslist->tsinfo[i]), + WLC_CAC_GET_DIR(tslist->tsinfo[i])); + + return 0; +} + +/* get specific TSPEC in driver */ +static int +wl_tspec(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + int ap_mode, err = -1; + tspec_arg_t *ts, tspec_arg; + char *temp = NULL; + uint argc = 0; + + if ((wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode)))) + return err; + ap_mode = dtoh32(ap_mode); + + if (ap_mode) { + fprintf(stderr, "This command can only be executed on the STA\n"); + return err; + } + + /* eat command name */ + argv++; + + /* arg count */ + while (argv[argc]) + argc++; + + /* required argments */ + if (argc < NUM_TSLIST_ARG) { + fprintf(stderr, "Too few arguments\n"); + fprintf(stderr, "wl cac_tspec 0xaa 0xbb 0xcc \n"); + fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n"); + fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n"); + fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n"); + return BCME_USAGE_ERROR; + } + + memset((uint8 *)&tspec_arg, 0, sizeof(tspec_arg_t)); + + tspec_arg.tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0); + if (*temp != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0); + if (*temp != '\0') + return BCME_USAGE_ERROR; + + tspec_arg.tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0); + if (*temp != '\0') + return BCME_USAGE_ERROR; + if ((err = wlu_var_getbuf(wl, cmd->name, &tspec_arg, sizeof(tspec_arg_t), &ptr)) < 0) + return err; + + ts = (tspec_arg_t *)ptr; + wl_cac_format_tspec_dtoh(ts); + wl_print_tspec(ts); + + return 0; +} + +/* get/set max bandwidth for each access category in ap */ +static int +wme_maxbw_params(void *wl, cmd_t *cmd, char **argv) +{ + wme_max_bandwidth_t cur_params, new_params; + char *val_p, *ac_str, *param; + int buflen; + int aci; + int err; + int val; + int ap_mode = 0; + + argv++; + + if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode))) < 0) + return err; + + if (!ap_mode) { + printf("%s: AP only\n", cmd->name); + return -1; + } + + buflen = WLC_IOCTL_MAXLEN; + + /* get the current max bandwidth, using buf as an input buffer. */ + strcpy(buf, "wme_maxbw_params"); + if ((err = wlu_get(wl, WLC_GET_VAR, &buf[0], buflen)) < 0) { + return err; + } + + /* cache the current values */ + memcpy(&cur_params, buf, sizeof(wme_max_bandwidth_t)); + + if ((ac_str = *argv) == NULL) { + printf("WME bandwidth limit: \n"); + for (aci = 0; aci < AC_COUNT; aci++) { + printf("%s: bandwidth limit %d\n", ac_names[aci], + cur_params.ac[aci]); + } + } else { + /* preload new values with current values */ + memcpy(&new_params, &cur_params, sizeof(new_params)); + while ((param = *argv++) != NULL) { + if ((val_p = *argv++) == NULL) { + printf("Need value following %s\n", param); + return BCME_USAGE_ERROR; + } + + val = (int)strtoul(val_p, NULL, 0); + + if (!strcmp(param, "be")) { + new_params.ac[AC_BE] = (uint32)val; + } else if (!strcmp(param, "bk")) { + new_params.ac[AC_BK] = (uint32)val; + } else if (!strcmp(param, "vi")) { + new_params.ac[AC_VI] = (uint32)val; + } else if (!strcmp(param, "vo")) { + new_params.ac[AC_VO] = (uint32)val; + } else { + printf("Unknown access category: %s\n", param); + return BCME_USAGE_ERROR; + } + } + + strcpy(buf, "wme_maxbw_params"); + memcpy(buf + strlen(buf) + 1, &new_params, sizeof(wme_max_bandwidth_t)); + err = wlu_set(wl, WLC_SET_VAR, &buf[0], buflen); + + } + + return err; +} + +/* get the tspec list for the given station */ +static int +wl_tslist_ea(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + int i; + int ap_mode, err = -1; + struct tslist *tslist; + scb_val_t scb_val; + + + if (!*++argv) { + printf("MAC address must be specified\n"); + return BCME_USAGE_ERROR; + } else if (!wl_ether_atoe(*argv, &scb_val.ea)) { + printf("Malformed MAC address parameter\n"); + return BCME_USAGE_ERROR; + } + if ((err = wlu_get(wl, WLC_GET_AP, &ap_mode, sizeof(ap_mode)))) + return err; + + ap_mode = dtoh32(ap_mode); + + if ((err = wlu_var_getbuf(wl, cmd->name, &scb_val.ea, ETHER_ADDR_LEN, &ptr)) < 0) + return err; + + tslist = (struct tslist *)ptr; + + for (i = 0; i < tslist->count; i++) + printf("tsinfo 0x%02X 0x%02X 0x%02X TID %d User Prio %d Direction %d\n", + tslist->tsinfo[i].octets[0], + tslist->tsinfo[i].octets[1], + tslist->tsinfo[i].octets[2], + WLC_CAC_GET_TID(tslist->tsinfo[i]), + WLC_CAC_GET_USER_PRIO(tslist->tsinfo[i]), + WLC_CAC_GET_DIR(tslist->tsinfo[i])); + + return 0; + +} + +/* get specific TSPEC for a STA */ +static int +wl_tspec_ea(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + int err = -1; + tspec_per_sta_arg_t tsea; + tspec_arg_t *ts; + char *temp; + uint argc = 0; + + /* eat command name */ + argv++; + + while (argv[argc]) + argc++; + + /* required argments */ + if (argc < (NUM_TSLIST_PER_EA_ARG + 1)) { + fprintf(stderr, "Too few arguments\n"); + fprintf(stderr, "wl cac_tspec 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx\n"); + fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n"); + fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n"); + fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n"); + fprintf(stderr, "\twhere xx:xx:xx:xx:xx:xx is mac address )\n"); + return BCME_USAGE_ERROR; + } + + memset((uint8 *)&tsea, 0, sizeof(tspec_per_sta_arg_t)); + + ts = &tsea.ts; + + ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &temp, 0); + if (*temp != '\0') + return BCME_USAGE_ERROR; + + ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &temp, 0); + if (*temp != '\0') + return BCME_USAGE_ERROR; + + ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &temp, 0); + if (*temp != '\0') + return BCME_USAGE_ERROR; + + /* add the ether address after tsinfo */ + if (!*argv) { + printf("MAC address must be specified\n"); + return BCME_USAGE_ERROR; + } else if (!wl_ether_atoe(*argv, &tsea.ea)) { + printf("Malformed MAC address parameter\n"); + return BCME_USAGE_ERROR; + } + + if ((err = wlu_var_getbuf(wl, cmd->name, &tsea, sizeof(tspec_per_sta_arg_t), &ptr)) < 0) + return err; + + ts = (tspec_arg_t *)ptr; + wl_cac_format_tspec_dtoh(ts); + wl_print_tspec(ts); + return 0; + +} + +static const uint8 wlu_wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, + AC_BE }; +static const uint8 wlu_prio2fifo[NUMPRIO] = { + 0, /* 0 BE AC_BE Best Effort */ + 1, /* 1 BK AC_BK Background */ + 2, /* 2 -- AC_BK Background */ + 3, /* 3 EE AC_BE Best Effort */ + 4, /* 4 CL AC_VI Video */ + 5, /* 5 VI AC_VI Video */ + 6, /* 6 VO AC_VO Voice */ + 7 /* 7 NC AC_VO Voice */ +}; +#define WME_PRIO2AC(prio) wlu_wme_fifo2ac[wlu_prio2fifo[(prio)]] + +static void +wl_print_tspec(tspec_arg_t *ts) +{ + const char *str; + if (ts->version != TSPEC_ARG_VERSION) { + printf("\tIncorrect version of TSPEC struct: expected %d; got %d\n", + TSPEC_ARG_VERSION, ts->version); + return; + } + + if (ts->length < (sizeof(tspec_arg_t) - (2 * sizeof(uint16)))) { + printf("\tTSPEC arg length too short: expected %d; got %d\n", + (int)(sizeof(tspec_arg_t) - (2 * sizeof(uint16))), ts->length); + return; + } + + switch (ts->flag & TSPEC_STATUS_MASK) { + case TSPEC_PENDING: + str = "PENDING"; + break; + case TSPEC_ACCEPTED: + str = "ACCEPTED"; + break; + case TSPEC_REJECTED: + str = "REJECTED"; + break; + default: + str = "UNKNOWN"; + break; + } + + printf("version %d\n", ts->version); + printf("length %d\n", ts->length); + + printf("TID %d %s\n", WLC_CAC_GET_TID(ts->tsinfo), str); + printf("tsinfo 0x%02x 0x%02x 0x%02x\n", ts->tsinfo.octets[0], + ts->tsinfo.octets[1], ts->tsinfo.octets[2]); + + /* breakout bitfields for apsd */ + if (WLC_CAC_GET_PSB(ts->tsinfo)) { + int ac = WME_PRIO2AC(WLC_CAC_GET_USER_PRIO(ts->tsinfo)); + switch (WLC_CAC_GET_DIR(ts->tsinfo)) { + case (TS_INFO_UPLINK >> TS_INFO_DIRECTION_SHIFT): + printf("AC[%d] : Trigger enabled\n", ac); + break; + + case (TS_INFO_DOWNLINK >> TS_INFO_DIRECTION_SHIFT): + printf("AC[%d] : Delivery enabled\n", ac); + break; + + case (TS_INFO_BIDIRECTIONAL >> + TS_INFO_DIRECTION_SHIFT): + printf("AC[%d] : Trig & Delv enabled\n", ac); + break; + } + } else { + int ac; + ac = WME_PRIO2AC(WLC_CAC_GET_USER_PRIO(ts->tsinfo)); + printf("AC [%d] : Legacy Power save\n", ac); + } + + + printf("nom_msdu_size %d %s\n", (ts->nom_msdu_size & 0x7fff), + ((ts->nom_msdu_size & 0x8000) ? "fixed size" : "")); + printf("max_msdu_size %d\n", ts->max_msdu_size); + printf("min_srv_interval %d\n", ts->min_srv_interval); + printf("max_srv_interval %d\n", ts->max_srv_interval); + printf("inactivity_interval %d\n", ts->inactivity_interval); + printf("suspension_interval %d\n", ts->suspension_interval); + printf("srv_start_time %d\n", ts->srv_start_time); + printf("min_data_rate %d\n", ts->min_data_rate); + printf("mean_data_rate %d\n", ts->mean_data_rate); + printf("peak_data_rate %d\n", ts->peak_data_rate); + printf("max_burst_size %d\n", ts->max_burst_size); + printf("delay_bound %d\n", ts->delay_bound); + printf("min_phy_rate %d\n", ts->min_phy_rate); + printf("surplus_bw %d\n", ts->surplus_bw); + printf("medium_time %d\n", ts->medium_time); +} + + +/* send delts for a specific ea */ +/* TODO : Club this with wl_tspec_ea */ +static int +wl_cac_delts_ea(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + int err = -1; + char *endptr = NULL; + tspec_per_sta_arg_t tsea; + tspec_arg_t *ts; + uint argc = 0; + + /* eat command name */ + argv++; + + while (argv[argc]) + argc++; + + /* required argments */ + if (argc < (NUM_TSLIST_PER_EA_ARG + 1)) { + fprintf(stderr, "Too few arguments\n"); + fprintf(stderr, "wl cac_delts_ea ver 0xaa 0xbb 0xcc xx:xx:xx:xx:xx:xx\n"); + fprintf(stderr, "\twhere ver is the tspec version\n"); + fprintf(stderr, "\twhere 0xaa is byte[0] of tsinfo (bits 0-7)\n"); + fprintf(stderr, "\twhere 0xbb is byte[1] of tsinfo (bits 8-15)\n"); + fprintf(stderr, "\twhere 0xcc is byte[2] of tsinfo (bits 16-23)\n"); + fprintf(stderr, "\twhere xx:xx:xx:xx:xx:xx is mac address )\n"); + return BCME_USAGE_ERROR; + } + + memset((uint8 *)&tsea, 0, sizeof(tspec_per_sta_arg_t)); + + ts = &tsea.ts; + + ts->length = sizeof(tspec_arg_t) - (2 * sizeof(uint16)); + ts->version = (uint16)strtol(*argv++, &endptr, 0); + + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ts->tsinfo.octets[0] = (uint8)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ts->tsinfo.octets[1] = (uint8)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ts->tsinfo.octets[2] = (uint8)strtol(*argv++, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + + /* add the ether address after tsinfo */ + if (!*argv) { + printf("MAC address must be specified\n"); + return BCME_USAGE_ERROR; + } else if (!wl_ether_atoe(*argv, &tsea.ea)) { + printf("Malformed MAC address parameter\n"); + return BCME_USAGE_ERROR; + } + + wl_cac_format_tspec_htod(ts); + if ((err = wlu_var_getbuf(wl, cmd->name, &tsea, sizeof(tspec_per_sta_arg_t), &ptr)) < 0) + return err; + + return 0; + +} + +static int +wl_antsel(void *wl, cmd_t *cmd, char **argv) +{ + const char *ant_sel = "fixed"; + char *val_name; + wlc_antselcfg_t val = {{0}, 0}; + int err, argc, i; + char *endptr = NULL; + uint32 txchain_bitmap = 0; + uint16 antsel_mask = 0; + + /* toss the command name */ + val_name = *argv++; + + if (!*argv) { + if (cmd->get < 0) + return -1; + if ((err = wlu_iovar_get(wl, "txchain", &txchain_bitmap, sizeof(txchain_bitmap))) < 0) + return err; + + /* iterate over max 4 chains */ + for (i = 0; i < 4; i ++) { + if (!(txchain_bitmap & (1<<i))) + antsel_mask |= (0xF << i * 4); + } + + if ((err = wlu_iovar_get(wl, val_name, &val, sizeof(wlc_antselcfg_t))) < 0) + return err; + + printf("C3C2C1C0: "); + for (i = ANT_SELCFG_TX_UNICAST; i < ANT_SELCFG_MAX; i++) { + if (val.ant_config[i] & ANT_SELCFG_AUTO) + ant_sel = "auto"; + printf("0x%04X %s ", + antsel_mask | (val.ant_config[i] & ANT_SELCFG_MASK), ant_sel); + } + printf("\n"); + } else { + /* arg count */ + for (argc = 0; argv[argc]; argc++); + + if ((argc >= 2 && argc <= 3) || argc > ANT_SELCFG_MAX) { + printf("invalid %d args\n", argc); + return BCME_USAGE_ERROR; + } + + val.ant_config[ANT_SELCFG_TX_UNICAST] = (uint8)strtol(*argv++, &endptr, 0); + printf("UTX 0x%02x\n", val.ant_config[ANT_SELCFG_TX_UNICAST]); + if (*endptr != '\0') { + printf("Invaild UTX parameter: %s\n", *argv); + return BCME_USAGE_ERROR; + } + if (argc == 1) { + val.ant_config[ANT_SELCFG_RX_UNICAST] = + val.ant_config[ANT_SELCFG_TX_UNICAST]; + val.ant_config[ANT_SELCFG_TX_DEF] = val.ant_config[ANT_SELCFG_TX_UNICAST]; + val.ant_config[ANT_SELCFG_RX_DEF] = val.ant_config[ANT_SELCFG_TX_UNICAST]; + } else { + val.ant_config[ANT_SELCFG_RX_UNICAST] = (uint8)strtol(*argv++, &endptr, 0); + printf("URX 0x%02x\n", val.ant_config[ANT_SELCFG_RX_UNICAST]); + if (*endptr != '\0') { + printf("Invaild URX parameter: %s\n", *argv); + return BCME_USAGE_ERROR; + } + val.ant_config[ANT_SELCFG_TX_DEF] = (uint8)strtol(*argv++, &endptr, 0); + printf("DTX 0x%02x\n", val.ant_config[ANT_SELCFG_TX_DEF]); + if (*endptr != '\0') { + printf("Invaild DTX parameter: %s\n", *argv); + return BCME_USAGE_ERROR; + } + val.ant_config[ANT_SELCFG_RX_DEF] = (uint8)strtol(*argv++, &endptr, 0); + printf("DRX 0x%02x\n", val.ant_config[ANT_SELCFG_RX_DEF]); + if (*endptr != '\0') { + printf("Invaild DRX parameter: %s\n", *argv); + return BCME_USAGE_ERROR; + } + } + err = wlu_iovar_set(wl, val_name, &val, sizeof(wlc_antselcfg_t)); + } + return err; +} + +static int +wl_txcore_pwr_offset(void *wl, cmd_t *cmd, char **argv) +{ + wl_txchain_pwr_offsets_t offsets; + char *endptr; + int i; + long val; + int err; + + /* toss the command name */ + argv++; + + if (!*argv) { + err = wlu_iovar_get(wl, cmd->name, &offsets, sizeof(wl_txchain_pwr_offsets_t)); + + if (err < 0) + return err; + + printf("txcore offsets qdBm: %d %d %d %d\n", + offsets.offset[0], offsets.offset[1], + offsets.offset[2], offsets.offset[3]); + + return 0; + } + + memset(&offsets, 0, sizeof(wl_txchain_pwr_offsets_t)); + + for (i = 0; i < WL_NUM_TXCHAIN_MAX; i++, argv++) { + if (!*argv) + break; + + val = strtol(*argv, &endptr, 0); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + if (val > 0) + return BCME_BADARG; + + offsets.offset[i] = (int8)val; + } + + err = wlu_iovar_set(wl, cmd->name, &offsets, sizeof(wl_txchain_pwr_offsets_t)); + + return err; +} + +static int +wl_txcore(void *wl, cmd_t *cmd, char **argv) +{ + miniopt_t to; + const char* fn_name = "wl_txcore"; + int err = 0, opt_err, val; + uint8 streams = 0; + bool streams_set = FALSE; + uint8 core = 0; + bool core_set = FALSE; + uint8 cck_mask = 0; + bool cck_set = FALSE; + uint8 ofdm_mask = 0; + bool ofdm_set = FALSE; + uint8 mcs_mask[4] = {0, 0, 0, 0}; /* pre-initialize # of streams {core:4 | stream:4} */ + bool mcs_set = FALSE; + uint8 idx; + uint32 coremask[2] = {0, 0}; + + /* toss the command name */ + argv++; + + if (!*argv) { + if (cmd->get < 0) + return -1; + if ((err = wlu_iovar_get(wl, cmd->name, &coremask, sizeof(uint32)*2)) < 0) + return err; + + printf("txcore enabled bitmap (Nsts {4..1}) 0x%02x 0x%02x 0x%02x 0x%02x\n", + (coremask[0] >> 24) & 0xff, (coremask[0] >> 16) & 0xff, + (coremask[0] >> 8) & 0xff, coremask[0] & 0xff); + printf("txcore mask OFDM 0x%02x CCK 0x%02x\n", + (coremask[1] >> 8) & 0xff, coremask[1] & 0xff); + return 0; + } + + val = atoi(*argv); + if (val == -1) + goto next; + + miniopt_init(&to, fn_name, "w", FALSE); + while ((opt_err = miniopt(&to, argv)) != -1) { + if (opt_err == 1) { + err = BCME_USAGE_ERROR; + goto exit; + } + argv += to.consumed; + + if (to.opt == 's') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for streams\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + streams_set = TRUE; + streams = (to.val & 0x0f); + if (streams > 4) + fprintf(stderr, "%s: Nsts > %d\n", fn_name, to.val); + } + if (to.opt == 'c') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for stf core\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + core_set = TRUE; + core = (to.val & 0x0f) << 4; + if (core == 0) { + fprintf(stderr, "%s: %1d-stream core cannot be zero\n", + fn_name, streams); + err = BCME_BADARG; + goto exit; + } + } + if (to.opt == 'o') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for streams\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + ofdm_set = TRUE; + ofdm_mask = (to.val & 0x0f); + if (ofdm_mask == 0) { + fprintf(stderr, "%s: OFDM core cannot be zero\n", fn_name); + err = BCME_BADARG; + goto exit; + } + } + if (to.opt == 'k') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for streams\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + cck_set = TRUE; + cck_mask = (to.val & 0x0f); + if (cck_mask == 0) { + fprintf(stderr, "%s: CCK core cannot be zero\n", fn_name); + err = BCME_BADARG; + goto exit; + } + } + + if (streams_set && core_set) { + streams_set = core_set = FALSE; + mcs_set = TRUE; + idx = streams - 1; + mcs_mask[idx] = (uint8)(core|streams); + } + } + + if (streams_set != core_set) { + fprintf(stderr, "%s: require to set both -s x -c y\n", fn_name); + err = BCME_BADARG; + goto exit; + } + + if (mcs_set) { + coremask[0] |= mcs_mask[0] << 0; + coremask[0] |= mcs_mask[1] << 8; + coremask[0] |= mcs_mask[2] << 16; + coremask[0] |= mcs_mask[3] << 24; + } + if (cck_set) + coremask[1] |= cck_mask; + if (ofdm_set) + coremask[1] |= ofdm_mask << 8; +next: + err = wlu_var_setbuf(wl, cmd->name, coremask, sizeof(uint32)*2); +exit: + return err; +} + +#ifdef PLC +static int +wl_plc(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + char *endptr; + const char *cmdname = "plc"; + wl_plc_params_t plc, *reply; + int err; + void *ptr; + + UNUSED_PARAMETER(cmd); + + memset(&plc, 0, sizeof(plc)); + + if ((param = *++argv) == NULL) { + plc.cmd = PLC_CMD_FAILOVER; + /* Get plc failover status */ + err = wlu_var_getbuf_sm(wl, cmdname, &plc, sizeof(plc), &ptr); + reply = (wl_plc_params_t *)ptr; + if (err >= 0) + printf("%d\n", reply->plc_failover); + return err; + } + + if ((strcmp(param, "1") == 0) || (strcmp(param, "0") == 0)) { + plc.cmd = PLC_CMD_FAILOVER; + plc.plc_failover = strtoul(param, &endptr, 0); + /* Set plc failover status */ + err = wlu_var_setbuf(wl, cmdname, &plc, sizeof(plc)); + return err; + } else if (strcmp(param, "node_list") == 0) { + wl_plc_nodelist_t *list = (wl_plc_nodelist_t *)buf; + uint32 i, max = (WLC_IOCTL_MAXLEN - sizeof(int)) / sizeof(wl_plc_nodelist_t); + + /* Get the list of known nodes */ + plc.cmd = PLC_CMD_NODE_LIST; + memset(buf, 0, WLC_IOCTL_MAXLEN); + err = wlu_iovar_getbuf(wl, cmdname, &plc, sizeof(plc), buf, WLC_IOCTL_MAXLEN); + if (err < 0) + return err; + + for (i = 0; i < dtoh32(list->count) && i < max; i++) { + printf("%s %-9s %-d\n", wl_ether_etoa(&list->node[i].ea), + list->node[i].node_type == NODE_TYPE_WIFI_ONLY ? "wifi-only" : + list->node[i].node_type == NODE_TYPE_PLC_ONLY ? "plc-only" : + list->node[i].node_type == NODE_TYPE_WIFI_PLC ? "wifi-plc" : + "unknown", list->node[i].cost); + } + return err; + } else if (strcmp(param, "mac_affinity") == 0) + plc.cmd = PLC_CMD_MAC_COST; + else if (strcmp(param, "link_affinity") == 0) + plc.cmd = PLC_CMD_LINK_COST; + else + return BCME_USAGE_ERROR; + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + if (!wl_ether_atoe(param, &plc.node_ea)) + return BCME_USAGE_ERROR; + + if ((param = *++argv) == NULL) { + /* Get plc link/mac path affinity */ + err = wlu_var_getbuf_sm(wl, cmdname, &plc, sizeof(plc), &ptr); + reply = (wl_plc_params_t *)ptr; + if (err >= 0) + printf("%d\n", reply->cost); + return err; + } + + /* Set plc link/mac path affinity */ + plc.cost = strtoul(param, &endptr, 0); + err = wlu_var_setbuf(wl, cmdname, &plc, sizeof(plc)); + + return err; +} +#endif /* PLC */ + +static int +wl_txfifo_sz(void *wl, cmd_t *cmd, char **argv) +{ + char *param; + const char *cmdname = "txfifo_sz"; + wl_txfifo_sz_t ts, *reply; + uint fifo; + int err; + void *ptr = NULL; + + UNUSED_PARAMETER(cmd); + + if ((param = *++argv) == NULL) + return BCME_USAGE_ERROR; + + fifo = atoi(param); + if (fifo > NFIFO) + return BCME_USAGE_ERROR; + ts.fifo = fifo; + ts.magic = WL_TXFIFO_SZ_MAGIC; + + if ((param = *++argv)) { + ts.size = atoi(param); + err = wlu_var_setbuf(wl, cmdname, &ts, sizeof(ts)); + } else { + if ((err = wlu_var_getbuf_sm(wl, cmdname, &ts, sizeof(ts), &ptr) < 0)) + return err; + reply = (wl_txfifo_sz_t *)ptr; + printf("fifo %d size %d\n", fifo, reply->size); + } + return err; +} +#ifdef WLPFN +static int +wl_pfn_set(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_pfn_param_t pfn_param; + + UNUSED_PARAMETER(cmd); + + /* Setup default values */ + pfn_param.version = PFN_VERSION; + /* Sorting based on list order, no back ground scan, no autoswitch, + * no immediate event report, no adaptvie scan, but immediate scan + */ + pfn_param.flags = (PFN_LIST_ORDER << SORT_CRITERIA_BIT | ENABLE << IMMEDIATE_SCAN_BIT); + /* Scan frequency of 30 sec */ + pfn_param.scan_freq = 30; + /* slow adapt scan is off by default */ + pfn_param.slow_freq = 0; + /* RSSI margin of 30 dBm */ + pfn_param.rssi_margin = 30; + /* Network timeout 60 sec */ + pfn_param.lost_network_timeout = 60; + /* best n = 2 by default */ + pfn_param.bestn = DEFAULT_BESTN; + /* mscan m=0 by default, so not record best networks by default */ + pfn_param.mscan = DEFAULT_MSCAN; + /* default repeat = 10 */ + pfn_param.repeat = DEFAULT_REPEAT; + /* by default, maximum scan interval = 2^2*scan_freq when adaptive scan is turned on */ + pfn_param.exp = DEFAULT_EXP; + + while (*++argv) { + if (!stricmp(*argv, "scanfrq")) { + if (*++argv) + pfn_param.scan_freq = atoi(*argv); + else { + fprintf(stderr, "Missing scanfrq option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "netimeout")) { + if (*++argv) + pfn_param.lost_network_timeout = atoi(*argv); + else { + fprintf(stderr, "Missing netimeout option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "rssi_delta")) { + if (*++argv) + pfn_param.rssi_margin = atoi(*argv); + else { + fprintf(stderr, "Missing rssi_delta option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "sort")) { + if (*++argv) { + pfn_param.flags &= ~SORT_CRITERIA_MASK; + if (!stricmp(*argv, "listorder")) + pfn_param.flags |= (PFN_LIST_ORDER << SORT_CRITERIA_BIT); + else if (!stricmp(*argv, "rssi")) + pfn_param.flags |= (PFN_RSSI << SORT_CRITERIA_BIT); + else { + fprintf(stderr, "Invalid sort option %s\n", *argv); + return BCME_USAGE_ERROR; + } + } else { + fprintf(stderr, "Missing sort option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "immediateevent")) { + if (*++argv) { + if (!stricmp(*argv, "1")) { + pfn_param.flags |= IMMEDIATE_EVENT_MASK; + } else if (!stricmp(*argv, "0")) { + pfn_param.flags &= ~IMMEDIATE_EVENT_MASK; + } else { + fprintf(stderr, "Invalid immediateevent option\n"); + return BCME_USAGE_ERROR; + } + } else { + fprintf(stderr, "Missing immediateevent option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "bkgscan")) { + if (*++argv) { + pfn_param.flags &= ~ENABLE_BKGRD_SCAN_MASK; + if (atoi(*argv)) + pfn_param.flags |= (ENABLE << ENABLE_BKGRD_SCAN_BIT); + else + pfn_param.flags |= (DISABLE << ENABLE_BKGRD_SCAN_BIT); + } else { + fprintf(stderr, "Missing bkgscan option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "immediate")) { + pfn_param.flags &= ~IMMEDIATE_SCAN_MASK; + if (*++argv) { + if (atoi(*argv)) + pfn_param.flags |= (ENABLE << IMMEDIATE_SCAN_BIT); + else + pfn_param.flags |= (DISABLE << IMMEDIATE_SCAN_BIT); + } else { + fprintf(stderr, "Missing immediate option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "bdscan")) { + if (*++argv) { + pfn_param.flags &= ~ENABLE_BD_SCAN_MASK; + if (atoi(*argv)) + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + else + pfn_param.flags |= (DISABLE << ENABLE_BD_SCAN_BIT); + } else { + fprintf(stderr, "Missing bdscan option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "separate")) { + if (*++argv) { + pfn_param.flags &= ~REPORT_SEPERATELY_MASK; + if (atoi(*argv)) + pfn_param.flags |= (ENABLE << REPORT_SEPERATELY_BIT); + else + pfn_param.flags |= (DISABLE << REPORT_SEPERATELY_BIT); + } else { + fprintf(stderr, "Missing seperate option\n"); + return -1; + } + } else if (!stricmp(*argv, "adapt")) { + if (*++argv) { + pfn_param.flags &= ~ENABLE_ADAPTSCAN_MASK; + if (!stricmp(*argv, "off")) { + pfn_param.flags |= (OFF_ADAPT << ENABLE_ADAPTSCAN_BIT); + } else if (!stricmp(*argv, "smart")) { + pfn_param.flags |= (SMART_ADAPT << ENABLE_ADAPTSCAN_BIT); + } else if (!stricmp(*argv, "strict")) { + pfn_param.flags |= (STRICT_ADAPT << ENABLE_ADAPTSCAN_BIT); + } else if (!stricmp(*argv, "slow")) { + pfn_param.flags |= (SLOW_ADAPT << ENABLE_ADAPTSCAN_BIT); + } else { + fprintf(stderr, "Invalid adaptive scan option %s\n", *argv); + return BCME_USAGE_ERROR; + } + } else { + fprintf(stderr, "Missing adaptive scan option\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "bestn")) { + pfn_param.bestn = atoi(*++argv); + } else if (!stricmp(*argv, "mscan")) { + pfn_param.mscan = atoi(*++argv); + } else if (!stricmp(*argv, "repeat")) { + pfn_param.repeat = atoi(*++argv); + if (pfn_param.repeat < 1 || pfn_param.repeat > 20) { + fprintf(stderr, "repeat %d out of range (1-20)\n", + pfn_param.repeat); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "exp")) { + pfn_param.exp = atoi(*++argv); + if (pfn_param.exp < 1 || pfn_param.exp > 5) { + fprintf(stderr, "exp %d out of range (1-5)\n", + pfn_param.exp); + return BCME_BADARG; + } + } else if (!stricmp(*argv, "slowfrq")) { + if (*++argv) + pfn_param.slow_freq = atoi(*argv); + else { + fprintf(stderr, "Missing slowfrq option\n"); + return BCME_USAGE_ERROR; + } + } else { + fprintf(stderr, "Invalid parameter %s\n", *argv); + return BCME_USAGE_ERROR; + } + } + + if ((((pfn_param.flags & ENABLE_ADAPTSCAN_MASK) == + (SLOW_ADAPT << ENABLE_ADAPTSCAN_BIT)) && + !pfn_param.slow_freq) || + (((pfn_param.flags & ENABLE_ADAPTSCAN_MASK) != + (SLOW_ADAPT << ENABLE_ADAPTSCAN_BIT)) && + pfn_param.slow_freq)) { + fprintf(stderr, "SLOW_ADAPT flag and slowfrq value not match\n"); + return BCME_BADARG; + } + pfn_param.version = htod32(pfn_param.version); + pfn_param.scan_freq = htod32(pfn_param.scan_freq); + pfn_param.lost_network_timeout = htod32(pfn_param.lost_network_timeout); + pfn_param.flags = htod16(pfn_param.flags); + pfn_param.rssi_margin = htod16(pfn_param.rssi_margin); + pfn_param.slow_freq = htod32(pfn_param.slow_freq); + + if ((err = wlu_iovar_set(wl, "pfn_set", &pfn_param, sizeof(wl_pfn_param_t)))) + return (err); + + return (0); +} + +static bool +validate_hex(char hexchar) +{ + if ((hexchar >= '0' && hexchar <= '9') || + (hexchar >= 'a' || hexchar <= 'z') || + (hexchar >= 'A' || hexchar <= 'Z')) + return TRUE; + else + return FALSE; +} + +static uint8 +char2hex(char hexchar) +{ + if (hexchar >= '0' && hexchar <= '9') + return (hexchar - '0'); + else if (hexchar >= 'a' && hexchar <= 'z') + return (hexchar - 'a' + 10); + else if (hexchar >= 'A' && hexchar <= 'Z') + return (hexchar - 'A' + 10); + else + { + fprintf(stderr, "non-hex\n"); + return 0xff; + } +} + +#define MAXNUM_SSID_PER_ADD 16 + +static int +wl_pfn_add(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_pfn_t *p_pfn_element = NULL; + int i, pfn_element_len, cnt; + wl_pfn_t *pssidnet = NULL; + int32 hidden; + + UNUSED_PARAMETER(cmd); + + pfn_element_len = MAXNUM_SSID_PER_ADD * sizeof(wl_pfn_t); + p_pfn_element = (wl_pfn_t *)malloc(pfn_element_len); + if (p_pfn_element == NULL) { + fprintf(stderr, "Failed to allocate buffer for %d bytes\n", pfn_element_len); + return BCME_NOMEM; + } + memset(p_pfn_element, '\0', pfn_element_len); + + pssidnet = p_pfn_element; + for (i = 0; i < MAXNUM_SSID_PER_ADD; i++) { + /* Default setting, open, no WPA, no WEP and bss */ + pssidnet->auth = DOT11_OPEN_SYSTEM; + pssidnet->wpa_auth = WPA_AUTH_DISABLED; + pssidnet->wsec = 0; + pssidnet->infra = 1; + pssidnet->flags = 0; + pssidnet++; + } + cnt = -1; + pssidnet = p_pfn_element; + while (*++argv) { + if (!stricmp(*argv, "ssid")) { + if (*++argv) { + if (++cnt >= MAXNUM_SSID_PER_ADD) { + fprintf(stderr, "exceed max 16 SSID per pfn_add\n"); + err = BCME_BADARG; + goto error; + } + if (cnt > 0) { + pssidnet->flags = htod32(pssidnet->flags); + pssidnet++; + } + strncpy((char *)pssidnet->ssid.SSID, *argv, + sizeof(pssidnet->ssid.SSID)); + pssidnet->ssid.SSID_len = + strlen((char *)pssidnet->ssid.SSID); + if (pssidnet->ssid.SSID_len > 32) { + fprintf(stderr, "SSID too long: %s\n", *argv); + err = BCME_BADARG; + goto error; + } + pssidnet->ssid.SSID_len = htod32(pssidnet->ssid.SSID_len); + } else { + fprintf(stderr, "no value for ssid\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } + else if (!stricmp(*argv, "hidden")) { + if (pssidnet->ssid.SSID_len == 0) { + fprintf(stderr, "Wrong! Start with SSID\n"); + err = BCME_USAGE_ERROR; + goto error; + } + if (*++argv) { + hidden = **argv - '0'; + if (hidden != ENABLE && hidden != DISABLE) { + fprintf(stderr, "invalid hidden setting, use 0/1\n"); + err = BCME_USAGE_ERROR; + goto error; + } + pssidnet->flags |= hidden << WL_PFN_HIDDEN_BIT; + } else { + fprintf(stderr, "no value for hidden\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else if (!stricmp(*argv, "imode")) { + if (*++argv) { + if (pssidnet->ssid.SSID_len == 0) { + fprintf(stderr, "Wrong! Start with SSID\n"); + err = BCME_USAGE_ERROR; + goto error; + } + if (!stricmp(*argv, "bss")) { + pssidnet->infra = 1; + } else if (!stricmp(*argv, "ibss")) { + pssidnet->infra = 0; + } else { + fprintf(stderr, "Invalid imode arg %s\n", *argv); + err = BCME_USAGE_ERROR; + goto error; + } + pssidnet->infra = htod32(pssidnet->infra); + } else { + fprintf(stderr, "Missing option for imode\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else if (!stricmp(*argv, "amode")) { + if (*++argv) { + if (pssidnet->ssid.SSID_len == 0) { + fprintf(stderr, "Wrong! Start with SSID\n"); + err = BCME_USAGE_ERROR; + goto error; + } + if (!stricmp(*argv, "open")) + pssidnet->auth = DOT11_OPEN_SYSTEM; + else if (!stricmp(*argv, "shared")) + pssidnet->auth = DOT11_SHARED_KEY; + else { + fprintf(stderr, "Invalid imode arg %s\n", *argv); + err = BCME_USAGE_ERROR; + goto error; + } + pssidnet->auth = htod32(pssidnet->auth); + } else { + fprintf(stderr, "Missing option for amode\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else if (!stricmp(*argv, "wpa_auth")) { + if (*++argv) { + uint32 wpa_auth; + if (pssidnet->ssid.SSID_len == 0) { + fprintf(stderr, "Wrong! Start with SSID\n"); + err = BCME_USAGE_ERROR; + goto error; + } + + /* figure requested auth, allow "any" */ + if (!stricmp(*argv, "wpapsk")) + pssidnet->wpa_auth = WPA_AUTH_PSK; + else if (!stricmp(*argv, "wpa2psk")) + pssidnet->wpa_auth = WPA2_AUTH_PSK; + else if (!stricmp(*argv, "wpadisabled")) + pssidnet->wpa_auth = WPA_AUTH_DISABLED; + else if (!stricmp(*argv, "any")) + pssidnet->wpa_auth = WPA_AUTH_PFN_ANY; + else if ((wpa_auth = strtoul(*argv, 0, 0))) + pssidnet->wpa_auth = wpa_auth; + else { + fprintf(stderr, "Invalid wpa_auth option %s\n", *argv); + err = BCME_USAGE_ERROR; + goto error; + } + pssidnet->wpa_auth = htod32(pssidnet->wpa_auth); + } else { + fprintf(stderr, "Missing option for wpa_auth\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else if (!stricmp(*argv, "wsec")) { + if (*++argv) { + if (pssidnet->ssid.SSID_len == 0) { + fprintf(stderr, "Wrong! Start with SSID\n"); + err = BCME_USAGE_ERROR; + goto error; + } + if (!stricmp(*argv, "WEP")) { + pssidnet->wsec = WEP_ENABLED; + } else if (!stricmp(*argv, "TKIP")) + pssidnet->wsec = TKIP_ENABLED; + else if (!stricmp(*argv, "AES")) + pssidnet->wsec = AES_ENABLED; + else if (!stricmp(*argv, "TKIPAES")) + pssidnet->wsec = TKIP_ENABLED | AES_ENABLED; + else { + fprintf(stderr, "Invalid wsec option %s\n", *argv); + err = BCME_USAGE_ERROR; + goto error; + } + pssidnet->wsec = htod32(pssidnet->wsec); + } else { + fprintf(stderr, "Missing option for wsec\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else if (!stricmp(*argv, "suppress")) { + if (*++argv) { + if (pssidnet->ssid.SSID_len == 0) { + fprintf(stderr, "Wrong! Start with SSID\n"); + err = BCME_USAGE_ERROR; + goto error; + } + if (!stricmp(*argv, "found")) { + pssidnet->flags |= WL_PFN_SUPPRESSFOUND_MASK; + } else if (!stricmp(*argv, "lost")) { + pssidnet->flags |= WL_PFN_SUPPRESSLOST_MASK; + } else if (!stricmp(*argv, "neither")) { + pssidnet->flags &= + ~(WL_PFN_SUPPRESSLOST_MASK | WL_PFN_SUPPRESSFOUND_MASK); + } else { + fprintf(stderr, "Invalid suppress option %s\n", *argv); + err = BCME_USAGE_ERROR; + goto error; + } + } else { + fprintf(stderr, "Missing option for suppress\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else if (!stricmp(*argv, "rssi")) { + if (*++argv) { + int rssi = atoi(*argv); + if (pssidnet->ssid.SSID_len == 0) { + fprintf(stderr, "Wrong! Start with SSID\n"); + err = BCME_USAGE_ERROR; + goto error; + } + if (rssi >= -128 && rssi <= 0) { + pssidnet->flags |= (rssi << WL_PFN_RSSI_SHIFT) + & WL_PFN_RSSI_MASK; + } else { + fprintf(stderr, "Invalid rssi option %s\n", *argv); + err = BCME_BADARG; + goto error; + } + } else { + fprintf(stderr, "Missing option for rssi\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else { + fprintf(stderr, "Invalid parameter %s\n", *argv); + err = BCME_USAGE_ERROR; + goto error; + } + } + pssidnet->flags = htod32(pssidnet->flags); + + pfn_element_len = (cnt + 1) * sizeof(wl_pfn_t); + if ((err = wlu_iovar_set(wl, "pfn_add", p_pfn_element, + pfn_element_len))) { + fprintf(stderr, "pfn_add fail\n"); + goto error; + } + free(p_pfn_element); + return (0); + +error: + free(p_pfn_element); + return err; +} + +#define MAXNUM_BSSID_PER_ADD 150 + +static int +wl_pfn_add_bssid(void *wl, cmd_t *cmd, char **argv) +{ + int err; + uint8 *ptr; + int i, bssidlistlen, cnt; + wl_pfn_bssid_t *bssidlist; + wl_pfn_bssid_t *pbssid = NULL; + + UNUSED_PARAMETER(cmd); + + if (!*(argv + 1)) { + fprintf(stderr, "Invalid command\n"); + return BCME_USAGE_ERROR; + } + + bssidlistlen = MAXNUM_BSSID_PER_ADD * sizeof(wl_pfn_bssid_t); + bssidlist = (wl_pfn_bssid_t *)malloc(bssidlistlen); + if (bssidlist == NULL) { + fprintf(stderr, "Failed to allocate buffer for %d bytes\n", bssidlistlen); + return BCME_NOMEM; + } + memset(bssidlist, '\0', bssidlistlen); + + cnt = 0; + while (*++argv) { + if (!stricmp(*argv, "bssid")) { + if (*++argv) { + if (cnt >= MAXNUM_BSSID_PER_ADD) { + fprintf(stderr, "exceed max 150 BSSID per pfn_add_bssid\n"); + err = BCME_BADARG; + goto error; + } + if (!cnt) + pbssid = bssidlist; + else { + pbssid->flags = htod16(pbssid->flags); + pbssid++; + } + + ptr = (uint8 *)*argv; + for (i = 0; i < ETHER_ADDR_LEN; i++) + { + if (!validate_hex(*ptr) || !validate_hex(*(ptr + 1))) + { + fprintf(stderr, "non-hex in BSSID\n"); + err = BCME_BADARG; + goto error; + } + pbssid->macaddr.octet[i] = + char2hex(*ptr) << 4 | char2hex(*(ptr+1)); + ptr += 3; + } + cnt++; + } else { + fprintf(stderr, "Missing option for bssid\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else if (!stricmp(*argv, "suppress")) { + if (!pbssid || ETHER_ISNULLADDR(pbssid->macaddr.octet)) { + fprintf(stderr, "Wrong! Start with BSSID\n"); + err = BCME_BADARG; + goto error; + } + if (*++argv) { + if (!stricmp(*argv, "found")) { + pbssid->flags |= WL_PFN_SUPPRESSFOUND_MASK; + } else if (!stricmp(*argv, "lost")) { + pbssid->flags |= WL_PFN_SUPPRESSLOST_MASK; + } else if (!stricmp(*argv, "neither")) { + pbssid->flags &= + ~(WL_PFN_SUPPRESSFOUND_MASK | WL_PFN_SUPPRESSLOST_MASK); + } else { + fprintf(stderr, "Invalid suppress option %s\n", *argv); + err = BCME_USAGE_ERROR; + goto error; + } + } else { + fprintf(stderr, "Missing option for suppress\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else if (!stricmp(*argv, "rssi")) { + if (*++argv) { + int rssi = atoi(*argv); + if (!pbssid || ETHER_ISNULLADDR(pbssid->macaddr.octet)) { + fprintf(stderr, "Wrong! Start with BSSID\n"); + err = BCME_BADARG; + goto error; + } + if (rssi >= -128 && rssi <= 0) { + pbssid->flags |= (rssi << WL_PFN_RSSI_SHIFT) + & WL_PFN_RSSI_MASK; + } else { + fprintf(stderr, "Invalid rssi option %s\n", *argv); + err = BCME_BADARG; + goto error; + } + } else { + fprintf(stderr, "Missing option for rssi\n"); + err = BCME_USAGE_ERROR; + goto error; + } + } else { + fprintf(stderr, "Invalid parameter %s\n", *argv); + err = BCME_USAGE_ERROR; + goto error; + } + } + pbssid->flags = htod16(pbssid->flags); + + bssidlistlen = cnt * sizeof(wl_pfn_bssid_t); + if ((err = wlu_iovar_set(wl, "pfn_add_bssid", bssidlist, + bssidlistlen))) { + fprintf(stderr, "pfn_add_bssid fail\n"); + goto error; + } + free(bssidlist); + return 0; + +error: + free(bssidlist); + return err; +} + +static int +wl_pfn_cfg(void *wl, cmd_t *cmd, char **argv) +{ + wl_pfn_cfg_t pfncfg_param; + int nchan = 0; + int err; + + UNUSED_PARAMETER(cmd); + + memset(&pfncfg_param, '\0', sizeof(wl_pfn_cfg_t)); + + /* Setup default values */ + pfncfg_param.reporttype = WL_PFN_REPORT_ALLNET; + pfncfg_param.channel_num = 0; + + while (*++argv) { + if (!stricmp(*argv, "report")) { + if (*++argv) { + if (!stricmp(*argv, "all")) { + pfncfg_param.reporttype = WL_PFN_REPORT_ALLNET; + } else if (!stricmp(*argv, "ssidonly")) { + pfncfg_param.reporttype = WL_PFN_REPORT_SSIDNET; + } else if (!stricmp(*argv, "bssidonly")) { + pfncfg_param.reporttype = WL_PFN_REPORT_BSSIDNET; + } else { + fprintf(stderr, "Invalid report option %s\n", *argv); + return BCME_USAGE_ERROR; + } + } else { + fprintf(stderr, "no value for report\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "channel")) { + if (*++argv) { + nchan = wl_parse_channel_list(*argv, pfncfg_param.channel_list, + WL_NUMCHANNELS); + if (nchan < 0) { + fprintf(stderr, "error parsing channel\n"); + return BCME_BADARG; + } + } else { + fprintf(stderr, "Missing option for channel\n"); + return BCME_USAGE_ERROR; + } + } else if (!stricmp(*argv, "prohibited")) { + if (*++argv) { + pfncfg_param.flags &= ~WL_PFN_CFG_FLAGS_PROHIBITED; + if (atoi(*argv)) + pfncfg_param.flags |= WL_PFN_CFG_FLAGS_PROHIBITED; + } else { + fprintf(stderr, "Missing prohibited option value\n"); + return BCME_USAGE_ERROR; + } + } else { + fprintf(stderr, "Invalid parameter %s\n", *argv); + return BCME_USAGE_ERROR; + } + } + + pfncfg_param.reporttype = htod32(pfncfg_param.reporttype); + pfncfg_param.channel_num = htod32(nchan); + pfncfg_param.flags = htod32(pfncfg_param.flags); + + if ((err = wlu_iovar_set(wl, "pfn_cfg", &pfncfg_param, + sizeof(wl_pfn_cfg_t)))) { + fprintf(stderr, "pfn_cfg fail\n"); + return err; + } + + return 0; +} + +static int +wl_pfn(void *wl, cmd_t *cmd, char **argv) +{ + int err, val; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { + val = atoi(*argv); + err = wlu_iovar_setint(wl, "pfn", (val ? 1 : 0)); + } else { + err = wlu_iovar_getint(wl, "pfn", &val); + if (!err) + wl_printint(val); + } + + return err; +} +#define WL_PFN_BESTNET_LEN 1024 + +static int +wl_pfnbest(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_pfn_scanresults_t *bestnet; + wl_pfn_net_info_t *netinfo; + uint32 i, j; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { + fprintf(stderr, "Invalid parameter %s\n", *argv); + return BCME_USAGE_ERROR; + } + bestnet = (wl_pfn_scanresults_t *)malloc(WL_PFN_BESTNET_LEN); + if (bestnet == NULL) { + fprintf(stderr, "Failed to allocate buffer of %d bytes\n", WL_PFN_BESTNET_LEN); + return BCME_NOMEM; + } + + bzero(bestnet, WL_PFN_BESTNET_LEN); + while (bestnet->status != PFN_COMPLETE) { + if ((err = wlu_iovar_get(wl, "pfnbest", (void *)bestnet, WL_PFN_BESTNET_LEN))) { + fprintf(stderr, "pfnbest fail\n"); + free(bestnet); + return err; + } + if (bestnet->count > + (WL_PFN_BESTNET_LEN / sizeof(wl_pfn_net_info_t))) + { + fprintf(stderr, "invalid data\n"); + free(bestnet); + return -1; + } + + printf("ver %d, status %d, count %d\n", + bestnet->version, bestnet->status, bestnet->count); + netinfo = bestnet->netinfo; + for (i = 0; i < bestnet->count; i++) { + for (j = 0; j < netinfo->pfnsubnet.SSID_len; j++) + printf("%c", netinfo->pfnsubnet.SSID[j]); + printf("\n"); + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", + netinfo->pfnsubnet.BSSID.octet[0], + netinfo->pfnsubnet.BSSID.octet[1], + netinfo->pfnsubnet.BSSID.octet[2], + netinfo->pfnsubnet.BSSID.octet[3], + netinfo->pfnsubnet.BSSID.octet[4], + netinfo->pfnsubnet.BSSID.octet[5]); + printf("channel: %d, RSSI: %d, timestamp: %d\n", + netinfo->pfnsubnet.channel, netinfo->RSSI, netinfo->timestamp); + netinfo++; + } + } + + free(bestnet); + return 0; +} + +static int +wl_pfnlbest(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_pfn_lscanresults_t *bestnet; + wl_pfn_lnet_info_t *netinfo; + uint32 i, j; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { + fprintf(stderr, "Invalid parameter %s\n", *argv); + return -1; + } + bestnet = (wl_pfn_lscanresults_t *)malloc(WL_PFN_BESTNET_LEN); + if (bestnet == NULL) { + fprintf(stderr, "Failed to allocate buffer of %d bytes\n", WL_PFN_BESTNET_LEN); + return -1; + } + bzero(bestnet, WL_PFN_BESTNET_LEN); + while (bestnet->status == PFN_INCOMPLETE) { + if ((err = wlu_iovar_get(wl, "pfnlbest", (void *)bestnet, WL_PFN_BESTNET_LEN))) { + fprintf(stderr, "pfnbest fail\n"); + return err; + } + printf("ver %d, status %d, count %d\n", + bestnet->version, bestnet->status, bestnet->count); + netinfo = bestnet->netinfo; + for (i = 0; i < bestnet->count; i++) { + for (j = 0; j < netinfo->pfnsubnet.SSID_len; j++) + printf("%c", netinfo->pfnsubnet.SSID[j]); + printf("\n"); + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", + netinfo->pfnsubnet.BSSID.octet[0], + netinfo->pfnsubnet.BSSID.octet[1], + netinfo->pfnsubnet.BSSID.octet[2], + netinfo->pfnsubnet.BSSID.octet[3], + netinfo->pfnsubnet.BSSID.octet[4], + netinfo->pfnsubnet.BSSID.octet[5]); + printf("channel: %d, flags: %d, RSSI: %d, timestamp: %d\n", + netinfo->pfnsubnet.channel, netinfo->flags, + netinfo->RSSI, netinfo->timestamp); + printf("RTT0: %d, RTT1: %d\n", netinfo->rtt0, netinfo->rtt1); + netinfo++; + } + } + + free(bestnet); + return 0; +} + +static int +wl_pfn_suspend(void *wl, cmd_t *cmd, char **argv) +{ + int err, val; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { + val = atoi(*argv); + err = wlu_iovar_setint(wl, "pfn_suspend", (val ? 1 : 0)); + } else { + err = wlu_iovar_getint(wl, "pfn_suspend", &val); + if (!err) + wl_printint(val); + } + + return err; +} + +static int +wl_pfn_mem(void *wl, cmd_t *cmd, char **argv) +{ + int err, val; + + UNUSED_PARAMETER(cmd); + + if (*++argv && !stricmp(*argv, "bestn")) { + if (*++argv) + val = atoi(*argv); + else { + fprintf(stderr, "Missing bestn value\n"); + return -1; + } + } else { + fprintf(stderr, "Missing bestn option\n"); + return -1; + } + + err = wlu_iovar_setint(wl, "pfnmem", val); + if (err) { + fprintf(stderr, "pfnmem set wrong!\n"); + return err; + } + + err = wlu_iovar_getint(wl, "pfnmem", &val); + if (!err) + wl_printint(val); + else + fprintf(stderr, "pfnmem get wrong!\n"); + return err; +} + +static void +wl_pfn_printnet(wl_pfn_scanresults_t *ptr, int event_type) +{ + wl_pfn_net_info_t *netinfo = ptr->netinfo; + uint32 i, j; + + if (WLC_E_PFN_NET_FOUND == event_type) { + printf("WLC_E_PFN_NET_FOUND:\n"); + } else if (WLC_E_PFN_NET_LOST == event_type) { + printf("WLC_E_PFN_NET_LOST:\n"); + } else if (WLC_E_PFN_BSSID_NET_FOUND == event_type) { + printf("WLC_E_PFN_BSSID_NET_FOUND:\n"); + } else if (WLC_E_PFN_BSSID_NET_LOST == event_type) { + printf("WLC_E_PFN_BSSID_NET_LOST:\n"); + } else { + return; + } + printf("ver %d, status %d, count %d\n", + ptr->version, ptr->status, ptr->count); + for (i = 0; i < ptr->count; i++) { + printf("%d. ", i + 1); + for (j = 0; j < netinfo->pfnsubnet.SSID_len; j++) + printf("%c", netinfo->pfnsubnet.SSID[j]); + printf("\n"); + printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", + netinfo->pfnsubnet.BSSID.octet[0], + netinfo->pfnsubnet.BSSID.octet[1], + netinfo->pfnsubnet.BSSID.octet[2], + netinfo->pfnsubnet.BSSID.octet[3], + netinfo->pfnsubnet.BSSID.octet[4], + netinfo->pfnsubnet.BSSID.octet[5]); + printf("channel %d, RSSI %d, timestamp %d\n", + netinfo->pfnsubnet.channel, netinfo->RSSI, netinfo->timestamp); + + netinfo++; + } +} + +static int +wl_pfn_event_check(void *wl, cmd_t *cmd, char **argv) +{ + int fd, err; + struct sockaddr_ll sll; + struct ifreq ifr; + char ifnames[IFNAMSIZ] = {"eth1"}; + bcm_event_t * event; + char data[512]; + int event_type; + struct ether_addr *addr; + char eabuf[ETHER_ADDR_STR_LEN]; + wl_pfn_scanresults_t *ptr; + wl_pfn_net_info_t *info; + uint32 i, j; + uint32 foundcnt, lostcnt; + + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(cmd); + + /* Override default ifname explicitly or implicitly */ + if (*++argv) { + if (strlen(*argv) >= IFNAMSIZ) { + printf("Interface name %s too long\n", *argv); + return -1; + } + strncpy(ifnames, *argv, IFNAMSIZ); + } else if (wl) { + strncpy(ifnames, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1)); + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifnames, IFNAMSIZ); + + fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM)); + if (fd < 0) { + printf("Cannot create socket %d\n", fd); + return -1; + } + + err = ioctl(fd, SIOCGIFINDEX, &ifr); + if (err < 0) { + printf("Cannot get index %d\n", err); + return -1; + } + + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = hton16(ETHER_TYPE_BRCM); + sll.sll_ifindex = ifr.ifr_ifindex; + err = bind(fd, (struct sockaddr *)&sll, sizeof(sll)); + if (err < 0) { + printf("Cannot get index %d\n", err); + return -1; + } + + while (1) { + recv(fd, data, sizeof(data), 0); + event = (bcm_event_t *)data; + addr = (struct ether_addr *)&(event->event.addr); + + event_type = ntoh32(event->event.event_type); + + if (addr != NULL) { + sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x", + (uchar)addr->octet[0]&0xff, + (uchar)addr->octet[1]&0xff, + (uchar)addr->octet[2]&0xff, + (uchar)addr->octet[3]&0xff, + (uchar)addr->octet[4]&0xff, + (uchar)addr->octet[5]&0xff); + } + + if (ntoh32(event->event.datalen)) { + if (WLC_E_PFN_SCAN_COMPLETE == event_type) { + ptr = (wl_pfn_scanresults_t *)(data + sizeof(bcm_event_t)); + info = ptr->netinfo; + foundcnt = ptr->count & 0xffff; + lostcnt = ptr->count >> 16; + printf("ver %d, status %d, found %d, lost %d\n", + ptr->version, ptr->status, foundcnt, lostcnt); + if (foundcnt) + printf("Network found:\n"); + for (i = 0; i < foundcnt; i++) { + printf("%d. ", i + 1); + for (j = 0; j < info->pfnsubnet.SSID_len; j++) + printf("%c", info->pfnsubnet.SSID[j]); + printf("\n"); + printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", + info->pfnsubnet.BSSID.octet[0], + info->pfnsubnet.BSSID.octet[1], + info->pfnsubnet.BSSID.octet[2], + info->pfnsubnet.BSSID.octet[3], + info->pfnsubnet.BSSID.octet[4], + info->pfnsubnet.BSSID.octet[5]); + printf("channel %d, RSSI %d, timestamp %d\n", + info->pfnsubnet.channel, info->RSSI, info->timestamp); + info++; + } + if (lostcnt) + printf("Network lost:\n"); + for (i = 0; i < lostcnt; i++) { + printf("%d. ", i + 1); + for (j = 0; j < info->pfnsubnet.SSID_len; j++) + printf("%c", info->pfnsubnet.SSID[j]); + printf("\n"); + printf("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", + info->pfnsubnet.BSSID.octet[0], + info->pfnsubnet.BSSID.octet[1], + info->pfnsubnet.BSSID.octet[2], + info->pfnsubnet.BSSID.octet[3], + info->pfnsubnet.BSSID.octet[4], + info->pfnsubnet.BSSID.octet[5]); + printf("channel %d, RSSI %d, timestamp %d\n", + info->pfnsubnet.channel, info->RSSI, info->timestamp); + info++; + } + } else if ((WLC_E_PFN_NET_FOUND == event_type) || + (WLC_E_PFN_NET_LOST == event_type) || + (WLC_E_PFN_BSSID_NET_FOUND == event_type) || + (WLC_E_PFN_BSSID_NET_LOST == event_type)) { + wl_pfn_printnet( + (wl_pfn_scanresults_t *)(data + sizeof(bcm_event_t)), + event_type); + } + + if (WLC_E_LINK == event_type || WLC_E_NDIS_LINK == event_type) { + if (ntoh16(event->event.flags) & WLC_EVENT_MSG_LINK) + printf("MACEVENT Link up :%s\n", eabuf); + else + printf("MACEVENT Link down :%s\n", eabuf); + } + } else { + if (WLC_E_PFN_SCAN_NONE == event_type) { + printf("Got WLC_E_PFN_SCAN_NONE\n"); + } + if (WLC_E_PFN_SCAN_ALLGONE == event_type) { + printf("Got WLC_E_PFN_SCAN_ALLGONE\n"); + } + if (WLC_E_PFN_BEST_BATCHING == event_type) { + printf("Got WLC_E_PFN_BEST_BATCHING\n"); + } + } + } + return (0); +} + +#define ESCAN_EVENTS_BUFFER_SIZE 2048 + +static int +wl_escan_event_check(void *wl, cmd_t *cmd, char **argv) +{ + int fd, err, i, octets; + struct sockaddr_ll sll; + struct ifreq ifr; + char ifnames[IFNAMSIZ] = {"eth1"}; + uint8 print_flag = 4; + bcm_event_t * event; + uint32 status; + char* data; + int event_type; + uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */ + + wl_escan_result_t* escan_data; + + + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(cmd); + + if (*++argv) { + if (strlen(*argv) >= IFNAMSIZ) { + printf("Interface name %s too long\n", *argv); + return -1; + } + strncpy(ifnames, *argv, (IFNAMSIZ - 1)); + if (*++argv) + print_flag = atoi(*argv); + } else if (wl) { + strncpy(ifnames, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1)); + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1)); + + memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN); + event_inds_mask[WLC_E_ESCAN_RESULT / 8] |= 1 << (WLC_E_ESCAN_RESULT % 8); + if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) + return (err); + + fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM)); + if (fd < 0) { + printf("Cannot create socket %d\n", fd); + return -1; + } + + err = ioctl(fd, SIOCGIFINDEX, &ifr); + if (err < 0) { + printf("Cannot get index %d\n", err); + return -1; + } + + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = hton16(ETHER_TYPE_BRCM); + sll.sll_ifindex = ifr.ifr_ifindex; + err = bind(fd, (struct sockaddr *)&sll, sizeof(sll)); + if (err < 0) { + printf("Cannot bind %d\n", err); + return -1; + } + + data = (char*)malloc(ESCAN_EVENTS_BUFFER_SIZE); + + if (data == NULL) { + printf("Cannot not allocate %d bytes for events receive buffer\n", + ESCAN_EVENTS_BUFFER_SIZE); + return BCME_NOMEM; + } + + while (1) { + octets = recv(fd, data, ESCAN_EVENTS_BUFFER_SIZE, 0); + event = (bcm_event_t *)data; + + event_type = ntoh32(event->event.event_type); + + if ((event_type == WLC_E_ESCAN_RESULT) && (octets > 0)) { + escan_data = (wl_escan_result_t*)&data[sizeof(bcm_event_t)]; + status = ntoh32(event->event.status); + + if (print_flag & 1) + printf("WLC_E_ESCAN_RESULT, (sync_id,status) = (%d,%d)\n", + escan_data->sync_id, status); + + if (print_flag & 2) + for (i = 0; i < escan_data->bss_count; i++) + dump_bss_info(&escan_data->bss_info[i]); + + if (print_flag & 4) { + if (status == WLC_E_STATUS_PARTIAL) { + printf("sync_id: %d, WLC_E_STATUS_PARTIAL\n", + escan_data->sync_id); + for (i = 0; i < escan_data->bss_count; i++) + dump_bss_info(&escan_data->bss_info[i]); + } + if (status == WLC_E_STATUS_SUCCESS) + printf("sync_id: %d, WLC_E_STATUS_SUCCESS => SCAN_DONE\n", + escan_data->sync_id); + if ((status != WLC_E_STATUS_SUCCESS) && + (status != WLC_E_STATUS_PARTIAL)) + printf("sync_id: %d, status:%d, misc. error/abort\n", + escan_data->sync_id, status); + } + + if (print_flag & 8) { + int remainder = escan_data->bss_info[0].ie_length; + int processed = sizeof(wl_escan_result_t); + uint8* iebuf = &((uint8*)escan_data)[sizeof(wl_escan_result_t)]; + + if (status != WLC_E_STATUS_PARTIAL) + continue; + + printf("MOREINFO: (sync_id,buflen,ielen) = (%d,%d,%d)\n", + escan_data->sync_id, + escan_data->buflen, + escan_data->bss_info[0].ie_length); + + /* do a tlv sanity check */ + while (remainder > 0) { + processed += 1 + 1 + iebuf[1]; + remainder -= 1 + 1 + iebuf[1]; + iebuf += 1 + 1 + iebuf[1]; + } + if (processed >= ESCAN_EVENTS_BUFFER_SIZE) + break; + + if (remainder != 0) { + printf("ERROR: IE tlv sanity check failed for " + "(ssid,sync_id,buflen,ielen,remainder) = " + "(%s,%d,%d,%d,%d)\n", + escan_data->bss_info[0].SSID, + escan_data->sync_id, escan_data->buflen, + escan_data->bss_info[0].ie_length, + remainder); + iebuf = &((uint8*)escan_data)[sizeof(wl_escan_result_t)]; + if ((escan_data->buflen - sizeof(wl_escan_result_t)) > 0) { + for (i = 0; + i < (int)(escan_data->buflen - + sizeof(wl_escan_result_t)); + i++) { + printf("%02x ", iebuf[i]); + } + printf("\n"); + } + } + } + } + } + + /* if we ever reach here */ + free(data); + + return (0); +} + +struct escan_bss { + struct escan_bss *next; + wl_bss_info_t bss[1]; +}; +#define ESCAN_BSS_FIXED_SIZE 4 + +static int +wl_escanresults(void *wl, cmd_t *cmd, char **argv) +{ + int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)) + + (WL_NUMCHANNELS * sizeof(uint16)); + wl_escan_params_t *params; + int fd, err, octets; + struct sockaddr_ll sll; + struct ifreq ifr; + char ifnames[IFNAMSIZ] = {"eth1"}; + bcm_event_t *event; + uint32 status; + char *data; + int event_type; + uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */ + wl_escan_result_t *escan_data; + struct escan_bss *escan_bss_head = NULL; + struct escan_bss *escan_bss_tail = NULL; + struct escan_bss *result; + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + params = (wl_escan_params_t*)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Error allocating %d bytes for scan params\n", params_size); + return BCME_NOMEM; + } + memset(params, 0, params_size); + + err = wl_scan_prep(wl, cmd, argv, ¶ms->params, ¶ms_size); + if (err) + goto exit2; + + memset(&ifr, 0, sizeof(ifr)); + if (wl) + strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1)); + else + strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1)); + + memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN); + + /* Read the event mask from driver and unmask the event WLC_E_ESCAN_RESULT */ + if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) + goto exit2; + event_inds_mask[WLC_E_ESCAN_RESULT / 8] |= 1 << (WLC_E_ESCAN_RESULT % 8); + if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) + goto exit2; + + fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM)); + if (fd < 0) { + printf("Cannot create socket %d\n", fd); + err = -1; + goto exit2; + } + + err = ioctl(fd, SIOCGIFINDEX, &ifr); + if (err < 0) { + printf("Cannot get index %d\n", err); + goto exit2; + } + + /* bind the socket first before starting escan so we won't miss any event */ + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = hton16(ETHER_TYPE_BRCM); + sll.sll_ifindex = ifr.ifr_ifindex; + err = bind(fd, (struct sockaddr *)&sll, sizeof(sll)); + if (err < 0) { + printf("Cannot bind %d\n", err); + goto exit2; + } + + params->version = htod32(ESCAN_REQ_VERSION); + params->action = htod16(WL_SCAN_ACTION_START); + + srand((unsigned)time(NULL)); + params->sync_id = htod16(rand() & 0xffff); + + params_size += OFFSETOF(wl_escan_params_t, params); + err = wlu_iovar_setbuf(wl, "escan", params, params_size, buf, WLC_IOCTL_MAXLEN); + + data = (char*)malloc(ESCAN_EVENTS_BUFFER_SIZE); + + if (data == NULL) { + printf("Cannot not allocate %d bytes for events receive buffer\n", + ESCAN_EVENTS_BUFFER_SIZE); + err = BCME_NOMEM; + goto exit2; + } + + /* receive scan result */ + while (1) { + octets = recv(fd, data, ESCAN_EVENTS_BUFFER_SIZE, 0); + event = (bcm_event_t *)data; + event_type = ntoh32(event->event.event_type); + + if ((event_type == WLC_E_ESCAN_RESULT) && (octets > 0)) { + escan_data = (wl_escan_result_t*)&data[sizeof(bcm_event_t)]; + status = ntoh32(event->event.status); + + if (status == WLC_E_STATUS_PARTIAL) { + wl_bss_info_t *bi = &escan_data->bss_info[0]; + wl_bss_info_t *bss; + + /* check if we've received info of same BSSID */ + for (result = escan_bss_head; result; result = result->next) { + bss = result->bss; + + if (!wlu_bcmp(bi->BSSID.octet, bss->BSSID.octet, + ETHER_ADDR_LEN) && + CHSPEC_BAND(bi->chanspec) == + CHSPEC_BAND(bss->chanspec) && + bi->SSID_len == bss->SSID_len && + !wlu_bcmp(bi->SSID, bss->SSID, bi->SSID_len)) + break; + } + + if (!result) { + /* New BSS. Allocate memory and save it */ + struct escan_bss *ebss = malloc(ESCAN_BSS_FIXED_SIZE + + bi->length); + + if (!ebss) { + perror("can't allocate memory for bss"); + goto exit1; + } + + ebss->next = NULL; + memcpy(&ebss->bss, bi, bi->length); + if (escan_bss_tail) { + escan_bss_tail->next = ebss; + } + else { + escan_bss_head = ebss; + } + escan_bss_tail = ebss; + } + else if (bi->RSSI != WLC_RSSI_INVALID) { + /* We've got this BSS. Update rssi if necessary */ + if (((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) && + ((bss->RSSI == WLC_RSSI_INVALID) || + (bss->RSSI < bi->RSSI))) { + /* preserve max RSSI if the measurements are + * both on-channel or both off-channel + */ + bss->RSSI = bi->RSSI; + bss->SNR = bi->SNR; + bss->phy_noise = bi->phy_noise; + } else if ((bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && + (bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { + /* preserve the on-channel rssi measurement + * if the new measurement is off channel + */ + bss->RSSI = bi->RSSI; + bss->SNR = bi->SNR; + bss->phy_noise = bi->phy_noise; + bss->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; + } + } + } + else if (status == WLC_E_STATUS_SUCCESS) { + /* Escan finished. Let's go dump the results. */ + break; + } + else { + printf("sync_id: %d, status:%d, misc. error/abort\n", + escan_data->sync_id, status); + goto exit1; + } + } + } + + /* print scan results */ + for (result = escan_bss_head; result; result = result->next) { + dump_bss_info(result->bss); + } + +exit1: + /* free scan results */ + result = escan_bss_head; + while (result) { + struct escan_bss *tmp = result->next; + free(result); + result = tmp; + } + + free(data); + close(fd); +exit2: + free(params); + + /* Read the event mask from driver and mask the event WLC_E_ESCAN_RESULT */ + if (!(err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) { + event_inds_mask[WLC_E_ESCAN_RESULT / 8] &= (~(1 << (WLC_E_ESCAN_RESULT % 8))); + err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN); + } + + return err; +} + +static int +wl_event_filter(void *wl, cmd_t *cmd, char **argv) +{ + int err; + uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */ + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN); + + /* Register for following event for pfn */ + event_inds_mask[WLC_E_LINK / 8] |= 1 << (WLC_E_LINK % 8); + event_inds_mask[WLC_E_PFN_NET_FOUND / 8] |= 1 << (WLC_E_PFN_NET_FOUND % 8); + event_inds_mask[WLC_E_PFN_NET_LOST / 8] |= 1 << (WLC_E_PFN_NET_LOST % 8); + event_inds_mask[WLC_E_PFN_SCAN_NONE/ 8] |= 1 << (WLC_E_PFN_SCAN_NONE % 8); + event_inds_mask[WLC_E_PFN_SCAN_ALLGONE/ 8] |= 1 << (WLC_E_PFN_SCAN_ALLGONE % 8); + + if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) + return (err); + + return (0); +} +#endif /* WLPFN */ + +#ifdef WLP2PO +#define UPNP_QUERY_VERSION "0x10" +#define BCM_SVC_RPOTYPE_ALL 0 +#define BCM_SVC_RPOTYPE_BONJOUR 1 +#define BCM_SVC_RPOTYPE_UPNP 2 +#define BCM_SVC_RPOTYPE_WSD 3 +#define BCM_SVC_RPOTYPE_VENDOR 255 + +static int +wl_p2po_listen(void *wl, cmd_t *cmd, char **argv) +{ + int err, params_size; + wl_p2po_listen_t params; + + UNUSED_PARAMETER(cmd); + + if (!argv[1] || !argv[2]) { + params.period = 0; + params.interval = 0; + } + else { + params.period = atoi(argv[1]); + params.interval = atoi(argv[2]); + } + params_size = sizeof(wl_p2po_listen_t); + + err = wlu_iovar_set(wl, "p2po_listen", ¶ms, params_size); + + return err; +} + +static int +hexstr2hex(char *str) +{ + int i, len; + char hexstr[3]; + char *src; + + src = str; + len = strlen(str)/2; + + for (i = 0; i < len; i++) { + hexstr[0] = src[0]; + hexstr[1] = src[1]; + hexstr[2] = '\0'; + str[i] = strtoul(hexstr, NULL, 16); + src += 2; + } + + return i; +} + +static int +wl_p2po_addsvc(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int protocol, query_len, response_len, params_size; + char *query, *response; + wl_p2po_qr_t *params; + + UNUSED_PARAMETER(cmd); + + if (!argv[1] || !argv[2] || !argv[3]) { + fprintf(stderr, "Too few arguments\n"); + return BCME_USAGE_ERROR; + } + + protocol = atoi(argv[1]); + if (protocol == BCM_SVC_RPOTYPE_BONJOUR) { + query = argv[2]; + response = argv[3]; + query_len = hexstr2hex(query); + response_len = hexstr2hex(response); + } else if (protocol == BCM_SVC_RPOTYPE_UPNP) { + if (memcmp(argv[2], UPNP_QUERY_VERSION, strlen(UPNP_QUERY_VERSION)) != 0 || + memcmp(argv[3], UPNP_QUERY_VERSION, strlen(UPNP_QUERY_VERSION)) != 0) { + fprintf(stderr, "UPnP query/response string must start with 0x10"); + return BCME_USAGE_ERROR; + } + query = argv[2] + strlen(UPNP_QUERY_VERSION) - 1; + response = argv[3] + strlen(UPNP_QUERY_VERSION) - 1; + query[0] = strtoul(UPNP_QUERY_VERSION, NULL, 16); + response[0] = strtoul(UPNP_QUERY_VERSION, NULL, 16); + + query_len = strlen(query); + response_len = strlen(response); + } + else { + fprintf(stderr, "<protocol> should be <1|2>\n"); + return BCME_USAGE_ERROR; + } + + params_size = sizeof(wl_p2po_qr_t) + query_len + response_len - 1; + params = (wl_p2po_qr_t *)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Not enough memory\n"); + return BCME_NOMEM; + } + + params->protocol = protocol; + params->query_len = query_len; + params->response_len = response_len; + memcpy(params->qrbuf, query, query_len); + memcpy(params->qrbuf+query_len, response, response_len); + + err = wlu_iovar_setbuf(wl, "p2po_addsvc", params, params_size, buf, WLC_IOCTL_MAXLEN); + + free(params); + + return err; +} + +static int +wl_p2po_delsvc(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int protocol, query_len, params_size; + char *query; + wl_p2po_qr_t *params; + + UNUSED_PARAMETER(cmd); + + if (!argv[1] || (*argv[1] != '0' && !argv[2])) { + fprintf(stderr, "Too few arguments\n"); + return BCME_USAGE_ERROR; + } + + if (*argv[1] == '0') { + protocol = 0; + query_len = 0; + } + else { + protocol = atoi(argv[1]); + if (protocol == BCM_SVC_RPOTYPE_BONJOUR) { + query = argv[2]; + query_len = hexstr2hex(query); + } else if (protocol == BCM_SVC_RPOTYPE_UPNP) { + if (memcmp(argv[2], UPNP_QUERY_VERSION, strlen(UPNP_QUERY_VERSION)) != 0) { + fprintf(stderr, "UPnP query string must start with 0x10"); + return BCME_USAGE_ERROR; + } + query = argv[2] + strlen(UPNP_QUERY_VERSION) - 1; + query[0] = strtoul(UPNP_QUERY_VERSION, NULL, 16); + + query_len = strlen(query); + } + else { + fprintf(stderr, "<protocol> should be <1|2>\n"); + return BCME_USAGE_ERROR; + } + } + + params_size = sizeof(wl_p2po_qr_t) + (query_len ? query_len - 1 : 0); + params = (wl_p2po_qr_t *)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Not enough memory\n"); + return BCME_NOMEM; + } + + params->protocol = protocol; + params->query_len = query_len; + if (query_len) + memcpy(params->qrbuf, query, query_len); + + err = wlu_iovar_set(wl, "p2po_delsvc", params, params_size); + + free(params); + + return err; +} + +static int +wl_p2po_sd_reqresp(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int transaction_id, protocol, query_len, params_size; + char *query; + wl_p2po_qr_t *params; + + UNUSED_PARAMETER(cmd); + + if (!argv[1] || !argv[2]) { + fprintf(stderr, "Too few arguments\n"); + return BCME_USAGE_ERROR; + } + + transaction_id = atoi(argv[1]); + if (transaction_id < 0 || transaction_id > 255) { + fprintf(stderr, "<transaction id> should be between 0 and 255\n"); + return BCME_USAGE_ERROR; + } + + protocol = atoi(argv[2]); + if (!argv[3]) { + /* find everything for protocol */ + query_len = 0; + } else if (protocol == BCM_SVC_RPOTYPE_BONJOUR) { + query = argv[3]; + query_len = hexstr2hex(query); + } else if (protocol == BCM_SVC_RPOTYPE_UPNP) { + if (memcmp(argv[3], UPNP_QUERY_VERSION, strlen(UPNP_QUERY_VERSION)) != 0) { + fprintf(stderr, "UPnP query string must start with 0x10"); + return BCME_USAGE_ERROR; + } + query = argv[3] + strlen(UPNP_QUERY_VERSION) - 1; + query[0] = strtoul(UPNP_QUERY_VERSION, NULL, 16); + + query_len = strlen(query); + } else { + fprintf(stderr, "<protocol> should be <0|1|2>\n"); + return BCME_USAGE_ERROR; + } + + params_size = sizeof(wl_p2po_qr_t) + (query_len ? query_len - 1 : 0); + params = (wl_p2po_qr_t *)malloc(params_size); + if (params == NULL) { + fprintf(stderr, "Not enough memory\n"); + return BCME_NOMEM; + } + + params->transaction_id = transaction_id; + params->protocol = protocol; + params->query_len = query_len; + if (query_len) + memcpy(params->qrbuf, query, query_len); + + err = wlu_iovar_set(wl, "p2po_sd_req_resp", params, params_size); + + free(params); + + return err; +} + +static int +wl_p2po_listen_channel(void *wl, cmd_t *cmd, char **argv) +{ + uint32 val; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { + val = atoi(*argv); + return wlu_iovar_setint(wl, "p2po_listen_channel", val); + } + + fprintf(stderr, "No channel is specified\n"); + return BCME_USAGE_ERROR; +} + +static int +wl_p2po_stop(void *wl, cmd_t *cmd, char **argv) +{ + uint32 val; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { + val = atoi(*argv); + return wlu_iovar_setint(wl, "p2po_stop", val); + } + + fprintf(stderr, "Please specify - 0:stop, 1:pause\n"); + return BCME_USAGE_ERROR; +} + +#define P2PO_EVENTS_BUFFER_SIZE 2048 + +static int +wl_p2po_results(void *wl, cmd_t *cmd, char **argv) +{ + int fd, err, octets; + struct sockaddr_ll sll; + struct ifreq ifr; + char ifnames[IFNAMSIZ] = {"eth1"}; + char *data; + uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */ + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + memset(&ifr, 0, sizeof(ifr)); + if (wl) + strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1)); + else + strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1)); + + memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN); + event_inds_mask[WLC_E_SERVICE_FOUND / 8] |= 1 << (WLC_E_SERVICE_FOUND % 8); + event_inds_mask[WLC_E_GAS_FRAGMENT_RX / 8] |= 1 << (WLC_E_GAS_FRAGMENT_RX % 8); + if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) + goto exit2; + + fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM)); + if (fd < 0) { + printf("Cannot create socket %d\n", fd); + err = -1; + goto exit2; + } + + err = ioctl(fd, SIOCGIFINDEX, &ifr); + if (err < 0) { + printf("Cannot get index %d\n", err); + goto exit1; + } + + /* bind the socket first before starting so we won't miss any event */ + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = hton16(ETHER_TYPE_BRCM); + sll.sll_ifindex = ifr.ifr_ifindex; + err = bind(fd, (struct sockaddr *)&sll, sizeof(sll)); + if (err < 0) { + printf("Cannot bind %d\n", err); + goto exit1; + } + + data = (char*)malloc(P2PO_EVENTS_BUFFER_SIZE); + + if (data == NULL) { + printf("Cannot not allocate %d bytes for events receive buffer\n", + P2PO_EVENTS_BUFFER_SIZE); + err = BCME_NOMEM; + goto exit1; + } + + /* receive result */ + while (1) { + bcm_event_t *bcm_event; + int event_type; + + octets = recv(fd, data, P2PO_EVENTS_BUFFER_SIZE, 0); + bcm_event = (bcm_event_t *)data; + event_type = ntoh32(bcm_event->event.event_type); + + if (octets >= (int)sizeof(bcm_event_t)) { + if (event_type == WLC_E_SERVICE_FOUND) { + uint32 status = ntoh32(bcm_event->event.status); + wl_event_sd_t *sd_data = + (wl_event_sd_t *)&data[sizeof(bcm_event_t)]; + + sd_data->channel = dtoh16(sd_data->channel); + + printf("WLC_E_SERVICE_FOUND: %s\n", + status == WLC_E_STATUS_PARTIAL ? "WLC_E_STATUS_PARTIAL" : + status == WLC_E_STATUS_SUCCESS ? "WLC_E_STATUS_SUCCESS" : + status == WLC_E_STATUS_FAIL ? "WLC_E_STATUS_FAIL" : + "unknown"); + printf(" channel = %d\n", sd_data->channel); + printf(" peer = %s\n", + wl_ether_etoa(&bcm_event->event.addr)); + if (status == WLC_E_STATUS_SUCCESS) { + wl_sd_tlv_t *tlv; + int i; + + tlv = sd_data->tlv; + for (i = 0; i < sd_data->count; i++) { + printf(" [TLV %d]\n", i); + tlv->length = dtoh16(tlv->length); + printf(" protocol type = %s\n", + tlv->protocol == 0 ? "ALL" : + tlv->protocol == BCM_SVC_RPOTYPE_BONJOUR ? + "BONJOUR" : + tlv->protocol == BCM_SVC_RPOTYPE_UPNP ? + "UPnP" : + tlv->protocol == BCM_SVC_RPOTYPE_WSD ? + "WS-Discovery" : + tlv->protocol == BCM_SVC_RPOTYPE_VENDOR ? + "Vendor specific" : "Unknown"); + printf(" transaction id = %u\n", + tlv->transaction_id); + printf(" status code = %u\n", + tlv->status_code); + printf(" length = %u\n", tlv->length); + wl_hexdump(tlv->data, tlv->length); + + tlv = (wl_sd_tlv_t *)((void *)tlv + tlv->length + + OFFSETOF(wl_sd_tlv_t, data)); + } + } + else { + /* fragments */ + } + } + } + } + + free(data); +exit1: + close(fd); +exit2: + return err; +} +#endif /* WLP2PO */ + +#ifdef WLANQPO + +#define ANQPO_EVENTS_BUFFER_SIZE 2048 + +static int +wl_anqpo_set(void *wl, cmd_t *cmd, char **argv) +{ + int err = BCME_USAGE_ERROR, malloc_size; + char *buffer; + wl_anqpo_set_t *set; + int length; + + UNUSED_PARAMETER(cmd); + + malloc_size = OFFSETOF(wl_anqpo_set_t, query_data) + + (ANQPO_MAX_QUERY_SIZE * sizeof(uint8)); + buffer = malloc(malloc_size); + if (buffer == NULL) { + fprintf(stderr, "Not enough memory\n"); + return BCME_NOMEM; + } + memset(buffer, 0, malloc_size); + set = (wl_anqpo_set_t *)buffer; + /* parameters not configured by default */ + set->max_retransmit = -1; + set->response_timeout = -1; + set->max_comeback_delay = -1; + set->max_retries = -1; + + while (*++argv) { + if (!stricmp(*argv, "max_retransmit")) { + if (*++argv) + set->max_retransmit = atoi(*argv); + else { + fprintf(stderr, "Missing max retransmit\n"); + err = BCME_USAGE_ERROR; + goto done; + } + } + else if (!stricmp(*argv, "response_timeout")) { + if (*++argv) + set->response_timeout = atoi(*argv); + else { + fprintf(stderr, "Missing response timeout\n"); + err = BCME_USAGE_ERROR; + goto done; + } + } + else if (!stricmp(*argv, "max_comeback_delay")) { + if (*++argv) + set->max_comeback_delay = atoi(*argv); + else { + fprintf(stderr, "Missing max comeback delay\n"); + err = BCME_USAGE_ERROR; + goto done; + } + } + else if (!stricmp(*argv, "max_retries")) { + if (*++argv) + set->max_retries = atoi(*argv); + else { + fprintf(stderr, "Missing retries\n"); + err = BCME_USAGE_ERROR; + goto done; + } + } + else if (!stricmp(*argv, "query")) { + if (*++argv) { + if ((set->query_len = hexstr2hex(*argv)) == 0) { + fprintf(stderr, "Invalid ANQP query\n"); + err = BCME_USAGE_ERROR; + goto done; + } + if (set->query_len > ANQPO_MAX_QUERY_SIZE) { + fprintf(stderr, "ANQP query size %d exceeds %d\n", + set->query_len, ANQPO_MAX_QUERY_SIZE); + err = BCME_USAGE_ERROR; + goto done; + } + memcpy(set->query_data, *argv, set->query_len); + } + else { + fprintf(stderr, "Missing ANQP query\n"); + err = BCME_USAGE_ERROR; + goto done; + } + } + else { + fprintf(stderr, "Invalid parameter %s\n", *argv); + err = BCME_USAGE_ERROR; + goto done; + } + + } + + length = OFFSETOF(wl_anqpo_set_t, query_data) + set->query_len; + set->max_retransmit = htod16(set->max_retransmit); + set->response_timeout = htod16(set->response_timeout); + set->max_comeback_delay = htod16(set->max_comeback_delay); + set->max_retries = htod16(set->max_retries); + set->query_len = htod16(set->query_len); + + err = wlu_iovar_set(wl, cmd->name, set, length); + +done: + free(buffer); + return err; +} + +static int +wl_anqpo_stop_query(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + return wlu_iovar_set(wl, cmd->name, 0, 0); +} + +static int +wl_anqpo_start_query(void *wl, cmd_t *cmd, char **argv) +{ + int err = BCME_USAGE_ERROR, malloc_size; + char *buffer; + wl_anqpo_peer_list_t *list; + wl_anqpo_peer_t *peer; + int c; + int length; + + UNUSED_PARAMETER(cmd); + + malloc_size = OFFSETOF(wl_anqpo_peer_list_t, peer) + + (ANQPO_MAX_PEER_LIST * sizeof(wl_anqpo_peer_t)); + buffer = malloc(malloc_size); + if (buffer == NULL) { + fprintf(stderr, "Not enough memory\n"); + return BCME_NOMEM; + } + memset(buffer, 0, malloc_size); + list = (wl_anqpo_peer_list_t *)buffer; + peer = &list->peer[0]; + + c = 1; + while (argv[c] && argv[c + 1]) { + if ((peer->channel = htod16(atoi(argv[c]))) == 0) { + fprintf(stderr, "Invalid channel\n"); + err = BCME_USAGE_ERROR; + goto done; + } + if (!wl_ether_atoe(argv[c + 1], &peer->addr)) { + fprintf(stderr, "Invalid address\n"); + err = BCME_USAGE_ERROR; + goto done; + } + list->count++; + c += 2; + peer++; + } + + length = OFFSETOF(wl_anqpo_peer_list_t, peer) + + (list->count * sizeof(wl_anqpo_peer_t)); + list->count = htod16(list->count); + + err = wlu_iovar_set(wl, cmd->name, list, length); + +done: + free(buffer); + return err; +} + +static int +wl_anqpo_ignore_ssid_list(void *wl, cmd_t *cmd, char **argv) +{ + int err = BCME_USAGE_ERROR, malloc_size; + char *buffer; + wl_anqpo_ignore_ssid_list_t *list; + int length; + + UNUSED_PARAMETER(cmd); + + malloc_size = OFFSETOF(wl_anqpo_ignore_ssid_list_t, ssid) + + (ANQPO_MAX_IGNORE_SSID * (sizeof(wl_anqpo_ignore_ssid_list_t) - + OFFSETOF(wl_anqpo_ignore_ssid_list_t, ssid))); + buffer = malloc(malloc_size); + if (buffer == NULL) { + fprintf(stderr, "Not enough memory\n"); + return BCME_NOMEM; + } + memset(buffer, 0, malloc_size); + list = (wl_anqpo_ignore_ssid_list_t *)buffer; + + /* get */ + if (!argv[1]) { + int i; + + if ((err = wlu_iovar_get(wl, cmd->name, list, malloc_size)) < 0) + goto done; + list->count = dtoh16(list->count); + for (i = 0; i < list->count; i++) { + char ssidbuf[SSID_FMT_BUF_LEN]; + + wl_format_ssid(ssidbuf, list->ssid[i].SSID, list->ssid[i].SSID_len); + printf("%s\n", ssidbuf); + } + goto done; + } + + /* set */ + argv++; + if (!stricmp(*argv, "clear")) { + list->is_clear = TRUE; + } + else if (!stricmp(*argv, "set")) { + list->is_clear = TRUE; + while (*++argv) { + int len = strlen(*argv); + if (list->count > ANQPO_MAX_IGNORE_SSID) { + fprintf(stderr, "Too many BSSID\n"); + err = BCME_USAGE_ERROR; + goto done; + } + if (len > 32) { + fprintf(stderr, "SSID too long\n"); + err = BCME_USAGE_ERROR; + goto done; + } + list->ssid[list->count].SSID_len = len; + memcpy(list->ssid[list->count].SSID, *argv, len); + list->count++; + } + } + else if (!stricmp(*argv, "append")) { + while (*++argv) { + int len = strlen(*argv); + if (list->count > ANQPO_MAX_IGNORE_SSID) { + fprintf(stderr, "Too many BSSID\n"); + err = BCME_USAGE_ERROR; + goto done; + } + if (len > 32) { + fprintf(stderr, "SSID too long\n"); + err = BCME_USAGE_ERROR; + goto done; + } + list->ssid[list->count].SSID_len = len; + memcpy(list->ssid[list->count].SSID, *argv, len); + list->count++; + } + } + else { + fprintf(stderr, "Invalid parameter %s\n", *argv); + err = BCME_USAGE_ERROR; + goto done; + } + + length = OFFSETOF(wl_anqpo_ignore_ssid_list_t, ssid) + + (list->count * (sizeof(wl_anqpo_ignore_ssid_list_t) - + OFFSETOF(wl_anqpo_ignore_ssid_list_t, ssid))); + list->count = htod16(list->count); + + err = wlu_iovar_set(wl, cmd->name, list, length); + +done: + free(buffer); + return err; +} + +static int +wl_anqpo_ignore_bssid_list(void *wl, cmd_t *cmd, char **argv) +{ + int err = BCME_USAGE_ERROR, malloc_size; + char *buffer; + wl_anqpo_ignore_bssid_list_t *list; + int length; + + UNUSED_PARAMETER(cmd); + + malloc_size = OFFSETOF(wl_anqpo_ignore_bssid_list_t, bssid) + + (ANQPO_MAX_IGNORE_BSSID * (sizeof(wl_anqpo_ignore_bssid_list_t) - + OFFSETOF(wl_anqpo_ignore_bssid_list_t, bssid))); + buffer = malloc(malloc_size); + if (buffer == NULL) { + fprintf(stderr, "Not enough memory\n"); + return BCME_NOMEM; + } + memset(buffer, 0, malloc_size); + list = (wl_anqpo_ignore_bssid_list_t *)buffer; + + /* get */ + if (!argv[1]) { + int i; + + if ((err = wlu_iovar_get(wl, cmd->name, list, malloc_size)) < 0) + goto done; + list->count = dtoh16(list->count); + for (i = 0; i < list->count; i++) { + printf("%s\n", wl_ether_etoa(&list->bssid[i])); + } + goto done; + } + + /* set */ + argv++; + if (!stricmp(*argv, "clear")) { + list->is_clear = TRUE; + } + else if (!stricmp(*argv, "set")) { + list->is_clear = TRUE; + while (*++argv) { + if (list->count > ANQPO_MAX_IGNORE_BSSID) { + fprintf(stderr, "Too many BSSID\n"); + err = BCME_USAGE_ERROR; + goto done; + } + if (!wl_ether_atoe(*argv, &list->bssid[list->count])) { + fprintf(stderr, "Invalid BSSID\n"); + err = BCME_USAGE_ERROR; + goto done; + } + list->count++; + } + } + else if (!stricmp(*argv, "append")) { + while (*++argv) { + if (list->count > ANQPO_MAX_IGNORE_BSSID) { + fprintf(stderr, "Too many BSSID\n"); + err = BCME_USAGE_ERROR; + goto done; + } + if (!wl_ether_atoe(*argv, &list->bssid[list->count])) { + fprintf(stderr, "Invalid BSSID\n"); + err = BCME_USAGE_ERROR; + goto done; + } + list->count++; + } + } + else { + fprintf(stderr, "Invalid parameter %s\n", *argv); + err = BCME_USAGE_ERROR; + goto done; + } + + length = OFFSETOF(wl_anqpo_ignore_bssid_list_t, bssid) + + (list->count * (sizeof(wl_anqpo_ignore_bssid_list_t) - + OFFSETOF(wl_anqpo_ignore_bssid_list_t, bssid))); + list->count = htod16(list->count); + + err = wlu_iovar_set(wl, cmd->name, list, length); + +done: + free(buffer); + return err; +} + +static int +wl_anqpo_results(void *wl, cmd_t *cmd, char **argv) +{ + int fd, err, octets; + struct sockaddr_ll sll; + struct ifreq ifr; + char ifnames[IFNAMSIZ] = {"eth1"}; + char *data; + uint8 event_inds_mask[WL_EVENTING_MASK_LEN]; /* event bit mask */ + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + memset(&ifr, 0, sizeof(ifr)); + if (wl) + strncpy(ifr.ifr_name, ((struct ifreq *)wl)->ifr_name, (IFNAMSIZ - 1)); + else + strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1)); + + memset(event_inds_mask, '\0', WL_EVENTING_MASK_LEN); + event_inds_mask[WLC_E_GAS_FRAGMENT_RX / 8] |= 1 << (WLC_E_GAS_FRAGMENT_RX % 8); + event_inds_mask[WLC_E_GAS_COMPLETE / 8] |= 1 << (WLC_E_GAS_COMPLETE % 8); + if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) + goto exit2; + + fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM)); + if (fd < 0) { + printf("Cannot create socket %d\n", fd); + err = -1; + goto exit2; + } + + err = ioctl(fd, SIOCGIFINDEX, &ifr); + if (err < 0) { + printf("Cannot get index %d\n", err); + goto exit1; + } + + /* bind the socket first before starting so we won't miss any event */ + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = hton16(ETHER_TYPE_BRCM); + sll.sll_ifindex = ifr.ifr_ifindex; + err = bind(fd, (struct sockaddr *)&sll, sizeof(sll)); + if (err < 0) { + printf("Cannot bind %d\n", err); + goto exit1; + } + + data = (char*)malloc(ANQPO_EVENTS_BUFFER_SIZE); + + if (data == NULL) { + printf("Cannot not allocate %d bytes for events receive buffer\n", + ANQPO_EVENTS_BUFFER_SIZE); + err = BCME_NOMEM; + goto exit1; + } + + /* receive result */ + while (1) { + bcm_event_t *bcm_event; + int event_type; + + octets = recv(fd, data, ANQPO_EVENTS_BUFFER_SIZE, 0); + bcm_event = (bcm_event_t *)data; + event_type = ntoh32(bcm_event->event.event_type); + + if (octets >= (int)sizeof(bcm_event_t)) { + uint32 status = ntoh32(bcm_event->event.status); + + if (event_type == WLC_E_GAS_FRAGMENT_RX) { + wl_event_gas_t *gas_data = + (wl_event_gas_t *)&data[sizeof(bcm_event_t)]; + + gas_data->channel = dtoh16(gas_data->channel); + gas_data->status_code = dtoh16(gas_data->status_code); + gas_data->data_len = dtoh16(gas_data->data_len); + + printf("WLC_E_GAS_FRAGMENT_RX: %s\n", + status == WLC_E_STATUS_PARTIAL ? "WLC_E_STATUS_PARTIAL" : + status == WLC_E_STATUS_SUCCESS ? "WLC_E_STATUS_SUCCESS" : + status == WLC_E_STATUS_FAIL ? "WLC_E_STATUS_FAIL" : + "unknown"); + printf(" channel = %d\n", gas_data->channel); + printf(" peer = %s\n", + wl_ether_etoa(&bcm_event->event.addr)); + printf(" dialog token = 0x%02x (%d)\n", + gas_data->dialog_token, gas_data->dialog_token); + printf(" fragment id = 0x%02x\n", gas_data->fragment_id); + printf(" GAS status = %s\n", + gas_data->status_code == DOT11_SC_SUCCESS ? "SUCCESS" : + gas_data->status_code == DOT11_SC_FAILURE ? "UNSPECIFIED" : + gas_data->status_code == DOT11_SC_ADV_PROTO_NOT_SUPPORTED ? + "ADVERTISEMENT_PROTOCOL_NOT_SUPPORTED" : + gas_data->status_code == DOT11_SC_NO_OUTSTAND_REQ ? + "NO_OUTSTANDING_REQUEST" : + gas_data->status_code == DOT11_SC_RSP_NOT_RX_FROM_SERVER ? + "RESPONSE_NOT_RECEIVED_FROM_SERVER" : + gas_data->status_code == DOT11_SC_TIMEOUT ? + "TIMEOUT" : + gas_data->status_code == DOT11_SC_QUERY_RSP_TOO_LARGE ? + "QUERY_RESPONSE_TOO_LARGE" : + gas_data->status_code == DOT11_SC_SERVER_UNREACHABLE ? + "SERVER_UNREACHABLE" : + gas_data->status_code == DOT11_SC_TRANSMIT_FAILURE ? + "TRANSMISSION_FAILURE" : "unknown"); + printf(" GAS data length = %d\n", gas_data->data_len); + if (gas_data->data_len) { + wl_hexdump(gas_data->data, gas_data->data_len); + } + } + else if (event_type == WLC_E_GAS_COMPLETE) { + printf("WLC_E_GAS_COMPLETE: %s\n", + status == WLC_E_STATUS_SUCCESS ? "WLC_E_STATUS_SUCCESS" : + "unknown"); + } + } + } + + free(data); +exit1: + close(fd); +exit2: + return err; +} +#endif /* WLANQPO */ + +static int +wl_hs20_ie(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + int ret; + int bsscfg_idx = 0; + int consumed = 0; + int length; + int malloc_size; + tlv_t *tlv; + + UNUSED_PARAMETER(cmd); + + if (!argv[1]) { + fprintf(stderr, "Too few arguments\n"); + return -1; + } + + /* parse a bsscfg_idx option if present */ + if ((ret = wl_cfg_option(argv + 1, argv[0], &bsscfg_idx, &consumed)) != 0) + return ret; + if (consumed) + argv = argv + consumed; + + length = atoi(argv[1]); + + if (length < 0 || length > 255) { + fprintf(stderr, "Invalid length\n"); + return -1; + } + else if (length > 0) { + if (!argv[2]) { + fprintf(stderr, + "Data bytes should be specified for non-zero length\n"); + return -1; + } + else { + /* Ensure each data byte is 2 characters long */ + if ((int)strlen(argv[2]) != (length * 2)) { + fprintf(stderr, "Please specify all the data bytes for this IE\n"); + return -1; + } + } + } + + malloc_size = OFFSETOF(tlv_t, data) + length; + tlv = malloc(malloc_size); + if (tlv == 0) { + fprintf(stderr, "Error allocating %d bytes for IE params\n", malloc_size); + return -1; + } + tlv->id = DOT11_MNG_VS_ID; + tlv->len = length; + + if (length > 0) { + if ((err = get_ie_data((uchar *)argv[2], tlv->data, length))) { + fprintf(stderr, "Error parsing data arg\n"); + free(tlv); + return err; + } + } + + if (bsscfg_idx == -1) + err = wlu_var_setbuf(wl, "hs20_ie", tlv, malloc_size); + else + err = wlu_bssiovar_setbuf(wl, "hs20_ie", bsscfg_idx, + tlv, malloc_size, buf, WLC_IOCTL_MAXLEN); + + free(tlv); + return (err); +} + +static dbg_msg_t toe_cmpnt[] = { + {TOE_TX_CSUM_OL, "tx_csum_ol"}, + {TOE_RX_CSUM_OL, "rx_csum_ol"}, + {0, NULL} +}; + +static dbg_msg_t arpoe_cmpnt[] = { + {ARP_OL_AGENT, "agent"}, + {ARP_OL_SNOOP, "snoop"}, + {ARP_OL_HOST_AUTO_REPLY, "host_auto_reply"}, + {ARP_OL_PEER_AUTO_REPLY, "peer_auto_reply"}, + {0, NULL} +}; + +/* + * Tcpip Offload Component-wise get/set control. + */ +static int +wl_offload_cmpnt(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + uint val, last_val = 0, cmpnt_add = 0, cmpnt_del = 0; + char *endptr; + dbg_msg_t *dbg_msg = NULL; + void *ptr = NULL; + int cmpnt; + + if (strcmp(cmd->name, "toe_ol") == 0) + dbg_msg = toe_cmpnt; + else if (strcmp(cmd->name, "arp_ol") == 0) + dbg_msg = arpoe_cmpnt; + else { + printf("Not a valid command\n"); + return BCME_BADARG; + } + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return (ret); + cmpnt = dtoh32(*(int *)ptr); + + if (!*++argv) { + printf("0x%x ", cmpnt); + for (i = 0; (val = dbg_msg[i].value); i++) { + if ((cmpnt & val) && (val != last_val)) + printf(" %s", dbg_msg[i].string); + last_val = val; + } + printf("\n"); + return (0); + } + + while (*argv) { + char *s = *argv; + if (*s == '+' || *s == '-') + s++; + else + cmpnt_del = ~0; /* make the whole list absolute */ + val = strtoul(s, &endptr, 0); + /* not a plain integer if not all the string was parsed by strtoul */ + if (*endptr != '\0') { + for (i = 0; (val = dbg_msg[i].value); i++) + if (stricmp(dbg_msg[i].string, s) == 0) + break; + if (!val) + goto usage; + } + if (**argv == '-') + cmpnt_del |= val; + else + cmpnt_add |= val; + ++argv; + } + + cmpnt &= ~cmpnt_del; + cmpnt |= cmpnt_add; + + cmpnt = htod32(cmpnt); + return (wlu_var_setbuf(wl, cmd->name, &cmpnt, sizeof(int))); + +usage: + fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n"); + fprintf(stderr, "Use a + or - prefix to make an incremental change."); + + for (i = 0; (val = dbg_msg[i].value); i++) { + if (val != last_val) + fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string); + else + fprintf(stderr, ", %s", dbg_msg[i].string); + last_val = val; + } + fprintf(stderr, "\n"); + + return 0; +} + +#if defined(WLNDOE) || defined(WLOFFLD) +/* + * If a host IP address is given, add it to the host-cache, + * e.g. "wl nd_hostip fe00:0:0:0:0:290:1fc0:18c0 ". + * If no address is given, dump all the addresses. + */ +static int +wl_hostipv6(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + struct ipv6_addr ipa_set, *ipa_get, null_ipa; + uint16 *ip_addr; + if (!*++argv) { + /* Get */ + void *ptr = NULL; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + ip_addr = (uint16*)ptr; + memset(null_ipa.addr, 0, IPV6_ADDR_LEN); + for (ipa_get = (struct ipv6_addr *)ptr; + memcmp(null_ipa.addr, ipa_get->addr, IPV6_ADDR_LEN) != 0; + ipa_get++) { + /* Print ipv6 Addr */ + for (i = 0; i < 8; i++) { + printf("%x", ntoh16(ip_addr[i])); + if (i < 7) + printf(":"); + } + printf("\r\n"); + + ip_addr += 8; + } + } else { + /* Add */ + if (!wl_atoipv6(*argv, &ipa_set)) + return BCME_USAGE_ERROR; + + /* we add one ip-addr at a time */ + return wlu_var_setbuf(wl, cmd->name, &ipa_set, IPV6_ADDR_LEN); + } + return ret; +} +#endif /* defined(WLOFFLD) || defined(WLNDOE) */ + +#ifdef WLNDOE +static int +wl_ndstatus(void *wl, cmd_t *cmd, char **argv) +{ + int ret = 0; + struct nd_ol_stats_t *nd_stats; + + if (!*++argv) { + /* Get */ + void *ptr = NULL; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + nd_stats = (struct nd_ol_stats_t *)ptr; + + printf("host_ip_entries %d\r\n", nd_stats->host_ip_entries); + printf("host_ip_overflow %d\r\n", nd_stats->host_ip_overflow); + printf("peer_request %d\r\n", nd_stats->peer_request); + printf("peer_request_drop %d\r\n", nd_stats->peer_request_drop); + printf("peer_reply_drop %d\r\n", nd_stats->peer_reply_drop); + printf("peer_service %d\r\n", nd_stats->peer_service); + } else { + printf("Cannot set nd stats\n"); + } + + return 0; +} + +/* + * If a solicit IP address is given, add it + * e.g. "wl nd_solicitip fe00:0:0:0:0:290:1fc0:18c0 ". + * If no address is given, dump all the addresses. + */ +static int +wl_solicitipv6(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + struct ipv6_addr ipa_set, *ipa_get, null_ipa; + uint16 *ip_addr; + if (!*++argv) { + /* Get */ + void *ptr = NULL; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + ip_addr = (uint16*)ptr; + memset(null_ipa.addr, 0, IPV6_ADDR_LEN); + for (ipa_get = (struct ipv6_addr *)ptr; + memcmp(null_ipa.addr, ipa_get->addr, IPV6_ADDR_LEN) != 0; + ipa_get++) { + /* Print ipv6 Addr */ + for (i = 0; i < 8; i++) { + printf("%x", ntoh16(ip_addr[i])); + if (i < 7) + printf(":"); + } + printf("\r\n"); + + ip_addr += 8; + } + } else { + /* Add */ + if (!wl_atoipv6(*argv, &ipa_set)) + return BCME_USAGE_ERROR; + + /* we add one ip-addr at a time */ + return wlu_var_setbuf(wl, cmd->name, &ipa_set, IPV6_ADDR_LEN); + } + return ret; +} + +/* + * If a remote IP address is given, add it + * e.g. "wl nd_remoteip fe00:0:0:0:0:290:1fc0:18c0 ". + * If no address is given, dump the addresses. + */ +static int +wl_remoteipv6(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + struct ipv6_addr ipa_set, *ipa_get, null_ipa; + uint16 *ip_addr; + if (!*++argv) { + /* Get */ + void *ptr = NULL; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + ip_addr = (uint16*)ptr; + memset(null_ipa.addr, 0, IPV6_ADDR_LEN); + for (ipa_get = (struct ipv6_addr *)ptr; + memcmp(null_ipa.addr, ipa_get->addr, IPV6_ADDR_LEN) != 0; + ipa_get++) { + /* Print ipv6 Addr */ + for (i = 0; i < 8; i++) { + printf("%x", ntoh16(ip_addr[i])); + if (i < 7) + printf(":"); + } + printf("\r\n"); + + ip_addr += 8; + } + } else { + /* Add */ + if (!wl_atoipv6(*argv, &ipa_set)) + return BCME_USAGE_ERROR; + + /* we add one ip-addr at a time */ + return wlu_var_setbuf(wl, cmd->name, &ipa_set, IPV6_ADDR_LEN); + } + return ret; +} +#endif /* WLNDOE */ +/* + * If a host IP address is given, add it to the host-cache, e.g. "wl arp_hostip 192.168.1.1". + * If no address is given, dump all the addresses. + */ +static int +wl_hostip(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + struct ipv4_addr ipa_set, *ipa_get, null_ipa; + + if (!*++argv) { + /* Get */ + void *ptr = NULL; + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + memset(null_ipa.addr, 0, IPV4_ADDR_LEN); + + for (ipa_get = (struct ipv4_addr *)ptr; + memcmp(null_ipa.addr, ipa_get->addr, IPV4_ADDR_LEN) != 0; + ipa_get++) + printf("%s\n", wl_iptoa(ipa_get)); + + printf("Total %d host addresses\n", (int)(ipa_get - (struct ipv4_addr *)ptr)); + } else { + /* Add */ + if (!wl_atoip(*argv, &ipa_set)) + return BCME_USAGE_ERROR; + /* we add one ip-addr at a time */ + return wlu_var_setbuf(wl, cmd->name, &ipa_set, sizeof(IPV4_ADDR_LEN)); + } + + return ret; +} +/* + * If a host IP address is given, add it to the host-cache, + * e.g. "wl nd_hostip fe00:0:0:0:0:290:1fc0:18c0 ". + * If no address is given, dump all the addresses. + */ +static int +wl_nshostip(void *wl, cmd_t *cmd, char **argv) +{ + + int ret = 0, i; + struct ipv6_addr ipa_set, *ipa_get, null_ipa; + uint16 *ip_addr; + if (!*++argv) { + /* Get */ + void *ptr = NULL; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + ip_addr = (uint16*)ptr; + memset(null_ipa.addr, 0, IPV6_ADDR_LEN); + for (ipa_get = (struct ipv6_addr *)ptr; + memcmp(null_ipa.addr, ipa_get->addr, IPV6_ADDR_LEN) != 0; + ipa_get++) { + /* Print ipv6 Addr */ + for (i = 0; i < 8; i++) + printf("%x", ntoh16(ip_addr[i])); + if (i < 7) + printf(":"); + } + printf("\r\n"); + ip_addr += 8; + } + else { + /* Add */ + if (!wl_atoipv6(*argv, &ipa_set)) + return -1; + /* we add one ip-addr at a time */ + return wlu_var_setbuf(wl, cmd->name, + &ipa_set, IPV6_ADDR_LEN); + } + return ret; +} + +#ifdef WLOFFLD +static int +wl_ol_notify_bcn_ie(void *wl, cmd_t *cmd, char **argv) +{ + int ret = -1; + void *ptr = NULL; + +#define VNDR_IE_ID (221) +#define OLMSG_BCN_MAX_IE (222) + + struct beacon_ie_notify_cmd { + uint32 id; + uint32 enable; + struct ipv4_addr vndriemask; + } beacon_notification_cmd; + + memset(&beacon_notification_cmd, 0, sizeof(beacon_notification_cmd)); + + ++argv; /* skip the command iteself */ + + if (!*argv) { + /* Get Everything */ + beacon_notification_cmd.id = -1; /* -1 indicates NONE */ + ret = wlu_var_getbuf(wl, cmd->name, &beacon_notification_cmd, + sizeof(beacon_notification_cmd), &ptr); + } else { + if (stricmp(*argv, "enable") == 0) { /* Enable Global flag */ + beacon_notification_cmd.id = -1; /* -1 indicates NONE */ + beacon_notification_cmd.enable = 1; + return wlu_var_setbuf(wl, cmd->name, &beacon_notification_cmd, + sizeof(beacon_notification_cmd)); + } else if (stricmp(*argv, "disable") == 0) { /* Disable Global flag */ + beacon_notification_cmd.id = -1; /* -1 indicates NONE */ + beacon_notification_cmd.enable = 0; + return wlu_var_setbuf(wl, cmd->name, &beacon_notification_cmd, + sizeof(beacon_notification_cmd)); + } else { /* Get/Set Enable/Disable some ID */ + + beacon_notification_cmd.id = (uint8) atoi(*argv); + + if (beacon_notification_cmd.id == VNDR_IE_ID) { + /* Get VNDR OUI */ + ++argv; + if (*argv) { /* Get a specific Vendor IE */ + if (!wl_atoip(*argv, &beacon_notification_cmd.vndriemask)) { + return -1; + } + ++argv; + /* Get enable/disable flag */ + if (*argv) { /* Set a specific Vendor ie */ + if (stricmp(*argv, "enable") == 0) + beacon_notification_cmd.enable = 1; + else if (stricmp(*argv, "disable") == 0) + beacon_notification_cmd.enable = 0; + else + return -1; + + return wlu_var_setbuf(wl, cmd->name, + &beacon_notification_cmd, + sizeof(beacon_notification_cmd)); + } else { + ret = wlu_var_getbuf(wl, cmd->name, + &beacon_notification_cmd, + sizeof(beacon_notification_cmd), + &ptr); + } + } else { /* Get ALL Vendor IE */ + ret = wlu_var_getbuf(wl, cmd->name, + &beacon_notification_cmd, + sizeof(beacon_notification_cmd), + &ptr); + } + } else { + if (beacon_notification_cmd.id > OLMSG_BCN_MAX_IE) { + return -1; + } + /* Get enable/disable flag */ + ++argv; + if(*argv) { /* Set IE ID */ + if (stricmp(*argv, "enable") == 0) + beacon_notification_cmd.enable = 1; + else if (stricmp(*argv, "disable") == 0) + beacon_notification_cmd.enable = 0; + else + return -1; + return wlu_var_setbuf(wl, cmd->name, + &beacon_notification_cmd, + sizeof(beacon_notification_cmd)); + } else { /* Get IE ID */ + ret = wlu_var_getbuf(wl, cmd->name, + &beacon_notification_cmd, + sizeof(beacon_notification_cmd), + &ptr); + } + } + } + } + if ((ret >= 0) && (ptr != NULL)) { + printf("%s\n", (char *)ptr); /* Print Everything */ + } + return ret; +} +#endif /* WLOFFLD */ + +static int +wl_mcast_ackmac(void *wl, cmd_t *cmd, char **argv) +{ + int ret = 0; + int i, err; + wl_rmc_entry_t ackmac_params; + wl_rmc_entry_table_t tablelist; + void *ptr = NULL; + wl_rmc_entry_table_t *reply = NULL; + wl_rmc_gbl_table_t *gtbl = NULL; + miniopt_t to; + struct ether_addr* ea = NULL; + bool index_set = FALSE; bool mac_set = FALSE; + + /* muticast mac address - ipv4 & ipv6 resp. */ + uint8 mc_mac[6] = {0x1, 0x0, 0x5e, 0x7f, 0xff, 0xff}; + uint8 mc_mac_ipv6[6] = {0x33, 0x33, 0x0, 0x0, 0x0, 0x0}; + + /* index will tell us what to do */ + + if (!*++argv) { + /* Get and display all entries in the table */ + if ((ret = wlu_var_getbuf(wl, cmd->name, + NULL, + 0, + &ptr)) < 0) { + return ret; + } + reply = (wl_rmc_entry_table_t *)ptr; + printf("\n Local: Active Mask 0x%02x Transmitter mask 0x%02x ", + reply->index, reply->opcode); + + printf("\n Enable\t Multi-cast Group "); + printf("\n %d \t\t Ack All \t", (reply->index & WL_RMC_ACK_MCAST_ALL)?1:0); + + for (i = 0; i < WL_RMC_MAX_TABLE_ENTRY; i++) { + printf("\n %d \t %s", + (reply->index & (WL_RMC_ACK_MCAST0 << i))?1:0, + wl_ether_etoa(&reply->entry[i].addr)); + } + + gtbl = (wl_rmc_gbl_table_t *)((char*)ptr+sizeof(wl_rmc_entry_table_t)); + + printf("\n Global Table: Active Mask 0x%02x ", gtbl->activeMask); + printf("\n Multi-cast \t\t Transmitter \t"); + printf("\n Ack All Entry \t\t %s", + wl_ether_etoa(>bl->ackAll.tr_info[0].addr)); + + for (i = 0; i < WL_RMC_MAX_TABLE_ENTRY; i++) { + printf("\n %s \t", wl_ether_etoa(>bl->mc_entry[i].mcaddr)); + + printf("%s \t", + wl_ether_etoa(>bl->mc_entry[i].tr_info[0].addr)); + + } + printf("\n"); + return 0; + } + + miniopt_init(&to, cmd->name, NULL, FALSE); + + while ((err = miniopt(&to, argv)) != -1) { + if (err == 1) { + return BCME_USAGE_ERROR; + } + argv += to.consumed; + /* Index for muticast address in RMC table */ + if (to.opt == 'i') { + if (!to.good_int || (to.val >= WL_RMC_MAX_TABLE_ENTRY && to.val)) { + fprintf(stderr, "%s: Invalid mode value\n", cmd->name); + err = -1; + goto exit; + } + tablelist.index = to.val; + index_set = TRUE; + } + + /* Add multicast address with index "i" to RMC table */ + if (to.opt == 't') { + if (!wl_ether_atoe(to.valstr, &ackmac_params.addr)) { + fprintf(stderr, + "%s: could not parse \"%s\" as a MAC address\n", + cmd->name, to.valstr); + err = -1; + goto exit; + } + mac_set = TRUE; + } + } + + if (index_set) { + if (!mac_set) { + /* if table index is -1 & no mac entry, it is for ACKALL */ + if (tablelist.index == 255) { + /* enable all multi-cast */ + tablelist.index = 0; + tablelist.opcode = RELMCAST_ENTRY_OP_ACK_ALL; + tablelist.entry[tablelist.index].flag = RELMCAST_ENTRY_OP_ACK_ALL; + } + /* if index is not -1 and no mac entry, + it is for removing entry at the index + */ + else if (tablelist.index < WL_RMC_MAX_TABLE_ENTRY) { + /* remove multi-cast entry by setting flag to deleted */ + tablelist.opcode = RELMCAST_ENTRY_OP_DELETE; + tablelist.entry[tablelist.index].flag = RELMCAST_ENTRY_OP_DELETE; + } + else { + printf("%s Invalid index %d\n", cmd->name, tablelist.index); + return BCME_USAGE_ERROR; + } + + return wlu_var_setbuf(wl, cmd->name, + &tablelist, + sizeof(wl_rmc_entry_table_t)+sizeof(wl_rmc_gbl_table_t)); + } else { + /* mac is also set */ + memcpy(&tablelist.entry[tablelist.index].addr, &ackmac_params.addr, + sizeof(struct ether_addr)); + + /* insert to list */ + ea = &tablelist.entry[tablelist.index].addr; + tablelist.entry[tablelist.index].flag = RELMCAST_ENTRY_OP_ENABLE; + + /* for ipv4, initial three bytes in mc address are standard & + 2 bytes for ipv6 + */ + if ((!memcmp(ea, mc_mac, 3) && !(ea->octet[3] & 0x80)) || + !memcmp(ea, mc_mac_ipv6, 2)) { + + fprintf(stderr, + "\nAdding multi-cast mac %s\n", wl_ether_etoa(ea)); + + return wlu_var_setbuf(wl, cmd->name, + &tablelist, + sizeof(wl_rmc_entry_table_t)+sizeof(wl_rmc_gbl_table_t)); + + } else { + + fprintf(stderr, "multicast mac started with" + "01:00:5e:0... or 33:33:...\n"); + ret = BCME_BADARG; + + } + } + } +exit: + return ret; +} + +static int +wl_mcast_ackreq(void *wl, cmd_t *cmd, char **argv) +{ + const char* fn_name = "wl_mcast_ackreq"; + int err, i = 0; + uint argc; + char *endptr = NULL; + void *ptr = NULL; + uint8 *reply_mode = NULL; + uint8 params_mode, old_mode; + wl_relmcast_status_t status; + + memset(¶ms_mode, 0, sizeof(uint8)); + /* toss the command name */ + argv++; + + if ((err = wlu_var_getbuf_sm(wl, cmd->name, ¶ms_mode, + sizeof(uint8), &ptr)) != BCME_OK) { + fprintf(stderr, "Error getting variable %s\n", argv[0]); + return err; + } + + reply_mode = (uint8 *)ptr; + old_mode = *reply_mode; + + if (!*argv) { + fprintf(stderr, "%s mode %d \n", fn_name, *reply_mode); + return err; + } + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* required arg: mode disable, enable or initiator enabled */ + if (argc < 1) + return -1; + + /* get the new ackreq mode */ + params_mode = strtol(argv[0], &endptr, 0); + + if ((*endptr != '\0') || (params_mode > WL_RMC_MODE_INITIATOR)) + return -1; + + if (argc > 1) { + fprintf(stderr, + "%s: could not parse extra argument %s:\n", + fn_name, argv[1]); + + err = -1; + goto exit; + } + + if ((err = wlu_var_setbuf(wl, cmd->name, ¶ms_mode, sizeof(uint8))) != BCME_OK) { + goto out_of_here; + } + + if (params_mode == WL_RMC_MODE_INITIATOR || + ((params_mode == WL_RMC_MODE_RECEIVER) && + (old_mode == WL_RMC_MODE_INITIATOR))) { + + for (i = 0; i <= 10; i++) { + /* check status of the RCV bit to make sure ack are receive */ + if ((err = wlu_iovar_get(wl, "rmc_status", + (void *) &status, + (sizeof(wl_relmcast_status_t)))) < 0) { + return (err); + } + + if (status.err != (uint16)BCME_NOTREADY) { + if (status.err == (uint16)BCME_RXFAIL) { + fprintf(stderr, "%s: error in setting mode: no ack receive" + "%d tx code %d \n", + fn_name, params_mode, status.err); + + err = -1; + } else { + err = 0; + } + goto out_of_here; + } + + /* Allow ample time (by staying in loop) to get ACK + for previous TX frame + */ + { + volatile uint16 busycnt = -1; + while (--busycnt) + ; + busycnt = -1; + } + } /* for loop */ + } +out_of_here: + if ((err < 0) || (i > 10)) + fprintf(stderr, "%s: Error setting %d err %d \n", fn_name, params_mode, err); + else + fprintf(stderr, "%s: setting %d err %d \n", fn_name, params_mode, err); +exit: + return 0; +} + + +static int +wl_mcast_status(void *wl, cmd_t *cmd, char **argv) +{ + int err, i; + wl_relmcast_status_t status; + + if (!*++argv) { + /* Get */ + if ((err = wlu_iovar_get(wl, cmd->name, (void *) &status, + (sizeof(wl_relmcast_status_t)))) < 0) + return (err); + + if (status.ver != WL_RMC_VER) { + printf("Wrong Version %d %d\n", WL_RMC_VER, status.ver); + } else if (status.num == 0) { + printf("No clients associated\n"); + } else { + for (i = 0; i < status.num; i++) + { + printf("%s\t%d\t%c%c%c\n", wl_ether_etoa(&status.clients[i].addr), + status.clients[i].rssi, + ((status.clients[i].flag & WL_RMC_FLAG_ACTIVEACKER) ? + 'A' : ' '), + ((status.clients[i].flag & WL_RMC_FLAG_INBLACKLIST) ? + 'B' : ' '), + ((status.clients[i].flag & WL_RMC_FLAG_RELMCAST) ? + 'R' : ' ')); + } + + printf("Notification Frame TimePeriod: %d ms\n", status.actf_time); + } + } else { + printf("Cannot set reliable multicast status\n"); + } + + return 0; +} + +static int +wl_mcast_actf_time(void *wl, cmd_t *cmd, char **argv) +{ + int val, error = -1; + const char *name = cmd->name; + + /* toss the command name from the args */ + argv++; + + if (!*argv) { + error = wlu_iovar_getint(wl, name, &val); + if (error < 0) + return (error); + printf("Action Frame tx time period: %dms\n", val); + + } else { + + val = (uint16)strtol(*argv, NULL, 10); /* 10 is for base 10 (decimal) */ + + if (val >= WL_RMC_ACTF_TIME_MIN && + val <= WL_RMC_ACTF_TIME_MAX) { + + error = wlu_iovar_setint(wl, name, val); + + } else { + + printf("\"Out of range\": valid range %dms - %dms\n", + WL_RMC_ACTF_TIME_MIN, + WL_RMC_ACTF_TIME_MAX); + } + } + return error; +} + +static int +wl_mcast_ar_timeout(void *wl, cmd_t *cmd, char **argv) +{ + int val, error = -1; + const char *name = cmd->name; + + /* toss the command name from the args */ + argv++; + + if (!*argv) { + error = wlu_iovar_getint(wl, name, &val); + if (error < 0) + return (error); + printf("Active Receiver time out: %dms\n", val); + + } else { + val = (uint16)strtol(*argv, NULL, 10); + if (val >= WL_RMC_ARTMO_MIN && + val <= WL_RMC_ARTMO_MAX) + error = wlu_iovar_setint(wl, name, val); + else + printf("\"Out of range\": valid range %dms - %dms\n", + WL_RMC_ARTMO_MIN, + WL_RMC_ARTMO_MAX); + } + return error; +} + +static int +wl_mcast_rssi_thresh(void *wl, cmd_t *cmd, char **argv) +{ + int val, error = -1; + const char *name = cmd->name; + + /* toss the command name from the args */ + argv++; + + if (!*argv) { + error = wlu_iovar_getint(wl, name, &val); + if (error < 0) + return (error); + printf("rmc rssi: %d\n", val); + + } else { + val = (int8)strtol(*argv, NULL, 10); + error = wlu_iovar_setint(wl, name, val); + } + + return error; +} + +static int +wl_mcast_stats(void *wl, cmd_t *cmd, char **argv) +{ +#define PRCNT(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh16(cnts_v.name)) +#define PRCNT32(name) pbuf += sprintf(pbuf, "%s %u ", #name, dtoh32(cnts_v.name)) + wl_rmc_cnts_t *cnts = NULL; + wl_rmc_cnts_t cnts_v; + int err = BCME_OK; + uint8 argval, argc; + char *pbuf = buf; + char *endptr = NULL; + void *ptr = NULL; + + if (!*++argv) { + /* no arg - get and display all values */ + + if ((err = wlu_var_getbuf (wl, cmd->name, &cnts_v, sizeof(wl_rmc_cnts_t), &ptr))) + return (err); + + cnts = (wl_rmc_cnts_t*)ptr; + + memcpy((wl_rmc_cnts_t*)&cnts_v, cnts, sizeof(wl_rmc_cnts_t)); + cnts_v.version = dtoh16(cnts->version); + cnts_v.length = dtoh16(cnts->length); + + if (cnts_v.version != WL_RMC_CNT_VERSION) { + printf("\tIncorrect version of counters struct: expected %d; got %d\n", + WL_RMC_CNT_VERSION, cnts->version); + + return -1; + } + + PRCNT(dupcnt); PRCNT(ackreq_err); PRCNT(af_tx_err); PRNL(); + PRCNT(null_tx_err); PRCNT(af_unicast_tx_err); PRCNT(mc_no_amt_slot); PRNL(); + PRCNT(mc_no_glb_slot); PRCNT(mc_not_mirrored); PRCNT(mc_existing_tr); PRNL(); + PRCNT(mc_exist_in_amt); PRCNT(mc_not_exist_in_gbl); PRCNT(mc_utilized); PRNL(); + PRCNT(mc_taken_other_tr); PRCNT32(rmc_rx_frames_mac); PRCNT32(rmc_tx_frames_mac); + PRNL(); PRCNT32(mc_ar_role_selected); PRCNT32(mc_ar_role_deleted); + PRCNT32(mc_noacktimer_expired); PRNL(); PRCNT32(mc_null_ar_cnt); PRNL(); + fputs(buf, stdout); + + } else { + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + argval = strtol(argv[0], &endptr, 0); + if (argval == 255) { + /* arg is -1, clear all the values */ + fprintf(stderr, "clearing rmc counters\n"); + err = wlu_var_setbuf(wl, cmd->name, &cnts_v, sizeof(wl_rmc_cnts_t)); + + } else { + fprintf(stderr, "Invalid arg, only -1" + "is allowed to clear counters\n"); + err = BCME_BADARG; + } + } + return err; +} + +static int +wl_mcast_rssi_delta(void *wl, cmd_t *cmd, char **argv) +{ + int val, error = -1; + const char *name = cmd->name; + + /* toss the command name from the args */ + argv++; + + if (!*argv) { + error = wlu_iovar_getint(wl, name, &val); + if (error < 0) + return (error); + printf("rmc rssi delta: %d\n", val); + + } else { + val = (uint16)strtol(*argv, NULL, 10); + if (val >= 0) /* rssi delta value should be a whole number */ + error = wlu_iovar_setint(wl, name, val); + else + printf("\"Out of range\": rmc rssi delta should be >=0\n"); + } + return error; +} + +static int +wl_mcast_vsie(void *wl, cmd_t *cmd, char **argv) +{ + int ret = 0; + void *ptr = NULL; + wl_rmc_vsie_t *reply = NULL; + wl_rmc_vsie_t vsie; + char *parse = NULL; + char tmp[4]; + int idx, cnt; + + if (!*++argv) { + + /* Get and display all entries in the table */ + if ((ret = wlu_var_getbuf(wl, cmd->name, + NULL, + 0, + &ptr)) < 0) { + return ret; + } + + reply = (wl_rmc_vsie_t*)ptr; + + printf("0x%x%x%x 0x%x", reply->oui[0], reply->oui[1], + reply->oui[2], reply->payload); + + } else { + + parse = *argv++; + + /* remove "0x" from the input string which is in hex */ + if (strlen(parse)/2 > DOT11_OUI_LEN) { + if (!strncmp("0x", parse, strlen("0x")) || + !strncmp("0X", parse, strlen("0X"))) { + parse += strlen("0x"); + } + } + + /* if OUI string is not 6 characters, simply reject */ + if (strlen(parse) != DOT11_OUI_LEN * 2) + return BCME_ERROR; + + /* parse oui string */ + for (idx = 0; idx < DOT11_OUI_LEN; idx++) { + for (cnt = 0; cnt < 2; cnt++) { + tmp[cnt] = *parse++; + } + tmp[cnt] = '\0'; + vsie.oui[idx] = (uint8)(strtoul(tmp, NULL, 16)); + } + + /* second argument is missing!! */ + if (!*argv) { + return BCME_ERROR; + } + + vsie.payload = (uint16)(strtoul(*argv, NULL, 16)); + ret = wlu_var_setbuf(wl, cmd->name, &vsie, sizeof(vsie)); + } + + return ret; +} + +static int +wl_arp_stats(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + struct arp_ol_stats_t *arpstats; + + if (!*++argv) { + /* Get */ + void *ptr = NULL; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + arpstats = (struct arp_ol_stats_t *)ptr; + printf("host_ip_entries = %d\n", dtoh32(arpstats->host_ip_entries)); + printf("host_ip_overflow = %d\n", dtoh32(arpstats->host_ip_overflow)); + printf("arp_table_entries = %d\n", dtoh32(arpstats->arp_table_entries)); + printf("arp_table_overflow = %d\n", dtoh32(arpstats->arp_table_overflow)); + printf("host_request = %d\n", dtoh32(arpstats->host_request)); + printf("host_reply = %d\n", dtoh32(arpstats->host_reply)); + printf("host_service = %d\n", dtoh32(arpstats->host_service)); + printf("peer_request = %d\n", dtoh32(arpstats->peer_request)); + printf("peer_request_drop = %d\n", dtoh32(arpstats->peer_request_drop)); + printf("peer_reply = %d\n", dtoh32(arpstats->peer_reply)); + printf("peer_reply_drop = %d\n", dtoh32(arpstats->peer_reply_drop)); + printf("peer_service = %d\n", dtoh32(arpstats->peer_service)); + printf("host_ip_entries = %d\n", dtoh32(arpstats->host_ip_entries)); + } else + printf("Cannot set arp stats, use 'wl arp_stats_clear' to clear the counters\n"); + + return 0; +} + +static int +wl_toe_stats(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + struct toe_ol_stats_t *toestats; + + if (!*++argv) { + /* Get */ + void *ptr = NULL; + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + toestats = (struct toe_ol_stats_t *)ptr; + printf("tx_summed = %d\n", dtoh32(toestats->tx_summed)); + printf("tx_iph_fill = %d\n", dtoh32(toestats->tx_iph_fill)); + printf("tx_tcp_fill = %d\n", dtoh32(toestats->tx_tcp_fill)); + printf("tx_udp_fill = %d\n", dtoh32(toestats->tx_udp_fill)); + printf("tx_icmp_fill = %d\n", dtoh32(toestats->tx_icmp_fill)); + printf("rx_iph_good = %d\n", dtoh32(toestats->rx_iph_good)); + printf("rx_iph_bad = %d\n", dtoh32(toestats->rx_iph_bad)); + printf("rx_tcp_good = %d\n", dtoh32(toestats->rx_tcp_good)); + printf("rx_tcp_bad = %d\n", dtoh32(toestats->rx_tcp_bad)); + printf("rx_udp_good = %d\n", dtoh32(toestats->rx_udp_good)); + printf("rx_udp_bad = %d\n", dtoh32(toestats->rx_udp_bad)); + printf("rx_icmp_good = %d\n", dtoh32(toestats->rx_icmp_good)); + printf("rx_icmp_bad = %d\n", dtoh32(toestats->rx_icmp_bad)); + printf("tx_tcp_errinj = %d\n", dtoh32(toestats->tx_tcp_errinj)); + printf("tx_udp_errinj = %d\n", dtoh32(toestats->tx_udp_errinj)); + printf("tx_icmp_errinj = %d\n", dtoh32(toestats->tx_icmp_errinj)); + printf("rx_tcp_errinj = %d\n", dtoh32(toestats->rx_tcp_errinj)); + printf("rx_udp_errinj = %d\n", dtoh32(toestats->rx_udp_errinj)); + printf("rx_icmp_errinj = %d\n", dtoh32(toestats->rx_icmp_errinj)); + } else + printf("Cannot set toe stats, use 'wl toe_stats_clear' to clear the counters\n"); + + return 0; +} + +static void +wl_rate_histo_print(wl_mac_ratehisto_res_t *rate_histo_res) +{ + uint i, nss; + + printf("Rates\n"); + for (i = 0; i < (DOT11_RATE_MAX + 1); i++) { + if (rate_histo_res->rate[i]) { + if (DIV_REM(i, 2)) + printf("%.2d\t%d.%d Mbit/s\n", + rate_histo_res->rate[i], DIV_QUO(i, 2), DIV_REM(i, 2)/10); + else + printf("%.2d\t%d Mbit/s\n", + rate_histo_res->rate[i], DIV_QUO(i, 2)); + } + } + + printf("MCS indexes:\n"); + for (i = 0; i < (WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX); i++) { + if (rate_histo_res->mcs[i]) { + printf("%d\tMCS %d\n", rate_histo_res->mcs[i], i); + } + } + + printf("VHT indexes:\n"); + for (nss = 0; nss < WL_TX_CHAINS_MAX; nss++) { + for (i = 0; i < WL_RATESET_SZ_VHT_MCS; i++) { + if (rate_histo_res->vht[i][nss]) { + printf("%d\tVHT %d Nss %d\n", rate_histo_res->vht[i][nss], i, + nss + 1); + } + } + } + + return; +} + +static int +wl_rate_histo(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr = NULL; + int err; + wl_mac_ratehisto_res_t *rate_histo_res; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return err; + + rate_histo_res = (wl_mac_ratehisto_res_t *)ptr; + + wl_rate_histo_print(rate_histo_res); + + return 0; +} + +static int +wl_mac_rate_histo(void *wl, cmd_t *cmd, char **argv) +{ + struct ether_addr ea; + int buflen, err; + wl_mac_ratehisto_cmd_t *rate_histo_cmd; + wl_mac_ratehisto_res_t *rate_histo_res; + + if (!*++argv || !wl_ether_atoe(*argv, &ea)) + return BCME_USAGE_ERROR; + + strcpy(buf, "mac_rate_histo"); + buflen = strlen(buf) + 1; + rate_histo_cmd = (wl_mac_ratehisto_cmd_t *)(buf + buflen); + memcpy((char*)&rate_histo_cmd->ea, (char*)&ea, ETHER_ADDR_LEN); + + if (*++argv) + { + /* The access category is obtained and checked for validity */ + rate_histo_cmd->ac_cat = (uint8)strtol(*argv, NULL, 0); + if (!(rate_histo_cmd->ac_cat == 0x10 || rate_histo_cmd->ac_cat == 0x4)) { + printf("Only Access Category 0x10 and 0x4 is supported\n"); + return BCME_BADARG; + } + + if (*++argv) { + /* The number of pkts to avg is obtained and checked for valid range */ + rate_histo_cmd->num_pkts = (uint8)strtol(*argv, NULL, 10); + } else { + /* Set default value as maximum of all access categories + * so that it is set to the max value below + */ + rate_histo_cmd->num_pkts = 64; + } + + if (rate_histo_cmd->ac_cat == 0x10 && rate_histo_cmd->num_pkts > 64) { + rate_histo_cmd->num_pkts = 64; + } else if (rate_histo_cmd->ac_cat == 0x4 && rate_histo_cmd->num_pkts > 32) { + rate_histo_cmd->num_pkts = 32; + } + } else { + return BCME_USAGE_ERROR; + } + + if ((err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN)) < 0) + return err; + + rate_histo_res = (wl_mac_ratehisto_res_t *)buf; + + wl_rate_histo_print(rate_histo_res); + + printf("First TSF Timestamp: %08x%08x\n", rate_histo_res->tsf_timer[0][1], + rate_histo_res->tsf_timer[0][0]); + printf("Last TSF Timestamp : %08x%08x\n", rate_histo_res->tsf_timer[1][1], + rate_histo_res->tsf_timer[1][0]); + + return 0; +} + +static int +wl_pkteng_stats(void *wl, cmd_t *cmd, char **argv) +{ + wl_pkteng_stats_t *stats; + void *ptr = NULL; + int err; + uint16 *pktstats; + int i, j; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return err; + + stats = ptr; + printf("Lost frame count %d\n", dtoh32(stats->lostfrmcnt)); + printf("RSSI %d\n", dtoh32(stats->rssi)); + printf("Signal to noise ratio %d\n", dtoh32(stats->snr)); + printf("rx1mbps %d rx2mbps %d rx5mbps5 %d\n" + "rx6mbps %d rx9mbps %d, rx11mbps %d\n" + "rx12mbps %d rx18mbps %d rx24mbps %d\n" + "rx36mbps %d rx48mbps %d rx54mbps %d\n", + stats->rxpktcnt[3], stats->rxpktcnt[1], stats->rxpktcnt[2], + stats->rxpktcnt[7], stats->rxpktcnt[11], stats->rxpktcnt[0], + stats->rxpktcnt[6], stats->rxpktcnt[10], stats->rxpktcnt[5], + stats->rxpktcnt[9], stats->rxpktcnt[4], stats->rxpktcnt[8]); + pktstats = &stats->rxpktcnt[NUM_80211b_RATES+NUM_80211ag_RATES]; + for (i = 0; i < NUM_80211n_RATES/4; i++) { + for (j = 0; j < 4; j++) { + printf("rxmcs%d %d ", j+4*i, pktstats[j+4*i]); + } + printf("\n"); + } + printf("rxmcsother %d\n", stats->rxpktcnt[NUM_80211_RATES]); + return 0; +} + + +#define LPPHY_PAPD_EPS_TBL_SIZE 64 +static int +wl_phy_papdepstbl(void *wl, cmd_t *cmd, char **argv) +{ + int32 eps_real, eps_imag; + int i; + uint32 eps_tbl[LPPHY_PAPD_EPS_TBL_SIZE]; + int err; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_iovar_get(wl, cmd->name, &eps_tbl, sizeof(eps_tbl))) < 0) + return err; + + for (i = 0; i < LPPHY_PAPD_EPS_TBL_SIZE; i++) { + if ((eps_real = (int32)(eps_tbl[i] >> 12)) > 0x7ff) + eps_real -= 0x1000; /* Sign extend */ + if ((eps_imag = (int32)(eps_tbl[i] & 0xfff)) > 0x7ff) + eps_imag -= 0x1000; /* Sign extend */ + printf("%d %d\n", eps_real, eps_imag); + } + + return 0; +} + +static int +wl_phy_txiqcc(void *wl, cmd_t *cmd, char **argv) +{ + int i; + int err; + int32 iqccValues[4]; + int32 value; + char *endptr; + int32 a, b, a1, b1; + wlc_rev_info_t revinfo; + uint32 phytype; + + memset(&revinfo, 0, sizeof(revinfo)); + if ((err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0) + return err; + + phytype = dtoh32(revinfo.phytype); + + if (phytype != WLC_PHY_TYPE_N) { + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, iqccValues, 2*sizeof(int32))) < 0) + return err; + a = (int16)iqccValues[0]; + b = (int16)iqccValues[1]; + /* sign extend a, b from 10 bit signed value to 32 bit signed value */ + a = ((a << 22) >> 22); + b = ((b << 22) >> 22); + printf("%d %d\n", a, b); + } + else + { + for (i = 0; i < 2; i++) { + value = strtol(*argv++, &endptr, 0); + if (value > 511 || value < -512) { + return BCME_BADARG; + } + iqccValues[i] = value; + } + + if ((err = wlu_var_setbuf(wl, cmd->name, iqccValues, 2*sizeof(int32))) < 0) + return err; + } + } else { + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, iqccValues, 4*sizeof(int32))) < 0) + return err; + a = (int16)iqccValues[0]; + b = (int16)iqccValues[1]; + a1 = (int16)iqccValues[2]; + b1 = (int16)iqccValues[3]; + /* sign extend a, b from 10 bit signed value to 32 bit signed value */ + a = ((a << 22) >> 22); + b = ((b << 22) >> 22); + a1 = ((a1 << 22) >> 22); + b1 = ((b1 << 22) >> 22); + printf("%d %d %d %d\n", a, b, a1, b1); + } + else + { + for (i = 0; i < 4; i++) { + value = strtol(*argv++, &endptr, 0); + if (value > 511 || value < -512) { + return BCME_BADARG; + } + iqccValues[i] = value; + } + + if ((err = wlu_var_setbuf(wl, cmd->name, iqccValues, 4*sizeof(int32))) < 0) + return err; + } + } + + return 0; +} + +static int +wl_phy_txlocc(void *wl, cmd_t *cmd, char **argv) +{ + int i; + int err; + int8 loccValues[12]; + int32 value; + char *endptr; + wlc_rev_info_t revinfo; + uint32 phytype; + + memset(&revinfo, 0, sizeof(revinfo)); + if ((err = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0) + return err; + + phytype = dtoh32(revinfo.phytype); + + if (phytype != WLC_PHY_TYPE_N) { + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, loccValues, + sizeof(loccValues))) < 0) + return err; + + /* sign extend the loccValues */ + loccValues[2] = (loccValues[2] << 3) >> 3; + loccValues[3] = (loccValues[3] << 3) >> 3; + loccValues[4] = (loccValues[4] << 3) >> 3; + loccValues[5] = (loccValues[5] << 3) >> 3; + + printf("%d %d %d %d %d %d\n", loccValues[0], + loccValues[1], loccValues[2], loccValues[3], + loccValues[4], loccValues[5]); + } + else + { + for (i = 0; i < 6; i++) { + value = strtol(*argv++, &endptr, 0); + if ((i >= 2) && (value > 15 || value < -15)) { + return BCME_BADARG; + } + loccValues[i] = (int8)value; + } + + if ((err = wlu_var_setbuf(wl, cmd->name, loccValues, 6*sizeof(int8))) < 0) + return err; + } + } else { + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, loccValues, + sizeof(loccValues))) < 0) + return err; + + /* sign extend the loccValues */ + loccValues[2] = (loccValues[2] << 3) >> 3; + loccValues[3] = (loccValues[3] << 3) >> 3; + loccValues[4] = (loccValues[4] << 3) >> 3; + loccValues[5] = (loccValues[5] << 3) >> 3; + loccValues[8] = (loccValues[8] << 3) >> 3; + loccValues[9] = (loccValues[9] << 3) >> 3; + loccValues[10] = (loccValues[10] << 3) >> 3; + loccValues[11] = (loccValues[11] << 3) >> 3; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d\n", loccValues[0], + loccValues[1], loccValues[2], loccValues[3], loccValues[4], + loccValues[5], loccValues[6], loccValues[7], loccValues[8], + loccValues[9], loccValues[10], loccValues[11]); + } + else + { + for (i = 0; i < 12; i++) { + value = strtol(*argv++, &endptr, 0); + if (((i < 2) && (value > 63 || value < -64)) || + ((i >= 2) && (value > 15 || value < -15))) { + return BCME_BADARG; + } + loccValues[i] = (int8)value; + } + + if ((err = wlu_var_setbuf(wl, cmd->name, loccValues, 12*sizeof(int8))) < 0) + return err; + } + } + + return 0; +} + +static int +wl_rssi_cal_freq_grp_2g(void *wl, cmd_t *cmd, char **argv) +{ + int i; + int err = -1; + uint8 nvramValues[14]; + char *endptr; + int ret = -1; + wlc_rev_info_t revinfo; + + uint8 N = 0; + + memset(&revinfo, 0, sizeof(revinfo)); + ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + if (ret) { + return ret; + } + + if (!*++argv) { + /* Reading the NVRAM variable */ + if ((err = wlu_iovar_get(wl, cmd->name, nvramValues, sizeof(nvramValues))) < 0) + return err; + + N = 14; /* 14 corresponds to number of channels in 2g */ + + for (i = 0; i < N-2; i++) { + printf("0x%x%x,", nvramValues[i], nvramValues[i+1]); + i++; + } + printf("0x%x%x\n", nvramValues[i], nvramValues[i+1]); + } else { + /* Writing to NVRAM variable */ + + char *splt; + int8 tmp; + splt = strtok(*argv, ","); + + /* N = 14 corresponds to number of channels in 2g */ + /* N = N /2 to package 2 channel's nibbles into 1 byte */ + N = 7; + + i = 0; + while (splt != NULL) { + /* Splitting the input based on charecter ',' + * Further each byte is divided into 2 nibbles + * and saved into 2 elements of array. + */ + tmp = strtol(splt, &endptr, 0); + nvramValues[i] = (tmp >> 4) & 0xf; + i++; + nvramValues[i] = tmp & 0xf; + splt = strtok(NULL, ","); + i++; + } + if (i != 14) { + printf("Insufficient arguments \n"); + return BCME_BADARG; + } + if ((err = wlu_var_setbuf(wl, cmd->name, nvramValues, N*2*sizeof(int8))) < 0) + return err; + } + + return 0; +} + +static int +wl_phy_rssi_gain_delta_2g_sub(void *wl, cmd_t *cmd, char **argv) +{ + int i; + int err = -1; + int8 deltaValues[28]; + int32 value; + char *endptr; + int ret = -1; + wlc_rev_info_t revinfo; + uint32 phytype; + uint8 N = 0; + + memset(&revinfo, 0, sizeof(revinfo)); + ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + if (ret) { + return ret; + } + phytype = dtoh32(revinfo.phytype); + + if (phytype != WLC_PHY_TYPE_AC) { + return err; + } + + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0) + return err; + N = 18; /* 9 entries per core, 4350 - 18 MAX entries; 4345 9 MAX entries */ + for (i = 0; i < N; i++) { + if (i%9 == 0 && i > 0) { + printf("\n"); + if (deltaValues[i] == -1) break; + } + + printf("%d ", deltaValues[i]); + } + if (i == N) + printf("\n"); + } else { + int argc = 0; + int index = 0; + while (argv[argc]) + argc++; + + /* ACPHY : 8/9 entries for a core; core 0 delta's can be + * given with or with out core_num as first element + */ + N = argc; + + for (i = 0; i < N; i++) { + value = strtol(*argv++, &endptr, 0); + if ((value > 63 || value < -64)) { + return BCME_BADARG; + } + if (argc == 9) { + /* If number of arguments is 9, then core + * number has been provided. + * And 8 elements related to 2 + * (BWs - 20 n 40) and 4 gain settings + * (elna_on, elna_off, rout_1, rout_2) are + * provided. So, 2 * 4 = 8 + 1 core_num = 9 + */ + deltaValues[i] = (int8)value; + } else { + /* If the number of elements is not eq to 9, + * then, core number was not provided. + * So, if only 8 elements are provided, only + * core 0's info is given. So, for i = 0, + * deltaValues element is 0 (core_num). If 16 + * elements are provided, then core 0 and 1's info is + * provided. So, i =0 element has core_num = 0, + * then, next 8 elements are core 0's + * deltas. For i = 8, core 1's core_num = 1 + * is inserted into deltaValues array. + * Similarly for third core data. + */ + if (i == 0) { + deltaValues[index] = 0; + index++; + } else if (i == 8) { + deltaValues[index] = 1; + index++; + } else if (i == 16) { + deltaValues[index] = 2; + index++; + } + deltaValues[index] = (int8)value; + index++; + } + } + /* If argc == 8, then only 1 core's info was given, + * so, setbuf() is called once. + * If argc == 16 then core 0 and 1's info was given. + * So, setbuf() is called twice. + * If argc == 24 then core 0, 1 and 2's info was given. + * So, setbuf() is called thrice. + */ + if ((err = wlu_var_setbuf(wl, cmd->name, + deltaValues, 9*sizeof(int8))) < 0) + return err; + if (argc >= 16) { + if ((err = wlu_var_setbuf(wl, cmd->name, + deltaValues + 9, 9*sizeof(int8))) < 0) + return err; + } + if (argc == 24) { + if ((err = wlu_var_setbuf(wl, cmd->name, + deltaValues + 18, 9*sizeof(int8))) < 0) + return err; + } + } + + return 0; +} + +static int +wl_phy_rssi_gain_delta_2g(void *wl, cmd_t *cmd, char **argv) +{ + int i; + int err = -1; + int8 deltaValues[18]; + int32 value; + char *endptr; + int ret = -1; + wlc_rev_info_t revinfo; + uint32 phytype; + uint8 N = 0; + + memset(&revinfo, 0, sizeof(revinfo)); + ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + if (ret) { + return ret; + } + phytype = dtoh32(revinfo.phytype); + + if (phytype != WLC_PHY_TYPE_AC) { + return err; + } + + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0) + return err; + if (phytype == WLC_PHY_TYPE_AC) + N = 15; /* ACPHY: 3 cores max x 5 entries */ + for (i = 0; i < N; i++) { + if ((phytype == WLC_PHY_TYPE_AC) && (i%5 == 0)) { + if (i > 0) printf("\n"); + if (deltaValues[i] == -1) break; + } + printf("%d ", deltaValues[i]); + } + if (i == N) + printf("\n"); + } else { + int argc = 0; + int index = 0; + while (argv[argc]) + argc++; + if (phytype == WLC_PHY_TYPE_AC) { + /* N = 5; ACPHY : 5 entries for a core */ + N = argc; + } + + for (i = 0; i < N; i++) { + value = strtol(*argv++, &endptr, 0); + if ((value > 63 || value < -64)) { + return BCME_BADARG; + } + if (argc == 5) { + /* If number of arguments is 5, then core number has been provided. + * And 8 elements related to 2 (BWs - 20 n 40) and 2 gain settings + * (elna_on, elna_off) are provided. So, 2 * 2 = 4 + 1 core_num = 5 + */ + deltaValues[i] = (int8)value; + } else { + /* If the number of elements is not eq to 5, + * then, core number was not provided. + * So, if only 4 elements are provided, only + * core 0's info is given. So, for i = 0, + * deltaValues element is 0 (core_num). If 8 + * elements are provided, then core 0 and 1's info is + * provided. So, i =0 element has core_num = 0, + * then, next 4 elements are core 0's + * deltas. For i = 4, core 1's core_num = 1 + * is inserted into deltaValues array. + * Similarly for third core data. + */ + if (i == 0) { + deltaValues[index] = 0; + index++; + } else if (i == 4) { + deltaValues[index] = 1; + index++; + } else if (i == 8) { + deltaValues[index] = 2; + index++; + } + deltaValues[index] = (int8)value; + index++; + } + + } + /* If argc == 4, then only 1 core's info was given, + * so, setbuf() is called once. + * If argc == 8 then core 0 and 1's info was given. + * So, setbuf() is called twice. + * If argc == 12 then core 0, 1 and 2's info was given. + * So, setbuf() is called thrice. + */ + if ((err = wlu_var_setbuf(wl, cmd->name, + deltaValues, 5*sizeof(int8))) < 0) + return err; + if (argc >= 8) { + if ((err = wlu_var_setbuf(wl, cmd->name, + deltaValues + 5, 5*sizeof(int8))) < 0) + return err; + } + if (argc == 12) { + if ((err = wlu_var_setbuf(wl, cmd->name, + deltaValues + 10, 5*sizeof(int8))) < 0) + return err; + } + + } + + return 0; +} + +static int +wl_phy_rssi_gain_delta_5g(void *wl, cmd_t *cmd, char **argv) +{ + int i; + int err = -1; + int8 deltaValues[28]; + int32 value; + char *endptr; + int ret = -1; + wlc_rev_info_t revinfo; + uint32 phytype; + uint8 N = 0, n_per_core, n_per_core_p1; + + char *varname = "rssi_cal_rev"; + const char *iovar = "nvram_get"; + void *p; + + err = wlu_var_getbuf(wl, iovar, varname, strlen(varname) + 1, &p); + if (err == 0) { + /* This means, NVRAM variable found. */ + /* Calls new function for accommodating ROuts */ + value = strtol(buf, &endptr, 0); + } + + if ((err < 0) || ((err == 0) && (value == 0))) { + /* This means, NVRAM variable not found or Variable is 0 */ + /* Calls old function */ + n_per_core = 6; + } else { + n_per_core = 12; + } + + n_per_core_p1 = n_per_core + 1; + memset(&revinfo, 0, sizeof(revinfo)); + ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + if (ret) { + return ret; + } + phytype = dtoh32(revinfo.phytype); + + if (phytype != WLC_PHY_TYPE_AC) { + return err; + } + + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0) + return err; + if (phytype == WLC_PHY_TYPE_AC) + N = n_per_core_p1 * 3; /* ACPHY: 3 cores max x 7 entries */ + for (i = 0; i < N; i++) { + if ((phytype == WLC_PHY_TYPE_AC) && (i%n_per_core_p1 == 0)) { + if (i > 0) printf("\n"); + if (deltaValues[i] == -1) break; + } + printf("%d ", deltaValues[i]); + } + if (i == N) + printf("\n"); + } else { + int argc = 0; + int index = 0; + while (argv[argc]) + argc++; + + if (phytype == WLC_PHY_TYPE_AC) { + /* N = 7; ACPHY : 7 entries for a core */ + N = argc; + } + + for (i = 0; i < N; i++) { + value = strtol(*argv++, &endptr, 0); + if ((value > 63 || value < -64)) { + return BCME_BADARG; + } + if (argc == n_per_core_p1) { + /* For Old implementation, ie, no Routs, n_per_core_p1 == 5 + * for New implementation, ie, no Routs, n_per_core_p1 == 9 + * If number of arguments is "n_per_core_p1", + * then core number has been provided. + */ + deltaValues[i] = (int8)value; + } else { + /* If the number of elements is not eq to + *"n_per_core", then, core number was not provided. + * So, if only "n_per_core" elements are provided, + * only core 0's info is given. So, for i = 0, + * deltaValues element is 0 (core_num). If "n_per_core * 2" + * elements are provided, then core 0 and 1's info is + * provided. So, i =0 element has core_num = 0, then, + * next "n_per_core" elements are core 0's + * deltas. For i = "n_per_core", core 1's + * core_num = 1 is inserted into deltaValues array. + * Similarly for third core data. + */ + + if (i == (n_per_core * 0)) { + deltaValues[index] = 0; + index++; + } + if (i == (n_per_core * 1)) { + deltaValues[index] = 1; + index++; + } + if (i == (n_per_core * 2)) { + deltaValues[index] = 2; + index++; + } + + deltaValues[index] = (int8)value; + index++; + } + + } + /* If argc == "n_per_core", then only 1 core's infoxs + * was given, so, setbuf() is called once. + * If argc == "n_per_core * 2" then core 0 and 1's info + * was given. So, setbuf() is called twice. + * If argc == "n_per_core * 3" then core 0, 1 and 2's + * info was given. So, setbuf() is called thrice. + */ + if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues, + n_per_core_p1*sizeof(int8))) < 0) + return err; + if (argc >= (n_per_core * 2)) { + if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues + + (n_per_core_p1 * 1), n_per_core_p1*sizeof(int8))) < 0) + return err; + } + if (argc == (n_per_core * 3)) { + if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues + + (n_per_core_p1 * 2), n_per_core_p1*sizeof(int8))) < 0) + return err; + } + + } + return 0; +} + +static int +wl_phy_rxgainerr_2g(void *wl, cmd_t *cmd, char **argv) +{ + int i; + int err = -1; + int8 deltaValues[18]; + int32 value; + char *endptr; + int ret = -1; + wlc_rev_info_t revinfo; + uint32 phytype; + uint8 N = 0; + + memset(&revinfo, 0, sizeof(revinfo)); + ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + if (ret) { + return ret; + } + phytype = dtoh32(revinfo.phytype); + + if (phytype != WLC_PHY_TYPE_AC) { + return err; + } + + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0) + return err; + if (phytype == WLC_PHY_TYPE_AC) + N = 2; /* ACPHY: 3 cores 1 entry per core */ + for (i = 0; i < N; i++) { + printf("%d ", deltaValues[i]); + } + if (i == N) + printf("\n"); + } else { + int argc = 0; + while (argv[argc]) + argc++; + if (argc != 2) { + printf("IOVAR works only for 2 cores scenario. \n"); + return err; + } + if (phytype == WLC_PHY_TYPE_AC) + N = 2; /* ACPHY : 5 entries for a core */ + for (i = 0; i < N; i++) { + value = strtol(*argv++, &endptr, 0); + if ((value > 63 || value < -64)) { + return BCME_BADARG; + } + deltaValues[i] = (int8)value; + } + if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues, N*sizeof(int8))) < 0) + return err; + } + + return 0; +} + +static int +wl_phy_rxgainerr_5g(void *wl, cmd_t *cmd, char **argv) +{ + int i; + int err = -1; + int8 deltaValues[28]; + int32 value; + char *endptr; + int ret = -1; + wlc_rev_info_t revinfo; + uint32 phytype; + uint8 N = 0; + + memset(&revinfo, 0, sizeof(revinfo)); + ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + if (ret) { + return ret; + } + phytype = dtoh32(revinfo.phytype); + + if (phytype != WLC_PHY_TYPE_AC) { + return err; + } + + if (!*++argv) { + if ((err = wlu_iovar_get(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0) + return err; + if (phytype == WLC_PHY_TYPE_AC) + N = 2; /* ACPHY: 3 cores 1 entry per core */ + for (i = 0; i < N; i++) { + printf("%d ", deltaValues[i]); + } + if (i == N) + printf("\n"); + } else { + int argc = 0; + while (argv[argc]) + argc++; + if (argc != 2) { + printf("IOVAR works only for 2 cores scenario. \n"); + return err; + } + if (phytype == WLC_PHY_TYPE_AC) + N = 2; /* ACPHY : 7 entries for a core */ + for (i = 0; i < N; i++) { + value = strtol(*argv++, &endptr, 0); + if ((value > 63 || value < -64)) { + return BCME_BADARG; + } + deltaValues[i] = (int8)value; + } + if ((err = wlu_var_setbuf(wl, cmd->name, deltaValues, sizeof(deltaValues))) < 0) + return err; + } + return 0; +} + +static int +wl_phytable(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int32 tableInfo[4]; + int32 value; + char *endptr; + void *ptr = NULL; + int32 tableId, tableOffset, tableWidth, tableElement; + + if (*++argv != NULL) + tableId = strtol(*argv, &endptr, 0); + else + return BCME_USAGE_ERROR; + + if (*++argv != NULL) + tableOffset = strtol(*argv, &endptr, 0); + else + return BCME_USAGE_ERROR; + + if (*++argv != NULL) + tableWidth = strtol(*argv, &endptr, 0); + else + return BCME_USAGE_ERROR; + + if ((tableId < 0) || (tableOffset < 0)) + return BCME_BADARG; + + if ((tableWidth != 8) && (tableWidth != 16) && (tableWidth != 32)) + return BCME_BADARG; + + if (!*++argv) { + tableInfo[0] = tableId; + tableInfo[1] = tableOffset; + tableInfo[2] = tableWidth; + + if ((err = wlu_var_getbuf(wl, cmd->name, tableInfo, 4*sizeof(int32), &ptr)) < 0) + return err; + + tableElement = ((int32*)ptr)[0]; + + printf("0x%x(%d)\n", tableElement, tableElement); + } + else + { + value = strtol(*argv++, &endptr, 0); + tableElement = value; + + tableInfo[0] = tableId; + tableInfo[1] = tableOffset; + tableInfo[2] = tableWidth; + tableInfo[3] = tableElement; + + if ((err = wlu_var_setbuf(wl, cmd->name, tableInfo, 4*sizeof(int32))) < 0) + return err; + } + + return 0; +} + +static int +wl_phy_txpwrindex(void *wl, cmd_t *cmd, char **argv) +{ + uint i; + int ret; + uint32 txpwridx[4] = { 0 }; + int8 idx[4] = { 0 }; + uint argc; + char *endptr; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + for (i = 0; i < 4; i++) { + if (argc > i) { + txpwridx[i] = strtol(argv[1 + i], &endptr, 0); + if (*endptr != '\0') { + printf("error\n"); + return BCME_USAGE_ERROR; + } + } + } + + if (argc == 0) { + if ((ret = wlu_iovar_getint(wl, cmd->name, (int*)&txpwridx[0])) < 0) { + return (ret); + } + txpwridx[0] = dtoh32(txpwridx[0]); + idx[0] = (int8)(txpwridx[0] & 0xff); + idx[1] = (int8)((txpwridx[0] >> 8) & 0xff); + idx[2] = (int8)((txpwridx[0] >> 16) & 0xff); + idx[3] = (int8)((txpwridx[0] >> 24) & 0xff); + printf("txpwrindex for core{0...3}: %d %d %d %d\n", idx[0], idx[1], + idx[2], idx[3]); + } else { + + wlc_rev_info_t revinfo; + uint32 phytype; + + memset(&revinfo, 0, sizeof(revinfo)); + if ((ret = wlu_get(wl, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) < 0) + return ret; + + phytype = dtoh32(revinfo.phytype); + + if (phytype == WLC_PHY_TYPE_HT) { + if (argc != 3) { + printf("HTPHY must specify 3 core txpwrindex\n"); + return BCME_USAGE_ERROR; + } + } else if (phytype == WLC_PHY_TYPE_N) { + if (argc != 2) { + printf("NPHY must specify 2 core txpwrindex\n"); + return BCME_USAGE_ERROR; + } + } + + ret = wlu_iovar_setbuf(wl, cmd->name, txpwridx, 4*sizeof(uint32), + buf, WLC_IOCTL_MAXLEN); + } + + return ret; +} + +static int +wl_phy_force_vsdb_chans(void *wl, cmd_t *cmd, char **argv) +{ + uint16 *chans = NULL; + int ret = 0; + void *ptr; + + UNUSED_PARAMETER(wl); UNUSED_PARAMETER(cmd); + + + if (argv[1] == NULL) { + if ((ret = wlu_var_getbuf(wl, "force_vsdb_chans", NULL, 0, &ptr) < 0)) { + printf("wl_phy_maxpower: fail to get maxpower\n"); + return ret; + } + chans = (uint16*)ptr; + printf("Chans : %x %x \n", chans[0], chans[1]); + } else if (argv[1] && argv[2]) { + /* Allocate memory */ + chans = (uint16*)malloc(2 * sizeof(uint16)); + if (chans == NULL) { + printf("unable to allocate Memory \n"); + return BCME_NOMEM; + } + chans[0] = wf_chspec_aton(argv[1]); + chans[1] = wf_chspec_aton(argv[2]); + if (((chans[0] & 0xff) == 0) || ((chans[1] & 0xff) == 0)) { + chans[0] = 0; + chans[1] = 0; + } + ret = wlu_iovar_setbuf(wl, cmd->name, chans, 2 * sizeof(uint16), + buf, WLC_IOCTL_MAXLEN); + if (chans) + free(chans); + } else { + ret = BCME_USAGE_ERROR; + } + + return ret; +} + +#ifdef SR_DEBUG +/* Displays PMU related info on screen */ +static int +wl_dump_pmu(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + pmu_reg_t *pmu_var; + int err; + uint i; + uint32 pmu_chip_ctl_reg; + uint32 pmu_chip_reg_reg; + uint32 pmu_chip_pll_reg; + uint32 pmu_chip_res_reg; + UNUSED_PARAMETER(argv); + if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr))) + return (err); + pmu_var = (pmu_reg_t *)ptr; + printf("PMU Control : 0x%08x\n", pmu_var->pmu_control); + printf("PMU Capabilities : 0x%08x\n", pmu_var->pmu_capabilities); + printf("PMU Status : 0x%08x\n", pmu_var->pmu_status); + printf("Resource State : 0x%08x\n", pmu_var->res_state); + printf("Resurce Pending : 0x%08x\n", pmu_var->res_pending); + printf("PMU Timer : 0x%08x\n", pmu_var->pmu_timer1); + printf("Minimum Resource Mask: 0x%08x\n", pmu_var->min_res_mask); + printf("Maximum Resource Mask: 0x%08x\n", pmu_var->max_res_mask); + /* Displays values of the 5 PMU Chip Control Registers */ + pmu_chip_ctl_reg = (pmu_var->pmu_capabilities & 0xf8000000); + pmu_chip_ctl_reg = pmu_chip_ctl_reg >> 27; + for (i = 0; i < pmu_chip_ctl_reg; i++) { + printf("PMU ChipControl[%d] : 0x%08x\n", i, pmu_var->pmu_chipcontrol1[i]); + } + /* Displays values of the 6 PMU Reg Control Registers */ + pmu_chip_reg_reg = (pmu_var->pmu_capabilities & 0x07c00000); + pmu_chip_reg_reg = pmu_chip_reg_reg >> 22; + for (i = 0; i < pmu_chip_reg_reg; i++) { + printf("PMU RegControl[%d] : 0x%08x\n", i, pmu_var->pmu_regcontrol[i]); + } + /* Displays values of the 6 PMU Pll Control Registers */ + pmu_chip_pll_reg = (pmu_var->pmu_capabilities & 0x003e0000); + pmu_chip_pll_reg = pmu_chip_pll_reg >> 17; + for (i = 0; i < pmu_chip_pll_reg; i++) { + printf("PMU PllControl[%d] : 0x%08x\n", i, pmu_var->pmu_pllcontrol[i]); + } + /* Displays values of the 31 PMU Resource Up/Down Timer */ + pmu_chip_res_reg = (pmu_var->pmu_capabilities & 0x00001f00); + pmu_chip_res_reg = pmu_chip_res_reg >> 8; + for (i = 0; i < pmu_chip_res_reg; i++) { + printf("PMU Resource Up/Down Timer[%d] : 0x%08x\n", i, + pmu_var->pmu_rsrc_up_down_timer[i]); + } + /* Displays values of the 31 PMU Resource Dependancy Mask */ + pmu_chip_res_reg = (pmu_var->pmu_capabilities & 0x00001f00); + pmu_chip_res_reg = pmu_chip_res_reg >> 8; + for (i = 0; i < pmu_chip_res_reg; i++) { + printf("PMU Resource Dependancy Mask[%d] : 0x%08x\n", i, + pmu_var->rsrc_dep_mask[i]); + } + return 0; +} + +static int +wl_pmu_keep_on(void *wl, cmd_t *cmd, char **argv) +{ + int err; + void *ptr; + uint32 val; + pmu_min_res_t *pmu_min_res_var; + + if (argv[1] == NULL) { + if ((err = wlu_var_getbuf_med (wl, cmd->name, NULL, 0, &ptr))) + return (err); + + pmu_min_res_var = (pmu_min_res_t *)ptr; + if (pmu_min_res_var->pmu_flag == 1) { + printf("Minimum Resource Mask:0x%x\n", + pmu_min_res_var->pmu_min_res_val); + } else { + printf("The PMU is kept on upto resource# %d\n", + pmu_min_res_var->pmu_min_res_val); + } + } + else { + val = atoi(argv[1]); + wlu_iovar_setbuf(wl, cmd->name, &val, sizeof(uint32), buf, WLC_IOCTL_MAXLEN); + } + return 0; +} +#endif /* SR_DEBUG */ + +static int +wl_sarlimit(void *wl, cmd_t *cmd, char **argv) +{ + uint i; + int ret; + sar_limit_t sar; + uint argc; + char *endptr; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (argc != 0 && argc != sizeof(sar_limit_t)) { + printf("Error: Input %d SAR values, need total %d SAR values\n", + argc, (int)sizeof(sar_limit_t)); + return BCME_USAGE_ERROR; + } + + if (argc == 0) { + if ((ret = wlu_iovar_get(wl, cmd->name, &sar, sizeof(sar_limit_t))) < 0) { + return (ret); + } + printf("\t2G: %4d %4d %4d %4d\n", + sar.band2g[0], sar.band2g[1], sar.band2g[2], sar.band2g[3]); + for (i = 0; i < WLC_SUBBAND_MAX; i++) { + printf("\t5G[%1d] %4d %4d %4d %4d\n", i, + sar.band5g[i][0], sar.band5g[i][1], + sar.band5g[i][2], sar.band5g[i][3]); + } + } else { + uint8 *ptr = (uint8 *)&sar; + memset(ptr, WLC_TXPWR_MAX, sizeof(sar_limit_t)); + for (i = 0; i < argc; i++) { + ptr[i] = (uint8)(strtol(argv[1 + i], &endptr, 0)); + if (*endptr != '\0') { + printf("error\n"); + return BCME_USAGE_ERROR; + } + } + printf("\t2G: %4d %4d %4d %4d\n", + sar.band2g[0], sar.band2g[1], sar.band2g[2], sar.band2g[3]); + for (i = 0; i < WLC_SUBBAND_MAX; i++) { + printf("\t5G[%1d] %4d %4d %4d %4d\n", i, + sar.band5g[i][0], sar.band5g[i][1], + sar.band5g[i][2], sar.band5g[i][3]); + } + ret = wlu_iovar_set(wl, cmd->name, &sar, sizeof(sar_limit_t)); + } + + return ret; +} + +static int +wl_bmon_bssid(void *wl, cmd_t *cmd, char **argv) +{ + uint argc; + uint8 params[ETHER_ADDR_LEN + 1]; + + argv ++; + + /* arg count */ + argc = ARGCNT(argv); + if (argc < 2) + return BCME_USAGE_ERROR; + + if (!wl_ether_atoe(argv[0], (struct ether_addr *)¶ms[0])) + return BCME_USAGE_ERROR; + + params[ETHER_ADDR_LEN] = (uint8)strtoul(argv[1], NULL, 0); + + return wlu_iovar_set(wl, cmd->name, params, sizeof(params)); +} + +static int +wl_phy_pavars(void *wl, cmd_t *cmd, char **argv) +{ + const pavars_t *pav = pavars; + uint16 inpa[WL_PHY_PAVARS_LEN]; + char *cpar = NULL, *p = NULL; + char *par; + char delimit[2] = " \0"; + int err = 0; + unsigned int val, val2[16]; + void *ptr = NULL; + int paparambwver = 0; + + const char *iovar = "nvram_dump"; + void *p1 = NULL; + + if ((err = wlu_var_getbuf(wl, iovar, NULL, 0, &p1)) < 0) { + if ((err = wlu_get(wl, WLC_NVRAM_DUMP, &buf[0], WLC_IOCTL_MAXLEN)) < 0) + return err; + p1 = (void *)buf; + } + + if ((p1 = strstr(p1, "paparambwver"))) { + char *q = NULL; + + p1 = (void*)((char*)p1 + 13); + paparambwver = strtoul(p1, &q, 10); + } + + if (paparambwver == 1) + pav = pavars_bwver_1; + else if (paparambwver == 2) + pav = pavars_bwver_2; + else + pav = pavars; + + if (*++argv) { /* set */ + while (pav->phy_type != PHY_TYPE_NULL) { + bool found = FALSE; + int i = 0; + + inpa[i++] = pav->phy_type; + inpa[i++] = pav->bandrange; + inpa[i++] = pav->chain; + + par = malloc(strlen(pav->vars)+1); + if (!par) + return BCME_NOMEM; + + strcpy(par, pav->vars); + + cpar = strtok (par, delimit); /* current param */ + + if (pav->phy_type == PHY_TYPE_AC) { + int pnum = 0, n; + + if (pav->bandrange == WL_CHAN_FREQ_RANGE_2G) + pnum = 3; + else if (pav->bandrange == WL_CHAN_FREQ_RANGE_5G_4BAND) + pnum = 12; + + /* Find the parameter in the input argument list */ + if ((p = find_pattern2(argv, cpar, val2, pnum))) { + found = TRUE; + for (n = 0; n < pnum; n ++) + inpa[i + n] = (uint16)val2[n]; + } + } else { + do { + val = 0; + + /* Find the parameter in the input argument list */ + if ((p = find_pattern(argv, cpar, &val))) { + found = TRUE; + inpa[i] = (uint16)val; + } else + inpa[i] = 0; + i++; + } while ((cpar = strtok (NULL, delimit))); + } + free(par); + + if (found) { + if ((err = wlu_var_setbuf(wl, cmd->name, inpa, + WL_PHY_PAVARS_LEN * sizeof(uint16))) < 0) { + printf("wl_phy_pavars: fail to set\n"); + return err; + } + } + pav++; + } + } else { /* get */ + while (pav->phy_type != PHY_TYPE_NULL) { + int i = 0; + uint16 *outpa; + + inpa[i++] = pav->phy_type; + inpa[i++] = pav->bandrange; + inpa[i++] = pav->chain; + + par = malloc(strlen(pav->vars)+1); + if (!par) + return BCME_NOMEM; + + strcpy(par, pav->vars); + + if ((err = wlu_var_getbuf_sm(wl, cmd->name, inpa, + WL_PHY_PAVARS_LEN * sizeof(uint16), &ptr)) < 0) { + printf("phy %x band %x chain %d err %d\n", pav->phy_type, + pav->chain, pav->bandrange, err); + free(par); + break; + } + + outpa = (uint16*)ptr; + if (outpa[0] == PHY_TYPE_NULL) { + pav++; + free(par); + continue; + } + + cpar = strtok(par, delimit); /* current param */ + + if (pav->phy_type == PHY_TYPE_AC) { + int pnum = 0, n; + + if (pav->bandrange == WL_CHAN_FREQ_RANGE_2G) + pnum = 3; + else if (pav->bandrange == WL_CHAN_FREQ_RANGE_5G_4BAND) + pnum = 12; + + printf("%s=", cpar); + for (n = 0; n < pnum; n ++) { + if (n != 0) + printf(","); + printf("0x%x", outpa[i + n]); + } + printf("\n"); + } else { + do { + printf("%s=0x%x\n", cpar, outpa[i++]); + } while ((cpar = strtok (NULL, delimit))); + } + pav++; + free(par); + } + } + + return err; +} + +static int +wl_phy_povars(void *wl, cmd_t *cmd, char **argv) +{ + const povars_t *pov = povars; + wl_po_t inpo; + char *cpar = NULL, *p = NULL; + char *par; /* holds longest povars->vars */ + char delimit[2] = " \0"; + int err = 0; + uint val; + void *ptr = NULL; + + if (*++argv) { /* set */ + while (pov->phy_type != PHY_TYPE_NULL) { + bool found = FALSE; + int i = 0; + + inpo.phy_type = pov->phy_type; + inpo.band = pov->bandrange; + + par = malloc(strlen(pov->vars)+1); + if (!par) + return BCME_NOMEM; + + strcpy(par, pov->vars); + + /* Take care of cck and ofdm before walking through povars->vars */ + if (pov->bandrange == WL_CHAN_FREQ_RANGE_2G) { + p = find_pattern(argv, "cck2gpo", &val); + if (p) found = TRUE; + inpo.cckpo = p ? (uint16)val : 0; + + p = find_pattern(argv, "ofdm2gpo", &val); + } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GL) { + p = find_pattern(argv, "ofdm5glpo", &val); + } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GM) { + p = find_pattern(argv, "ofdm5gpo", &val); + } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GH) { + p = find_pattern(argv, "ofdm5ghpo", &val); + } + inpo.ofdmpo = p ? (uint32)val : 0; + if (p) found = TRUE; + + cpar = strtok (par, delimit); /* current param */ + do { + val = 0; + + /* Find the parameter in the input argument list */ + p = find_pattern(argv, cpar, &val); + if (p) found = TRUE; + inpo.mcspo[i] = p ? (uint16)val : 0; + i++; + } while ((cpar = strtok (NULL, delimit))); + + if (found) { + if ((err = wlu_var_setbuf(wl, cmd->name, &inpo, + sizeof(wl_po_t))) < 0) { + printf("wl_phy_povars: fail to set\n"); + free(par); + return err; + } + } + pov++; + free(par); + } + } else { /* get */ + while (pov->phy_type != PHY_TYPE_NULL) { + int i = 0; + wl_po_t *outpo; + + inpo.phy_type = pov->phy_type; + inpo.band = pov->bandrange; + + par = malloc(strlen(pov->vars)+1); + if (!par) + return BCME_NOMEM; + + strcpy(par, pov->vars); + + if ((err = wlu_var_getbuf(wl, cmd->name, &inpo, sizeof(povars_t), + &ptr)) < 0) { + printf("phy %x band %x err %d\n", pov->phy_type, + pov->bandrange, err); + free(par); + break; + } + + outpo = (wl_po_t*)ptr; + if (outpo->phy_type == PHY_TYPE_NULL) { + pov++; + free(par); + continue; + } + + /* Take care of cck and ofdm before walking through povars->vars */ + if (outpo->band == WL_CHAN_FREQ_RANGE_2G) { + printf("cck2gpo=0x%x\n", outpo->cckpo); + printf("ofdm2gpo=0x%x\n", outpo->ofdmpo); + } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GL) { + printf("ofdm5glpo=0x%x\n", outpo->ofdmpo); + } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GM) { + printf("ofdm5gpo=0x%x\n", outpo->ofdmpo); + } else if (pov->bandrange == WL_CHAN_FREQ_RANGE_5GH) { + printf("ofdm5ghpo=0x%x\n", outpo->ofdmpo); + } + + cpar = strtok(par, delimit); /* current param */ + do { + printf("%s=0x%x\n", cpar, outpo->mcspo[i++]); + } while ((cpar = strtok (NULL, delimit))); + + pov++; + free(par); + } + } + + return err; +} + +static int +wl_phy_rpcalvars(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0, k; + unsigned int val; + wl_rpcal_t rpcal[WL_NUM_RPCALVARS], *rpcal_out; + void *ptr = NULL; + + if (*++argv) { /* set */ + bool found = FALSE; + + /* initialization */ + memset(&(rpcal[0]), 0, sizeof(wl_rpcal_t)*WL_NUM_RPCALVARS); + + if (find_pattern(argv, "rpcal2g", &val)) { + found = TRUE; + rpcal[WL_CHAN_FREQ_RANGE_2G].value = (uint16) val; + rpcal[WL_CHAN_FREQ_RANGE_2G].update = 1; + } + + if (find_pattern(argv, "rpcal5gb0", &val)) { + found = TRUE; + rpcal[WL_CHAN_FREQ_RANGE_5G_BAND0].value = (uint16) val; + rpcal[WL_CHAN_FREQ_RANGE_5G_BAND0].update = 1; + } + + if (find_pattern(argv, "rpcal5gb1", &val)) { + found = TRUE; + rpcal[WL_CHAN_FREQ_RANGE_5G_BAND1].value = (uint16) val; + rpcal[WL_CHAN_FREQ_RANGE_5G_BAND1].update = 1; + } + + if (find_pattern(argv, "rpcal5gb2", &val)) { + found = TRUE; + rpcal[WL_CHAN_FREQ_RANGE_5G_BAND2].value = (uint16) val; + rpcal[WL_CHAN_FREQ_RANGE_5G_BAND2].update = 1; + } + + if (find_pattern(argv, "rpcal5gb3", &val)) { + found = TRUE; + rpcal[WL_CHAN_FREQ_RANGE_5G_BAND3].value = (uint16) val; + rpcal[WL_CHAN_FREQ_RANGE_5G_BAND3].update = 1; + } + + if (found) { + err = wlu_var_setbuf(wl, cmd->name, &(rpcal[0]), + sizeof(wl_rpcal_t)*WL_NUM_RPCALVARS); + if (err < 0) { + printf("wl_phy_rpcalvars: fail to set\n"); + return err; + } + } else { + printf("wl_phy_rpcalvars: fail to found matching rpcalvar name\n"); + return err; + } + + } else { /* get */ + + err = wlu_var_getbuf(wl, cmd->name, &(rpcal[0]), + sizeof(wl_rpcal_t)*WL_NUM_RPCALVARS, &ptr); + + if (err < 0) { + printf("wl_phy_rpcalvars: fail to get\n"); + return err; + } else { + rpcal_out = (wl_rpcal_t*) ptr; + } + + for (k = 0; k < WL_NUM_RPCALVARS; k++) { + + switch (k) { + case WL_CHAN_FREQ_RANGE_2G: + printf("rpcal2g=0x%x ", rpcal_out[k].value); + break; + case WL_CHAN_FREQ_RANGE_5G_BAND0: + printf("rpcal5gb0=0x%x ", rpcal_out[k].value); + break; + case WL_CHAN_FREQ_RANGE_5G_BAND1: + printf("rpcal5gb1=0x%x ", rpcal_out[k].value); + break; + case WL_CHAN_FREQ_RANGE_5G_BAND2: + printf("rpcal5gb2=0x%x ", rpcal_out[k].value); + break; + case WL_CHAN_FREQ_RANGE_5G_BAND3: + printf("rpcal5gb3=0x%x\n", rpcal_out[k].value); + break; + } + } + } + + return 0; +} + +static int +wl_phy_fem(void *wl, cmd_t *cmd, char **argv) +{ + srom_fem_t fem; + srom_fem_t *rfem; + void *ptr; + bool found = FALSE; + int err = 0; + uint val; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { /* write fem */ + + /* fem2g */ + memset(&fem, 0, sizeof(srom_fem_t)); + + if (find_pattern(argv, "tssipos2g", &val)) { + found = TRUE; + fem.tssipos = val; + } + + if (find_pattern(argv, "extpagain2g", &val)) { + found = TRUE; + fem.extpagain = val; + } + + if (find_pattern(argv, "pdetrange2g", &val)) { + found = TRUE; + fem.pdetrange = val; + } + + if (find_pattern(argv, "triso2g", &val)) { + found = TRUE; + fem.triso = val; + } + + if (find_pattern(argv, "antswctl2g", &val)) { + found = TRUE; + fem.antswctrllut = val; + } + + if (found) { + if ((err = wlu_var_setbuf(wl, "fem2g", &fem, sizeof(srom_fem_t)) < 0)) + printf("wl_phy_fem: fail to set fem2g\n"); + else + printf("fem2g set\n"); + } + + found = FALSE; + /* fem5g */ + memset(&fem, 0, sizeof(srom_fem_t)); + + if (find_pattern(argv, "tssipos5g", &val)) { + found = TRUE; + fem.tssipos = val; + } + + if (find_pattern(argv, "extpagain5g", &val)) { + found = TRUE; + fem.extpagain = val; + } + + if (find_pattern(argv, "pdetrange5g", &val)) { + found = TRUE; + fem.pdetrange = val; + } + + if (find_pattern(argv, "triso5g", &val)) { + found = TRUE; + fem.triso = val; + } + + if (find_pattern(argv, "antswctl5g", &val)) { + found = TRUE; + fem.antswctrllut = val; + } + + if (found) { + if ((err = wlu_var_setbuf(wl, "fem5g", &fem, sizeof(srom_fem_t)) < 0)) + printf("wl_phy_fem: fail to set fem5g\n"); + else + printf("fem5g set\n"); + } + } else { + if ((err = wlu_var_getbuf(wl, "fem2g", NULL, 0, (void**)&ptr) < 0)) { + printf("wl_phy_fem: fail to get fem2g\n"); + } else { + rfem = (srom_fem_t*)ptr; /* skip the "fem2g" */ + printf("tssipos2g=0x%x extpagain2g=0x%x pdetrange2g=0x%x" + " triso2g=0x%x antswctl2g=0x%x\n", + rfem->tssipos, rfem->extpagain, rfem->pdetrange, + rfem->triso, rfem->antswctrllut); + } + + if ((err = wlu_var_getbuf(wl, "fem5g", NULL, 0, (void**)&ptr) < 0)) { + printf("wl_phy_fem: fail to get fem5g\n"); + } else { + rfem = (srom_fem_t*)ptr; /* skip the "fem2g" */ + printf("tssipos5g=0x%x extpagain5g=0x%x pdetrange5g=0x%x" + " triso5g=0x%x antswctl5g=0x%x\n", + rfem->tssipos, rfem->extpagain, rfem->pdetrange, + rfem->triso, rfem->antswctrllut); + } + } + + return err; +} + +static int +wl_phy_maxpower(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + uint val; + uint8 maxp[8]; + void *ptr; + uint8 *rmaxp; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { /* write maxpower */ + + if (find_pattern(argv, "maxp2ga0", &val)) + maxp[0] = val; + else + printf("Missing maxp2ga0\n"); + + if (find_pattern(argv, "maxp2ga1", &val)) + maxp[1] = val; + else + printf("Missing maxp2ga1\n"); + + if (find_pattern(argv, "maxp5ga0", &val)) + maxp[2] = val; + else + printf("Missing maxp5ga0\n"); + + if (find_pattern(argv, "maxp5ga1", &val)) + maxp[3] = val; + else + printf("Missing maxp5ga1\n"); + + if (find_pattern(argv, "maxp5gla0", &val)) + maxp[4] = val; + else + printf("Missing maxp5gla0\n"); + + if (find_pattern(argv, "maxp5gla1", &val)) + maxp[5] = val; + else + printf("Missing maxp5gla1\n"); + + if (find_pattern(argv, "maxp5gha0", &val)) + maxp[6] = val; + else + printf("Missing maxp5gha0\n"); + + if (find_pattern(argv, "maxp5gha1", &val)) + maxp[7] = val; + else + printf("Missing maxp5gha1\n"); + + if ((err = wlu_var_setbuf(wl, "maxpower", &maxp, 8 * sizeof(uint8)) < 0)) { + printf("wl_phy_maxpower: fail to set\n"); + } + } else { + if ((err = wlu_var_getbuf(wl, "maxpower", NULL, 0, &ptr) < 0)) { + printf("wl_phy_maxpower: fail to get maxpower\n"); + return err; + } + rmaxp = (uint8*)ptr; + printf("maxp2ga0=%x\n", rmaxp[0]); + printf("maxp2ga1=%x\n", rmaxp[1]); + printf("maxp5ga0=%x\n", rmaxp[2]); + printf("maxp5ga1=%x\n", rmaxp[3]); + printf("maxp5gla0=%x\n", rmaxp[4]); + printf("maxp5gla1=%x\n", rmaxp[5]); + printf("maxp5gha0=%x\n", rmaxp[6]); + printf("maxp5gha1=%x\n", rmaxp[7]); + } + + return err; +} + +static int +wl_antgain(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + uint val; + uint8 ag[2]; + uint8 *rag; + void *ptr; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { /* write maxpower */ + if (find_pattern(argv, "ag0", &val)) + ag[0] = val & 0xff; + else { + printf("Missing ag0\n"); + return BCME_USAGE_ERROR; + } + + if (find_pattern(argv, "ag1", &val)) + ag[1] = val & 0xff; + else { + printf("Missing ag1\n"); + return BCME_USAGE_ERROR; + } + + if ((err = wlu_var_setbuf(wl, "antgain", &ag, 2 * sizeof(uint8)) < 0)) { + printf("wl_antgain: fail to set\n"); + } + } else { + if ((err = wlu_var_getbuf(wl, "antgain", NULL, 0, &ptr) < 0)) { + printf("wl_antgain: fail to get antgain\n"); + return err; + } + rag = (uint8*)ptr; + printf("ag0=%x\n", rag[0]); + printf("ag1=%x\n", rag[1]); + } + + return err; +} + +static int +wl_pkteng(void *wl, cmd_t *cmd, char **argv) +{ + wl_pkteng_t pkteng; + + memset(&pkteng, 0, sizeof(pkteng)); + if (strcmp(cmd->name, "pkteng_stop") == 0) { + if (!*++argv) + return BCME_USAGE_ERROR; + if (strcmp(*argv, "tx") == 0) + pkteng.flags = WL_PKTENG_PER_TX_STOP; + else if (strcmp(*argv, "rx") == 0) + pkteng.flags = WL_PKTENG_PER_RX_STOP; + else + return BCME_USAGE_ERROR; + } + else if (strcmp(cmd->name, "pkteng_start") == 0) { + if (!*++argv) + return BCME_USAGE_ERROR; + if (!wl_ether_atoe(*argv, (struct ether_addr *)&pkteng.dest)) + return BCME_USAGE_ERROR; + if (!*++argv) + return BCME_USAGE_ERROR; + if ((strcmp(*argv, "tx") == 0) || (strcmp(*argv, "txwithack") == 0)) { + if (strcmp(*argv, "tx") == 0) + pkteng.flags = WL_PKTENG_PER_TX_START; + else + pkteng.flags = WL_PKTENG_PER_TX_WITH_ACK_START; + if (!*++argv) + return BCME_USAGE_ERROR; + if (strcmp(*argv, "async") == 0) + pkteng.flags &= ~WL_PKTENG_SYNCHRONOUS; + else if (strcmp(*argv, "sync") == 0) + pkteng.flags |= WL_PKTENG_SYNCHRONOUS; + else + /* neither optional parameter [async|sync] */ + --argv; + if (!*++argv) + return BCME_USAGE_ERROR; + pkteng.delay = strtoul(*argv, NULL, 0); + if (!*++argv) + return BCME_USAGE_ERROR; + pkteng.length = strtoul(*argv, NULL, 0); + if (!*++argv) + return BCME_USAGE_ERROR; + pkteng.nframes = strtoul(*argv, NULL, 0); + if (*++argv) + if (!wl_ether_atoe(*argv, (struct ether_addr *)&pkteng.src)) + return BCME_USAGE_ERROR; + } + else if ((strcmp(*argv, "rx") == 0) || (strcmp(*argv, "rxwithack") == 0)) { + if ((strcmp(*argv, "rx") == 0)) + pkteng.flags = WL_PKTENG_PER_RX_START; + else + pkteng.flags = WL_PKTENG_PER_RX_WITH_ACK_START; + + if (*++argv) { + if (strcmp(*argv, "async") == 0) + pkteng.flags &= ~WL_PKTENG_SYNCHRONOUS; + else if (strcmp(*argv, "sync") == 0) { + pkteng.flags |= WL_PKTENG_SYNCHRONOUS; + /* sync mode requires number of frames and timeout */ + if (!*++argv) + return BCME_USAGE_ERROR; + pkteng.nframes = strtoul(*argv, NULL, 0); + if (!*++argv) + return BCME_USAGE_ERROR; + pkteng.delay = strtoul(*argv, NULL, 0); + } + } + } + else + return BCME_USAGE_ERROR; + } + else { + printf("Invalid command name %s\n", cmd->name); + return 0; + } + + pkteng.flags = htod32(pkteng.flags); + pkteng.delay = htod32(pkteng.delay); + pkteng.nframes = htod32(pkteng.nframes); + pkteng.length = htod32(pkteng.length); + + return (wlu_var_setbuf(wl, "pkteng", &pkteng, sizeof(pkteng))); +} + +static int +wl_rxiq(void *wl, cmd_t *cmd, char **argv) +{ + miniopt_t to; + const char* fn_name = "wl_rxiqest"; + int err, argc, opt_err; + uint32 rxiq; + uint8 resolution = 0; + uint8 lpf_hpc = 1; + uint8 dig_lpf = 1; + uint8 gain_correct = 0; + uint8 extra_gain_3dBsteps = 0; + uint8 force_gain_type = 0; + uint8 antenna = 3; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + + /* DEFAULT: + * gain_correct = 0 (disable gain correction), + * lpf_hpc = 1 (sets lpf hpc to lowest value), + * dig_lpf = 1; (sets to ltrn_lpf mode) + * resolution = 0 (coarse), + * samples = 1024 (2^10) and antenna = 3 + * force_gain_type = 0 (init gain mode) + */ + rxiq = (extra_gain_3dBsteps << 28) | (gain_correct << 24) | (dig_lpf << 22) + | (lpf_hpc << 20) | (resolution << 16) | (10 << 8) | (force_gain_type << 4) + | antenna; + + if (argc != 0) { + miniopt_init(&to, fn_name, NULL, FALSE); + while ((opt_err = miniopt(&to, argv)) != -1) { + if (opt_err == 1) { + err = BCME_USAGE_ERROR; + goto exit; + } + argv += to.consumed; + + if (to.opt == 'g') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int" + " for gain-correction (0, 1, 2, 3, 4, 7, 8)\n", + fn_name, to.valstr); + + err = BCME_BADARG; + goto exit; + } + if ((to.val < 0) || (to.val > 8)) { + fprintf(stderr, "%s: invalid gain-correction select %d" + " (0,1,2,3,4,7,8)\n", fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + gain_correct = to.val & 0xf; + rxiq = ((gain_correct << 24) | (rxiq & 0xf0ffffff)); + } + if (to.opt == 'f') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int" + " for lpf-hpc override select (0, 1)\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val < 0) || (to.val > 1)) { + fprintf(stderr, "%s: invalid lpf-hpc override select %d" + " (0,1)\n", fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + lpf_hpc = to.val & 0xf; + rxiq = ((lpf_hpc << 20) | (rxiq & 0xff0fffff)); + } + if (to.opt == 'w') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int" + " for dig-lpf override select (0, 1 or 2)\n", + fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val < 0) || (to.val > 2)) { + fprintf(stderr, "%s: invalid dig-lpf override select %d" + " (0,1,2)\n", fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + dig_lpf = to.val & 0x3; + rxiq = ((dig_lpf << 22) | (rxiq & 0xff3fffff)); + } + if (to.opt == 'r') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int" + " for resolution (0, 1)\n", fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val < 0) || (to.val > 1)) { + fprintf(stderr, "%s: invalid resolution select %d" + " (0,1)\n", fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + resolution = to.val & 0xf; + rxiq = ((resolution << 16) | (rxiq & 0xfff0ffff)); + } + if (to.opt == 's') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int for" + " the sample count\n", fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if (to.val < 0 || to.val > 16) { + fprintf(stderr, "%s: sample count too large %d" + "(10 <= x <= 16)\n", fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + rxiq = (((to.val & 0xff) << 8) | (rxiq & 0xffff00ff)); + } + if (to.opt == 'a') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int" + " for antenna (0, 1, 3)\n", fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val < 0) || (to.val > 3)) { + fprintf(stderr, "%s: invalid antenna select %d\n", + fn_name, to.val); + err = BCME_BADARG; + goto exit; + } + rxiq = ((rxiq & 0xffffff00) | (to.val & 0xff)); + } + if (to.opt == 'e') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int" + " for extra INITgain\n", fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val < 0) || (to.val > 24) || (to.val % 3 != 0)) { + fprintf(stderr, + "%s: Valid extra INITgain = {0, 3, .., 21, 24}\n", + fn_name); + err = BCME_BADARG; + goto exit; + } + rxiq = ((((to.val/3) & 0xf) << 28) | (rxiq & 0x0fffffff)); + } + if (to.opt == 'i') { + if (!to.good_int) { + fprintf(stderr, + "%s: could not parse \"%s\" as an int" + " for init or clipLO mode\n", fn_name, to.valstr); + err = BCME_BADARG; + goto exit; + } + if ((to.val != 0) && (to.val != 1) && + (to.val != 2) && (to.val != 3) && (to.val != 4)) { + fprintf(stderr, + "%s: Valid options - 0(default gain), 1(fixed high gain)" + "or 4(fixed low gain). \n", + fn_name); + err = BCME_BADARG; + goto exit; + } + rxiq = ((rxiq & 0xffffff0f) | ((to.val << 4) & 0xf0)); + } + } + } + + if ((err = wlu_iovar_setint(wl, cmd->name, (int)rxiq)) < 0) + return err; + if ((err = wlu_iovar_getint(wl, cmd->name, (int*)&rxiq)) < 0) + return err; + + if (resolution == 1) { + /* fine resolution power reporting (0.25dB resolution) */ + uint8 core; + int16 tmp; + if (rxiq >> 20) { + /* Three chains: */ + for (core = 0; core < 3; core ++) { + tmp = (rxiq >> (10*core)) & 0x3ff; + tmp = ((int16)(tmp << 6)) >> 6; /* sign extension */ + if (tmp < 0) { + tmp = -1*tmp; + printf("-%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25); + } else { + printf("%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25); + } + } + printf("\n"); + } else if (rxiq >> 10) { + /* 2 chains */ + for (core = 0; core < 2; core ++) { + tmp = (rxiq >> (10*core)) & 0x3ff; + tmp = ((int16)(tmp << 6)) >> 6; /* sign extension */ + if (tmp < 0) { + tmp = -1*tmp; + printf("-%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25); + } else { + printf("%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25); + } + } + printf("\n"); + } else { + /* 1 chain */ + tmp = rxiq & 0x3ff; + tmp = ((int16)(tmp << 6)) >> 6; /* sign extension */ + if (tmp < 0) { + tmp = -1*tmp; + printf("-%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25); + } else { + printf("%d.%ddBm ", (tmp >> 2), (tmp & 0x3)*25); + } + printf("\n"); + } + } else { + if (rxiq >> 16) + printf("%ddBm %ddBm %ddBm\n", (int8)(rxiq & 0xff), + (int8)((rxiq >> 8) & 0xff), (int8)((rxiq >> 16) & 0xff)); + else if (rxiq >> 8) + printf("%ddBm %ddBm\n", (int8)(rxiq & 0xff), (int8)((rxiq >> 8) & 0xff)); + else + printf("%ddBm\n", (int8)(rxiq & 0xff)); + } +exit: + return err; +} + +/* Convert user's input in hex pattern to byte-size mask */ +static int +wl_pattern_atoh(char *src, char *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && + strncmp(src, "0X", 2) != 0) { + printf("Data invalid format. Needs to start with 0x\n"); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + printf("Data invalid format. Needs to be of even length\n"); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + strncpy(num, src, 2); + num[2] = '\0'; + dst[i] = (uint8)strtoul(num, NULL, 16); + src += 2; + } + return i; +} + +static int +wl_wowl_status(void *wl, cmd_t *cmd, char **argv) +{ + int flags_prev = 0; + int err; + + UNUSED_PARAMETER(cmd); + + argv++; + + if ((err = wlu_iovar_getint(wl, "wowl_status", &flags_prev))) + return err; + + printf("Status of last wakeup:\n"); + printf("\tflags:0x%x\n", flags_prev); + + if (flags_prev & WL_WOWL_BCN) + printf("\t\tWake-on-Loss-of-Beacons enabled\n"); + + if (flags_prev & WL_WOWL_MAGIC) + printf("\t\tWake-on-Magic frame enabled\n"); + if (flags_prev & WL_WOWL_NET) + printf("\t\tWake-on-Net pattern enabled\n"); + if (flags_prev & WL_WOWL_DIS) + printf("\t\tWake-on-Deauth enabled\n"); + + if (flags_prev & WL_WOWL_RETR) + printf("\t\tRetrograde TSF enabled\n"); + if (flags_prev & WL_WOWL_TST) + printf("\t\tTest-mode enabled\n"); + + printf("\n"); + + return 0; +} + +static int +wl_wowl_wakeind(void *wl, cmd_t *cmd, char **argv) +{ + wl_wowl_wakeind_t wake = {0, 0}; + int err; + + UNUSED_PARAMETER(cmd); + + argv++; + + if (*argv) { + if (strcmp(*argv, "clear")) + return BCME_USAGE_ERROR; + err = wlu_iovar_set(wl, "wowl_wakeind", *argv, strlen(*argv)); + return err; + } + + if ((err = wlu_iovar_get(wl, "wowl_wakeind", &wake, sizeof(wl_wowl_wakeind_t))) < 0) + return err; + + if (wake.pci_wakeind) + printf("PCI Indication set\n"); + if (wake.ucode_wakeind != 0) { + printf("MAC Indication set\n"); + + if ((wake.ucode_wakeind & WL_WOWL_MAGIC) == WL_WOWL_MAGIC) + printf("\tMAGIC packet received\n"); + if ((wake.ucode_wakeind & WL_WOWL_NET) == WL_WOWL_NET) + printf("\tPacket received with Netpattern\n"); + if ((wake.ucode_wakeind & WL_WOWL_DIS) == WL_WOWL_DIS) + printf("\tDisassociation/Deauth received\n"); + if ((wake.ucode_wakeind & WL_WOWL_RETR) == WL_WOWL_RETR) + printf("\tRetrograde TSF detected\n"); + if ((wake.ucode_wakeind & WL_WOWL_BCN) == WL_WOWL_BCN) + printf("\tBeacons Lost\n"); + if ((wake.ucode_wakeind & WL_WOWL_TST) == WL_WOWL_TST) + printf("\tTest Mode\n"); + if ((wake.ucode_wakeind & WL_WOWL_M1) == WL_WOWL_M1) + printf("\tPTK Refresh received.\n"); + if ((wake.ucode_wakeind & WL_WOWL_EAPID) == WL_WOWL_EAPID) + printf("\tEAP-Identity request received\n"); + if ((wake.ucode_wakeind & WL_WOWL_GTK_FAILURE) == WL_WOWL_GTK_FAILURE) + printf("\tWake on GTK failure.\n"); + if ((wake.ucode_wakeind & WL_WOWL_EXTMAGPAT) == WL_WOWL_EXTMAGPAT) + printf("\tExtended Magic Packet received.\n"); + + if ((wake.ucode_wakeind & WL_WOWL_KEYROT) == WL_WOWL_KEYROT) + printf("\tKey Rotation Packet received.\n"); + if ((wake.ucode_wakeind & WL_WOWL_SCANOL) == WL_WOWL_SCANOL) + printf("\tWake on Scan offload.\n"); + if ((wake.ucode_wakeind & WL_WOWL_MDNS_CONFLICT) == WL_WOWL_MDNS_CONFLICT) + printf("\tWake on MDNS Conflict.\n"); + if ((wake.ucode_wakeind & WL_WOWL_MDNS_SERVICE) == WL_WOWL_MDNS_SERVICE) + printf("\tWake on MDNS Service.\n"); + if ((wake.ucode_wakeind & WL_WOWL_TCPKEEP_DATA) == WL_WOWL_TCPKEEP_DATA) + printf("\tWake on TCP Keepalive Data.\n"); + if ((wake.ucode_wakeind & WL_WOWL_TCPKEEP_TIME) == WL_WOWL_TCPKEEP_TIME) + printf("\tWake on TCP Keepalive Timeout.\n"); + if ((wake.ucode_wakeind & WL_WOWL_FW_HALT) == WL_WOWL_FW_HALT) + printf("\tWake on Firmware died in wowl mode.\n"); + + + if ((wake.ucode_wakeind & (WL_WOWL_NET | WL_WOWL_MAGIC | WL_WOWL_EXTMAGPAT))) { + if ((wake.ucode_wakeind & WL_WOWL_BCAST) == WL_WOWL_BCAST) + printf("\t\tBroadcast/Mcast frame received\n"); + else + printf("\t\tUnicast frame received\n"); + } + } + + if (!wake.pci_wakeind && wake.ucode_wakeind == 0) + printf("No wakeup indication set\n"); + + return 0; +} +/* Used by NINTENDO2 */ +static int +wl_wowl_wake_reason(void *wl, cmd_t *cmd, char **argv) +{ + int err = -1; + wl_wr_t wr; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) { + err = wlu_iovar_get(wl, "wakeup_reason", &wr, sizeof(wl_wr_t)); + if (err) + return err; + + if (wr.reason && wr.reason < REASON_LAST) { + printf("ID: %d\t", wr.id); + + if (wr.reason == LCD_ON) + printf("Reason: LCD_ON\n"); + else if (wr.reason == LCD_OFF) + printf("Reason: LCD_OFF\n"); + else if (wr.reason == DRC1_WAKE) + printf("Reason: DRC1_WAKE\n"); + else if (wr.reason == DRC2_WAKE) + printf("Reason: DRC2_WAKE\n"); + } + else + printf("Unknown wakeup Reason\n"); + } + return err; +} + +/* Send a wakeup frame to sta in WAKE mode */ +static int +wl_wowl_pkt(void *wl, cmd_t *cmd, char **argv) +{ + char *arg = buf; + const char *str; + char *dst; + uint tot = 0; + uint16 type, pkt_len; + int dst_ea = 0; /* 0 == manual, 1 == bcast, 2 == ucast */ + char *ea[ETHER_ADDR_LEN]; + if (!*++argv) + return BCME_USAGE_ERROR; + + UNUSED_PARAMETER(cmd); + + str = "wowl_pkt"; + strncpy(arg, str, strlen(str)); + arg[strlen(str)] = '\0'; + dst = arg + strlen(str) + 1; + tot += strlen(str) + 1; + + pkt_len = (uint16)htod32(strtoul(*argv, NULL, 0)); + + *((uint16*)dst) = pkt_len; + + dst += sizeof(pkt_len); + tot += sizeof(pkt_len); + + if (!*++argv) { + printf("Dest of the packet needs to be provided\n"); + return BCME_USAGE_ERROR; + } + + /* Dest of the frame */ + if (!strcmp(*argv, "bcast")) { + dst_ea = 1; + if (!wl_ether_atoe("ff:ff:ff:ff:ff:ff", (struct ether_addr *)dst)) + return BCME_USAGE_ERROR; + } else if (!strcmp(*argv, "ucast")) { + dst_ea = 2; + if (!*++argv) { + printf("EA of ucast dest of the packet needs to be provided\n"); + return BCME_USAGE_ERROR; + } + if (!wl_ether_atoe(*argv, (struct ether_addr *)dst)) + return BCME_USAGE_ERROR; + /* Store it */ + memcpy(ea, dst, ETHER_ADDR_LEN); + } else if (!wl_ether_atoe(*argv, (struct ether_addr *)dst)) + return BCME_USAGE_ERROR; + + dst += ETHER_ADDR_LEN; + tot += ETHER_ADDR_LEN; + + if (!*++argv) { + printf("type - magic/net needs to be provided\n"); + return BCME_USAGE_ERROR; + } + + if (strncmp(*argv, "magic", strlen("magic")) == 0) + type = WL_WOWL_MAGIC; + else if (strncmp(*argv, "net", strlen("net")) == 0) + type = WL_WOWL_NET; + else if (strncmp(*argv, "eapid", strlen("eapid")) == 0) + type = WL_WOWL_EAPID; + else + return BCME_USAGE_ERROR; + + *((uint16*)dst) = type; + dst += sizeof(type); + tot += sizeof(type); + + if (type == WL_WOWL_MAGIC) { + if (pkt_len < MAGIC_PKT_MINLEN) + return BCME_BADARG; + + if (dst_ea == 2) + memcpy(dst, ea, ETHER_ADDR_LEN); + else { + if (!*++argv) + return BCME_USAGE_ERROR; + + if (!wl_ether_atoe(*argv, (struct ether_addr *)dst)) + return BCME_USAGE_ERROR; + } + tot += ETHER_ADDR_LEN; + } else if (type == WL_WOWL_NET) { + wl_wowl_pattern_t *wl_pattern; + wl_pattern = (wl_wowl_pattern_t *)dst; + + if (!*++argv) { + printf("Starting offset not provided\n"); + return BCME_USAGE_ERROR; + } + + wl_pattern->offset = (uint)htod32(strtoul(*argv, NULL, 0)); + + wl_pattern->masksize = 0; + + wl_pattern->patternoffset = (uint)htod32(sizeof(wl_wowl_pattern_t)); + + dst += sizeof(wl_wowl_pattern_t); + + if (!*++argv) { + printf("pattern not provided\n"); + return BCME_USAGE_ERROR; + } + + wl_pattern->patternsize = + (uint)htod32(wl_pattern_atoh((char *)(uintptr)*argv, dst)); + dst += wl_pattern->patternsize; + tot += sizeof(wl_wowl_pattern_t) + wl_pattern->patternsize; + + wl_pattern->reasonsize = 0; + if (*++argv) { + wl_pattern->reasonsize = + (uint)htod32(wl_pattern_atoh((char *)(uintptr)*argv, dst)); + tot += wl_pattern->reasonsize; + } + } else { /* eapid */ + if (!*++argv) { + printf("EAPOL identity string not provided\n"); + return BCME_USAGE_ERROR; + } + + *dst++ = strlen(*argv); + strncpy(dst, *argv, strlen(*argv)); + tot += 1 + strlen(*argv); + } + return (wlu_set(wl, WLC_SET_VAR, arg, tot)); +} + +static int +wl_wowl_pattern(void *wl, cmd_t *cmd, char **argv) +{ + int err; + uint i, j; + uint8 *ptr; + wl_wowl_pattern_t *wl_pattern; + + UNUSED_PARAMETER(cmd); + + if (*++argv) { + char *arg = buf; + const char *str; + char *dst; + uint tot = 0; + + if (strcmp(*argv, "add") != 0 && strcmp(*argv, "del") != 0 && + strcmp(*argv, "clr") != 0) { + return BCME_USAGE_ERROR; + } + + str = "wowl_pattern"; + strncpy(arg, str, strlen(str)); + arg[strlen(str)] = '\0'; + dst = arg + strlen(str) + 1; + tot += strlen(str) + 1; + + str = *argv; + strncpy(dst, str, strlen(str)); + tot += strlen(str) + 1; + + if (strcmp(str, "clr") != 0) { + wl_pattern = (wl_wowl_pattern_t *)(dst + strlen(str) + 1); + dst = (char*)wl_pattern + sizeof(wl_wowl_pattern_t); + if (!*++argv) { + printf("Starting offset not provided\n"); + return BCME_USAGE_ERROR; + } + wl_pattern->offset = htod32(strtoul(*argv, NULL, 0)); + if (!*++argv) { + printf("Mask not provided\n"); + return BCME_USAGE_ERROR; + } + + /* Parse the mask */ + str = *argv; + wl_pattern->masksize = htod32(wl_pattern_atoh((char *)(uintptr)str, dst)); + if (wl_pattern->masksize == (uint)-1) + return BCME_USAGE_ERROR; + + dst += wl_pattern->masksize; + wl_pattern->patternoffset = htod32((sizeof(wl_wowl_pattern_t) + + wl_pattern->masksize)); + + if (!*++argv) { + printf("Pattern value not provided\n"); + return BCME_USAGE_ERROR; + } + + /* Parse the value */ + str = *argv; + wl_pattern->patternsize = + htod32(wl_pattern_atoh((char *)(uintptr)str, dst)); + if (wl_pattern->patternsize == (uint)-1) + return BCME_USAGE_ERROR; + tot += sizeof(wl_wowl_pattern_t) + wl_pattern->patternsize + + wl_pattern->masksize; + } + + return (wlu_set(wl, WLC_SET_VAR, arg, tot)); + } else { + wl_wowl_pattern_list_t *list; + if ((err = wlu_iovar_get(wl, "wowl_pattern", buf, WLC_IOCTL_MAXLEN)) < 0) + return err; + list = (wl_wowl_pattern_list_t *)buf; + printf("#of patterns :%d\n", list->count); + ptr = (uint8 *)list->pattern; + for (i = 0; i < list->count; i++) { + uint8 *pattern; + + wl_pattern = (wl_wowl_pattern_t *)ptr; + printf("Pattern %d:\n", i+1); + printf("ID :0x%x\n" + "Offset :%d\n" + "Masksize :%d\n" + "Mask :0x", + (uint32)wl_pattern->id, wl_pattern->offset, wl_pattern->masksize); + pattern = ((uint8 *)wl_pattern + sizeof(wl_wowl_pattern_t)); + for (j = 0; j < wl_pattern->masksize; j++) + printf("%02x", pattern[j]); + printf("\n" + "PatternSize:%d\n" + "Pattern :0x", wl_pattern->patternsize); + /* Go to end to find pattern */ + pattern = ((uint8*)wl_pattern + wl_pattern->patternoffset); + for (j = 0; j < wl_pattern->patternsize; j++) + printf("%02x", pattern[j]); + printf("\n\n"); + ptr += (wl_pattern->masksize + wl_pattern->patternsize + + sizeof(wl_wowl_pattern_t)); + } + } + + return err; +} + + +static int +wl_wowl_extended_magic(void *wl, cmd_t *cmd, char **argv) +{ + char *arg = buf; + const char *str; + char *dst; + uint tot; + int ret; + + str = "wowl_ext_magic"; + strncpy(arg, str, strlen(str)); + arg[strlen(str)] = '\0'; + + if (*++argv) { + dst = arg + strlen(str) + 1; + tot = strlen(str) + 1; + ret = wl_pattern_atoh(*argv, dst); + if (ret == -1) + return BCME_USAGE_ERROR; + if (ret != 6) { + printf("Extended magic pattern must be 6-byte length\n"); + return BCME_USAGE_ERROR; + } + tot += 6; + + ret = wlu_set(wl, cmd->set, arg, tot); + return ret; + } + + + if ((ret = wlu_get(wl, cmd->get, arg, WLC_IOCTL_MAXLEN)) < 0) + return ret; + + printf("0x"); + for (ret = 0; ret < 6; ret++) + printf("%02x", (uint8)arg[ret]); + printf("\n"); + + return 0; + +} + + +static int +wl_rifs(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int val, rifs; + char *val_name; + + UNUSED_PARAMETER(cmd); + + /* command name */ + val_name = *argv++; + + if (!*argv) { + if ((err = wlu_iovar_getint(wl, val_name, (int*)&rifs)) < 0) + return err; + + printf("%s\n", ((rifs & 0xff) ? "On" : "Off")); + return 0; + } + + val = rifs = (atoi(*argv) ? 1 : 0); + if (rifs != 0 && rifs != 1) + return BCME_USAGE_ERROR; + + if ((err = wlu_set(wl, WLC_SET_FAKEFRAG, &val, sizeof(int))) < 0) { + printf("Set frameburst error %d\n", err); + return err; + } + if ((err = wlu_iovar_setint(wl, val_name, (int)rifs)) < 0) + printf("Set rifs error %d\n", err); + + return err; +} + +static int +wl_rifs_advert(void *wl, cmd_t *cmd, char **argv) +{ + int err; + int rifs_advert; + char *val_name; + + BCM_REFERENCE(cmd); + + /* command name */ + val_name = *argv++; + + if (!*argv) { + if ((err = wlu_iovar_getint(wl, val_name, (int*)&rifs_advert)) < 0) + return err; + + printf("%s\n", ((rifs_advert & 0xff) ? "On" : "Off")); + return 0; + } + + if (strcmp(*argv, "-1") && strcmp(*argv, "0")) + return BCME_USAGE_ERROR; + + rifs_advert = atoi(*argv); + + if ((err = wlu_iovar_setint(wl, val_name, (int)rifs_advert)) < 0) + printf("Set rifs mode advertisement error %d\n", err); + + return err; +} + +/* this is the batched command packet size. now for remoteWL, we set it to 512 bytes */ +#define MEMBLOCK (512 - 32) /* allow 32 bytes for overhead (header, alignment, etc) */ + +int wl_seq_batch_in_client(bool enable) +{ + batch_in_client = enable; + return 0; +} + + +int +wl_seq_start(void *wl, cmd_t *cmd, char **argv) +{ + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + if (!batch_in_client) { + return wlu_iovar_setbuf(wl, "seq_start", NULL, 0, buf, WLC_IOCTL_MAXLEN); + } + else { + if (cmd_batching_mode) { + printf("calling seq_start() when it's already in batching mode\n"); + clean_up_cmd_list(); + cmd_batching_mode = FALSE; + return BCME_USAGE_ERROR; + } + else { + cmd_batching_mode = TRUE; + cmd_pkt_list_num = 0; + + cmd_list.head = NULL; + cmd_list.tail = NULL; + } + } + + return 0; +} + +int +wl_seq_stop(void *wl, cmd_t *cmd, char **argv) +{ + char *bufp; + int ret = 0; + int seq_list_len; + int len; + wl_seq_cmd_pkt_t *next_cmd; + + UNUSED_PARAMETER(cmd); + UNUSED_PARAMETER(argv); + + if (!batch_in_client) { + return wlu_iovar_setbuf(wl, "seq_stop", NULL, 0, buf, WLC_IOCTL_MAXLEN); + } + else { + if (!cmd_batching_mode) { + printf("calling seq_stop when it's already out of batching mode\n"); + return BCME_USAGE_ERROR; + } + cmd_batching_mode = FALSE; + + next_cmd = cmd_list.head; + + /* dump batched commands to the DUT */ + + if (next_cmd == NULL) { + printf("no command batched\n"); + return BCME_USAGE_ERROR; + } + + ret = wlu_iovar_setbuf(wl, "seq_start", NULL, 0, buf, WLC_IOCTL_MAXLEN); + if (ret) { + printf("failed to send seq_start\n"); + goto fail; + } + + while (next_cmd != NULL) { + bufp = buf; + memset(bufp, 0, WLC_IOCTL_MAXLEN); + + strcpy(bufp, "seq_list"); + bufp += (strlen("seq_list") + 1); + bufp = ALIGN_ADDR(bufp, WL_SEQ_CMD_ALIGN_BYTES); + seq_list_len = bufp - buf; + + while ((seq_list_len < MEMBLOCK) && (next_cmd != NULL)) { + len = ROUNDUP(next_cmd->cmd_header.len, WL_SEQ_CMD_ALIGN_BYTES); + len += (seq_list_len + sizeof(wl_seq_cmd_ioctl_t)); + + if (len < MEMBLOCK) { + memcpy(bufp, &(next_cmd->cmd_header), + sizeof(wl_seq_cmd_ioctl_t)); + bufp += sizeof(wl_seq_cmd_ioctl_t); + memcpy(bufp, next_cmd->data, next_cmd->cmd_header.len); + bufp += next_cmd->cmd_header.len; + bufp = ALIGN_ADDR(bufp, WL_SEQ_CMD_ALIGN_BYTES); + seq_list_len = len; + + next_cmd = next_cmd->next; + } + else + break; + } + + ret = wl_set(wl, WLC_SET_VAR, &buf[0], seq_list_len); + + if (ret) { + printf("failed to send seq_list\n"); + goto fail; + } + } + + ret = wlu_iovar_setbuf(wl, "seq_stop", NULL, 0, buf, WLC_IOCTL_MAXLEN); + if (ret) { + printf("failed to send seq_stop\n"); + } + + fail: + clean_up_cmd_list(); + return ret; + } +} + +static int +wl_obss_scan_params_range_chk(wl_obss_scan_arg_t *obss_scan_arg) +{ + if (obss_scan_arg->passive_dwell < 0) + obss_scan_arg->passive_dwell = WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT; + else if (obss_scan_arg->passive_dwell < WLC_OBSS_SCAN_PASSIVE_DWELL_MIN || + obss_scan_arg->passive_dwell > WLC_OBSS_SCAN_PASSIVE_DWELL_MAX) { + printf("passive dwell not in range %d\n", obss_scan_arg->passive_dwell); + return -1; + } + + if (obss_scan_arg->active_dwell < 0) + obss_scan_arg->active_dwell = WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT; + else if (obss_scan_arg->active_dwell < WLC_OBSS_SCAN_ACTIVE_DWELL_MIN || + obss_scan_arg->active_dwell > WLC_OBSS_SCAN_ACTIVE_DWELL_MAX) { + printf("active dwell not in range %d\n", obss_scan_arg->active_dwell); + return -1; + } + + if (obss_scan_arg->bss_widthscan_interval < 0) + obss_scan_arg->bss_widthscan_interval = + WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT; + else if (obss_scan_arg->bss_widthscan_interval < WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN || + obss_scan_arg->bss_widthscan_interval > WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX) { + printf("Width Trigger Scan Interval not in range %d\n", + obss_scan_arg->bss_widthscan_interval); + return -1; + } + + if (obss_scan_arg->chanwidth_transition_delay < 0) + obss_scan_arg->chanwidth_transition_delay = + WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT; + else if ((obss_scan_arg->chanwidth_transition_delay < + WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN) || + (obss_scan_arg->chanwidth_transition_delay > + WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX)) { + printf("Width Channel Transition Delay Factor not in range %d\n", + obss_scan_arg->chanwidth_transition_delay); + return -1; + } + + if (obss_scan_arg->passive_total < 0) + obss_scan_arg->passive_total = WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT; + else if (obss_scan_arg->passive_total < WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN || + obss_scan_arg->passive_total > WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX) { + printf("Passive Total per Channel not in range %d\n", obss_scan_arg->passive_total); + return -1; + } + + if (obss_scan_arg->active_total < 0) + obss_scan_arg->active_total = WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT; + if (obss_scan_arg->active_total < WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN || + obss_scan_arg->active_total > WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX) { + printf("Active Total per Channel not in range %d\n", obss_scan_arg->active_total); + return -1; + } + + if (obss_scan_arg->activity_threshold < 0) + obss_scan_arg->activity_threshold = WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT; + else if (obss_scan_arg->activity_threshold < WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN || + obss_scan_arg->activity_threshold > WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX) { + printf("Activity Threshold not in range %d\n", obss_scan_arg->activity_threshold); + return -1; + } + return 0; +} + +/* Send a periodic keep-alive packet at the specificed interval. */ +static int +wl_keep_alive(void *wl, cmd_t *cmd, char **argv) +{ + const char *str; + wl_keep_alive_pkt_t keep_alive_pkt; + wl_keep_alive_pkt_t *keep_alive_pktp; + int buf_len; + int str_len; + int i; + int rc; + void *ptr = NULL; + + + if (*++argv == NULL) { + /* + ** Get current keep-alive status. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return rc; + + keep_alive_pktp = (wl_keep_alive_pkt_t *) ptr; + + printf("Period (msec) :%d\n" + "Length :%d\n" + "Packet :0x", + dtoh32(keep_alive_pktp->period_msec), + dtoh16(keep_alive_pktp->len_bytes)); + + for (i = 0; i < keep_alive_pktp->len_bytes; i++) + printf("%02x", keep_alive_pktp->data[i]); + + printf("\n"); + } + else { + /* + ** Set keep-alive attributes. + */ + + str = "keep_alive"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[ str_len ] = '\0'; + + keep_alive_pktp = (wl_keep_alive_pkt_t *) (buf + str_len + 1); + keep_alive_pkt.period_msec = htod32(strtoul(*argv, NULL, 0)); + buf_len = str_len + 1; + + + if (keep_alive_pkt.period_msec == 0) { + keep_alive_pkt.len_bytes = 0; + + buf_len += sizeof(wl_keep_alive_pkt_t); + } + else { + if (NULL != *++argv) { + keep_alive_pkt.len_bytes = + htod16(wl_pattern_atoh(*argv, (char *) keep_alive_pktp->data)); + buf_len += (WL_KEEP_ALIVE_FIXED_LEN + keep_alive_pkt.len_bytes); + } + else { + keep_alive_pkt.len_bytes = 0; + buf_len += WL_KEEP_ALIVE_FIXED_LEN; + } + } + + /* Keep-alive attributes are set in local variable (keep_alive_pkt), and + * then memcpy'ed into buffer (keep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)keep_alive_pktp, &keep_alive_pkt, WL_KEEP_ALIVE_FIXED_LEN); + + + rc = wlu_set(wl, + WLC_SET_VAR, + buf, + buf_len); + + } + + return (rc); +} + +/* mkeep-alive : Send a periodic keep-alive packet or null-data at the specificed interval. */ +/* wowl_keepalive : Send a periodic keep alive packet the specificed interval in wowl mode. */ +static int +wl_mkeep_alive(void *wl, cmd_t *cmd, char **argv) +{ + const char *str; + wl_mkeep_alive_pkt_t mkeep_alive_pkt; + wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + int buf_len; + int str_len; + int len_bytes; + int i; + int rc; + void *ptr = NULL; + + memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); + + str = *argv; /* mkeep_alive or wowl_keepalive */ + if (*++argv == NULL) { + return BCME_USAGE_ERROR; + } + else { + /* read the packet index */ + int mkeep_alive_id = htod32(strtoul(*argv, NULL, 0)); + + if (*++argv == NULL) { + /* + ** Get current keep-alive status. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, &mkeep_alive_id, + sizeof(int), &ptr)) < 0) + return rc; + + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) ptr; + + printf("Id :%d\n" + "Period (msec) :%d\n" + "Length :%d\n" + "Packet :0x", + mkeep_alive_pktp->keep_alive_id, + dtoh32(mkeep_alive_pktp->period_msec), + dtoh16(mkeep_alive_pktp->len_bytes)); + + for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) + printf("%02x", mkeep_alive_pktp->data[i]); + + printf("\n"); + return rc; + } + + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[ str_len ] = '\0'; + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); + mkeep_alive_pkt.period_msec = htod32(strtoul(*argv, NULL, 0)); + buf_len = str_len + 1; + mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; + + len_bytes = 0; + + buf_len += WL_MKEEP_ALIVE_FIXED_LEN; + if (mkeep_alive_pkt.period_msec != 0) { + if (NULL != *++argv) { + len_bytes = wl_pattern_atoh(*argv, (char *) mkeep_alive_pktp->data); + buf_len += len_bytes; + } + } + mkeep_alive_pkt.len_bytes = htod16(len_bytes); + + /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and + * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); + + rc = wlu_set(wl, + WLC_SET_VAR, + buf, + buf_len); + + } + + return (rc); +} + + +/* Enable/disable installed packet filter. */ +static int +wl_pkt_filter_enable(void *wl, cmd_t *cmd, char **argv) +{ + wl_pkt_filter_enable_t enable_parm; + int rc; + + if (*++argv == NULL) { + printf("No args provided\n"); + return BCME_USAGE_ERROR; + } + + /* Parse packet filter id. */ + enable_parm.id = htod32(strtoul(*argv, NULL, 0)); + + if (*++argv == NULL) { + printf("Enable/disable value not provided\n"); + return BCME_USAGE_ERROR; + } + + /* Parse enable/disable value. */ + enable_parm.enable = htod32(strtoul(*argv, NULL, 0)); + + + /* Enable/disable the specified filter. */ + rc = wlu_var_setbuf(wl, + cmd->name, + &enable_parm, + sizeof(wl_pkt_filter_enable_t)); + + return (rc); +} + + +/* Install a new packet filter. */ +static int +wl_pkt_filter_add(void *wl, cmd_t *cmd, char **argv) +{ + const char *str; + wl_pkt_filter_t pkt_filter; + wl_pkt_filter_t *pkt_filterp; + int buf_len; + int str_len; + int rc; + uint32 mask_size; + uint32 pattern_size; + + UNUSED_PARAMETER(cmd); + + str = "pkt_filter_add"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[ str_len ] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); + + /* Parse packet filter id. */ + if (*++argv == NULL) { + printf("No args provided\n"); + return BCME_USAGE_ERROR; + } + pkt_filter.id = htod32(strtoul(*argv, NULL, 0)); + + /* Parse filter polarity. */ + if (*++argv == NULL) { + printf("Polarity not provided\n"); + return BCME_USAGE_ERROR; + } + pkt_filter.negate_match = htod32(strtoul(*argv, NULL, 0)); + + /* Parse filter type. */ + if (*++argv == NULL) { + printf("Filter type not provided\n"); + return BCME_USAGE_ERROR; + } + pkt_filter.type = htod32(strtoul(*argv, NULL, 0)); + if ((pkt_filter.type != WL_PKT_FILTER_TYPE_PATTERN_MATCH) && + (pkt_filter.type != WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT)) { + printf("Invalid filter type %d\n", pkt_filter.type); + return BCME_USAGE_ERROR; + } + + /* Handle basic pattern filter */ + if (pkt_filter.type == WL_PKT_FILTER_TYPE_PATTERN_MATCH) { + wl_pkt_filter_pattern_t *pfilter = &pkt_filterp->u.pattern; + + /* Parse pattern filter offset. */ + if (*++argv == NULL) { + printf("Offset not provided\n"); + return BCME_USAGE_ERROR; + } + pkt_filter.u.pattern.offset = htod32(strtoul(*argv, NULL, 0)); + + /* Parse pattern filter mask. */ + if (*++argv == NULL) { + printf("Bitmask not provided\n"); + return BCME_USAGE_ERROR; + } + rc = wl_pattern_atoh(*argv, (char *)pfilter->mask_and_pattern); + if (rc <= 0) { + printf("Invalid mask provided: %s\n", *argv); + return BCME_USAGE_ERROR; + } + mask_size = htod32(rc); + + /* Parse pattern filter pattern. */ + if (*++argv == NULL) { + printf("Pattern not provided\n"); + return BCME_USAGE_ERROR; + } + rc = wl_pattern_atoh(*argv, (char *)&pfilter->mask_and_pattern[rc]); + if (rc <= 0) { + printf("Invalid pattern provided: %s\n", *argv); + return BCME_USAGE_ERROR; + } + pattern_size = htod32(rc); + + if (mask_size != pattern_size) { + printf("Mask and pattern not the same size\n"); + return BCME_USAGE_ERROR; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * rc); + + /* The fields that were put in a local for alignment purposes now + * get copied to the right place in the ioctl buffer. + */ + memcpy((char *)pkt_filterp, &pkt_filter, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + } + + /* Handle pattern filter with timeout event */ + if (pkt_filter.type == WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT) { + wl_pkt_filter_pattern_timeout_t *pfilter = &pkt_filterp->u.pattern_timeout; + + /* Parse pattern filter offset. */ + if (*++argv == NULL) { + printf("Offset not provided\n"); + return BCME_USAGE_ERROR; + } + pkt_filter.u.pattern.offset = htod32(strtoul(*argv, NULL, 0)); + + /* Parse pattern filter mask. */ + if (*++argv == NULL) { + printf("Bitmask not provided\n"); + return BCME_USAGE_ERROR; + } + rc = wl_pattern_atoh(*argv, (char *)pfilter->mask_and_pattern); + if (rc <= 0) { + printf("Invalid mask provided: %s\n", *argv); + return BCME_USAGE_ERROR; + } + mask_size = htod32(rc); + + /* Parse pattern filter pattern. */ + if (*++argv == NULL) { + printf("Pattern not provided\n"); + return BCME_USAGE_ERROR; + } + rc = wl_pattern_atoh(*argv, (char *)&pfilter->mask_and_pattern[rc]); + if (rc <= 0) { + printf("Rejecting: %s\n", *argv); + return BCME_USAGE_ERROR; + } + pattern_size = htod32(rc); + + if (mask_size != pattern_size) { + printf("Mask and pattern not the same size\n"); + return BCME_USAGE_ERROR; + } + + if (*++argv == NULL) { + printf("timeout not specified\n"); + return BCME_USAGE_ERROR; + } + pkt_filter.u.pattern_timeout.timeout = htod32(strtoul(*argv, NULL, 0)); + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN + 2 * rc); + + /* The fields that were put in a local for alignment purposes now + * get copied to the right place in the ioctl buffer. + */ + memcpy((char *)pkt_filterp, &pkt_filter, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN); + } + + rc = wlu_set(wl, WLC_SET_VAR, buf, buf_len); + + return (rc); +} + +static void +wl_pkt_filter_list_mask_pat(uint8 *bytes, uint size, char *indent) +{ + uint j; + + printf("%sMask :0x", indent); + + for (j = 0; j < size; j++) + printf("%02x", bytes[j]); + + printf("\n%sPattern :0x", indent); + + for (; j < 2 * size; j++) + printf("%02x", bytes[j]); + + printf("\n\n"); +} + +/* List installed packet filters. */ +static int +wl_pkt_filter_list(void *wl, cmd_t *cmd, char **argv) +{ + wl_pkt_filter_list_t *list; + wl_pkt_filter_t *filterp; + void *ptr = NULL; + unsigned int i; + int rc; + unsigned int filter_len; + uint32 enable; + + + if (*++argv == NULL) { + printf("No args provided\n"); + return BCME_USAGE_ERROR; + } + + /* Parse filter list to retrieve (enabled/disabled). */ + enable = htod32(strtoul(*argv, NULL, 0)); + /* + ** Get list of installed packet filters. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, &enable, sizeof(enable), &ptr)) < 0) + return rc; + + list = (wl_pkt_filter_list_t *) ptr; + + printf("Num filters: %d\n\n", list->num); + + filterp = list->filter; + for (i = 0; i < list->num; i++) + { + uint type = dtoh32(filterp->type); + + if (type == WL_PKT_FILTER_TYPE_PATTERN_MATCH) { + printf("Id :%d\n" + "Negate :%d\n" + "Type :%d\n" + "Offset :%d\n" + "Pattern len :%d\n", + dtoh32(filterp->id), + dtoh32(filterp->negate_match), + dtoh32(filterp->type), + dtoh32(filterp->u.pattern.offset), + dtoh32(filterp->u.pattern.size_bytes)); + + wl_pkt_filter_list_mask_pat(filterp->u.pattern.mask_and_pattern, + dtoh32(filterp->u.pattern.size_bytes), ""); + filter_len = WL_PKT_FILTER_PATTERN_FIXED_LEN + + 2 * dtoh32(filterp->u.pattern.size_bytes); + } else if (type == WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT) { + printf("Id :%d\n" + "Negate :%d\n" + "Type :%d\n" + "Offset :%d\n" + "Pattern len :%d\n" + "Timeout :%d seconds\n", + dtoh32(filterp->id), + dtoh32(filterp->negate_match), + dtoh32(filterp->type), + dtoh32(filterp->u.pattern_timeout.offset), + dtoh32(filterp->u.pattern_timeout.size_bytes), + dtoh32(filterp->u.pattern_timeout.timeout)); + + wl_pkt_filter_list_mask_pat(filterp->u.pattern_timeout.mask_and_pattern, + dtoh32(filterp->u.pattern_timeout.size_bytes), ""); + filter_len = WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN + + 2 * dtoh32(filterp->u.pattern_timeout.size_bytes); + } + + filter_len += WL_PKT_FILTER_FIXED_LEN; + filterp = (wl_pkt_filter_t *) ((uint8 *)filterp + filter_len); + filterp = ALIGN_ADDR(filterp, sizeof(uint32)); + + } + + return (rc); +} + + +/* Get packet filter debug statistics. */ +static int +wl_pkt_filter_stats(void *wl, cmd_t *cmd, char **argv) +{ + wl_pkt_filter_stats_t *stats; + uint32 id; + int rc; + void *ptr = NULL; + + if (*++argv == NULL) { + printf("No args provided\n"); + return BCME_USAGE_ERROR; + } + + /* Parse filter id to retrieve. */ + id = htod32(strtoul(*argv, NULL, 0)); + + + /* Get debug stats. */ + if ((rc = wlu_var_getbuf(wl, cmd->name, &id, sizeof(id), &ptr)) < 0) + return rc; + + stats = (wl_pkt_filter_stats_t *) ptr; + + printf("Packets matched for filter '%d': %d\n" + "Total packets discarded : %d\n" + "Total packet forwarded : %d\n", + id, + dtoh32(stats->num_pkts_matched), + dtoh32(stats->num_pkts_discarded), + dtoh32(stats->num_pkts_forwarded)); + + return (rc); +} + +#ifdef TRAFFIC_MGMT +/* Get/set traffic management configuration. */ +static int +wl_trf_mgmt_config(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + uint32 i; + trf_mgmt_config_t *ptrf_mgmt_config; + uint8 buf[sizeof(trf_mgmt_config_t)]; + int buf_len; + char *endptr = NULL; + int rc = -1; + void *ptr = NULL; + + if (!*++argv) { + /* + * Get current traffic management configuration. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return rc; + + ptrf_mgmt_config = (trf_mgmt_config_t *)ptr; + + printf("Enabled : %d\n", + dtoh32(ptrf_mgmt_config->trf_mgmt_enabled)); + printf("Host IP Address : %s\n", + wl_iptoa((void *)&ptrf_mgmt_config->host_ip_addr)); + printf("Host IP Subnet Mask : %s\n", + wl_iptoa((void *)&ptrf_mgmt_config->host_subnet_mask)); + printf("Downlink Bandwidth : %d\n", + dtoh32(ptrf_mgmt_config->downlink_bandwidth)); + printf("Uplink Bandwidth : %d\n", + dtoh32(ptrf_mgmt_config->uplink_bandwidth)); + printf("\n"); + + printf("Minimum Tx Bandwidth[BK] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[0])); + printf("Minimum Tx Bandwidth[BE] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[1])); + printf("Minimum Tx Bandwidth[VI] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[2])); + printf("\n"); + + printf("Minimum Rx Bandwidth[BK] : %d\n", + dtoh32(ptrf_mgmt_config->min_rx_bandwidth[0])); + printf("Minimum Rx Bandwidth[BE] : %d\n", + dtoh32(ptrf_mgmt_config->min_rx_bandwidth[1])); + printf("Minimum Rx Bandwidth[VI] : %d\n", + dtoh32(ptrf_mgmt_config->min_rx_bandwidth[2])); + printf("\n"); + + printf("Flags : 0x%04X\n", + dtoh32(ptrf_mgmt_config->flags)); + } + else { + /* arg count */ + while (argv[argc]) + argc++; + + /* required arguments */ + if ((argc != 1) && (argc != 5) && (argc != 6)) { + fprintf(stderr, "Too few/many arguments (require 1 or 5 or 6 , got %d)\n", argc); + return BCME_USAGE_ERROR; + } + + ptrf_mgmt_config = (trf_mgmt_config_t *)buf; + buf_len = sizeof(trf_mgmt_config_t); + memset((uint8 *)buf, 0, buf_len); + + ptrf_mgmt_config->trf_mgmt_enabled = htod32((int32)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') { + return BCME_USAGE_ERROR; + } + + if (argc > 1) { + if (ptrf_mgmt_config->trf_mgmt_enabled) { + if (!wl_atoip(*argv++, (void *)&ptrf_mgmt_config->host_ip_addr)) { + return BCME_USAGE_ERROR; + } + if (!wl_atoip(*argv++, (void *)&ptrf_mgmt_config->host_subnet_mask)) { + return BCME_USAGE_ERROR; + } + ptrf_mgmt_config->downlink_bandwidth = + htod32((int32)strtol(*argv++, &endptr, 0)); + ptrf_mgmt_config->uplink_bandwidth = + htod32((int32)strtol(*argv++, &endptr, 0)); + + /* + * Zero-fill min bandwidth based. This will cause the driver to use + * defult settings + */ + for (i = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) { + ptrf_mgmt_config->min_tx_bandwidth[i] = 0; + ptrf_mgmt_config->min_rx_bandwidth[i] = 0; + } + + if (argc == 6) { + ptrf_mgmt_config->flags = htod32((int32)strtol(*argv++, &endptr, 0)); + } + } else { + return BCME_BADARG; + } + } + + rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_config, buf_len); + } + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* Sets a traffic management filter. */ +static int +wl_trf_mgmt_filters_add(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + trf_mgmt_filter_list_t *ptrf_mgmt_filter_list; + trf_mgmt_filter_t *ptrf_mgmt_filter; + uint8 buf[sizeof(trf_mgmt_filter_list_t)]; + int buf_len; + char *param; + char *endptr = NULL; + int rc = -1; + + (void)param; + /* arg count */ + param = *++argv; + while (argv[argc]) + argc++; + + /* required arguments */ + if (argc != 4) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 4, argc); + return BCME_USAGE_ERROR; + } + + ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buf; + buf_len = sizeof(trf_mgmt_filter_list_t); + memset((uint8 *)buf, 0, buf_len); + + ptrf_mgmt_filter_list->num_filters = 1; + ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[0]; + + ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_filter_list, buf_len); + + return rc; +} +/* Sets a traffic management filter L2/L3/L4 */ +static int +wl_trf_mgmt_filters_addex(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + trf_mgmt_filter_list_t *ptrf_mgmt_filter_list; + trf_mgmt_filter_t *ptrf_mgmt_filter; + uint8 buf[sizeof(trf_mgmt_filter_list_t)]; + int buf_len; + char *param; + char *endptr = NULL; + int rc = -1; + + (void)param; + (void)cmd; + /* arg count */ + param = *++argv; + while (argv[argc]) + argc++; + + /* required arguments */ + if (argc < 3) { + fprintf(stderr, "Too few arguments (require > 3 got %d)\n", argc); + return BCME_USAGE_ERROR; + } + + ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buf; + buf_len = sizeof(trf_mgmt_filter_list_t); + memset((uint8 *)buf, 0, buf_len); + + ptrf_mgmt_filter_list->num_filters = 1; + ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[0]; + + ptrf_mgmt_filter->flags = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + if (ptrf_mgmt_filter->flags & TRF_FILTER_MAC_ADDR) { + + if (argc != 3) { + fprintf(stderr, "Too many arguments (require 3 got %d)\n", argc); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv++, &ptrf_mgmt_filter->dst_ether_addr)) + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } else { + /* required arguments */ + if (argc != 5) { + fprintf(stderr, "Too few/many arguments (require 5 got %d)\n", argc); + return BCME_USAGE_ERROR; + } + + ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->priority = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + + rc = wlu_var_setbuf(wl, "trf_mgmt_filters_add", ptrf_mgmt_filter_list, buf_len); + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* Removes a traffic management filter. */ +static int +wl_trf_mgmt_filters_remove(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + trf_mgmt_filter_list_t *ptrf_mgmt_filter_list; + trf_mgmt_filter_t *ptrf_mgmt_filter; + uint8 buf[sizeof(trf_mgmt_filter_list_t)]; + int buf_len; + char *endptr = NULL; + char *param; + int rc = -1; + + (void)param; + /* arg count */ + param = *++argv; + while (argv[argc]) + argc++; + + /* required arguments */ + if (argc != 3) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 3, argc); + return BCME_USAGE_ERROR; + } + + ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buf; + buf_len = sizeof(trf_mgmt_filter_list_t); + + memset((uint8 *)buf, 0, buf_len); + + ptrf_mgmt_filter_list->num_filters = 1; + ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[0]; + + ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_filter_list, buf_len); + + return rc; +} + +/* Removes a traffic management filter for L2/L3/L4 */ +static int +wl_trf_mgmt_filters_removeex(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + trf_mgmt_filter_list_t *ptrf_mgmt_filter_list; + trf_mgmt_filter_t *ptrf_mgmt_filter; + uint8 buf[sizeof(trf_mgmt_filter_list_t)]; + int buf_len; + char *endptr = NULL; + char *param; + int rc = -1; + + (void)param; + (void)cmd; + /* arg count */ + param = *++argv; + while (argv[argc]) + argc++; + + /* required arguments */ + if (argc < 2) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 2, argc); + return BCME_USAGE_ERROR; + } + + ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)buf; + buf_len = sizeof(trf_mgmt_filter_list_t); + + memset((uint8 *)buf, 0, buf_len); + + ptrf_mgmt_filter_list->num_filters = 1; + ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[0]; + + ptrf_mgmt_filter->flags = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') { + return BCME_USAGE_ERROR; + } + if (ptrf_mgmt_filter->flags & TRF_FILTER_MAC_ADDR) { + + if (argc != 2) { + fprintf(stderr, "Too many arguments (require 2 got %d)\n", argc); + return BCME_USAGE_ERROR; + } + + if (!wl_ether_atoe(*argv++, &ptrf_mgmt_filter->dst_ether_addr)) { + return BCME_USAGE_ERROR; + } + + } else { + if (argc < 4) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 4, argc); + return BCME_USAGE_ERROR; + } + ptrf_mgmt_filter->dst_port = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->src_port = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + ptrf_mgmt_filter->prot = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + + rc = wlu_var_setbuf(wl, "trf_mgmt_filters_remove", ptrf_mgmt_filter_list, buf_len); + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* lists the current traffic management filters. */ +static int +wl_trf_mgmt_filters_list(void *wl, cmd_t *cmd, char **argv) +{ + trf_mgmt_filter_list_t *ptrf_mgmt_filter_list; + trf_mgmt_filter_t *ptrf_mgmt_filter; + uint i; + int rc = -1; + void *ptr = NULL; + + UNUSED_PARAMETER(argv); + + /* + * Get current traffic management filters. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return rc; + + ptrf_mgmt_filter_list = (trf_mgmt_filter_list_t *)ptr; + + printf("Number of filters : %d\n", dtoh32(ptrf_mgmt_filter_list->num_filters)); + + for (i = 0; i < ptrf_mgmt_filter_list->num_filters; i++) { + ptrf_mgmt_filter = &ptrf_mgmt_filter_list->filter[i]; + + if (ptrf_mgmt_filter->flags & TRF_FILTER_MAC_ADDR) { + printf("\n"); + printf("Filter #%d\n", i); + printf("Flags : 0x%02x\n", dtoh32(ptrf_mgmt_filter->flags)); + printf("Dst EtherAddr : %s\n", + wl_ether_etoa(&ptrf_mgmt_filter->dst_ether_addr)); + printf("Priority : %d\n", dtoh32(ptrf_mgmt_filter->priority)); + } else { + printf("\n"); + printf("Filter #%d\n", i); + printf("Dst Port : %d\n", dtoh32(ptrf_mgmt_filter->dst_port)); + printf("Src Port : %d\n", dtoh32(ptrf_mgmt_filter->src_port)); + printf("Protocol : %d\n", dtoh32(ptrf_mgmt_filter->prot)); + printf("Flags : 0x%02x\n", dtoh32(ptrf_mgmt_filter->flags)); + printf("Priority : %d\n", dtoh32(ptrf_mgmt_filter->priority)); + } + } + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* Clears the traffic management filters. */ +static int +wl_trf_mgmt_filters_clear(void *wl, cmd_t *cmd, char **argv) +{ + int rc = -1; + + UNUSED_PARAMETER(argv); + + rc = wlu_var_setbuf(wl, cmd->name, NULL, 0); + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* + * Get/set traffic management bandwidth configuration. We support the ability to get/set just the + * bandwidth parameters in the global trf_mgmt_config_t structure. + */ +static int +wl_trf_mgmt_bandwidth(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + trf_mgmt_config_t *ptrf_mgmt_config; + uint8 buf[sizeof(trf_mgmt_config_t)]; + int buf_len; + char *endptr = NULL; + int i, total_bandwidth; + int rc = -1; + void *ptr = NULL; + + if (!*++argv) { + /* + * Get current traffic management bandwidth settings. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return rc; + + ptrf_mgmt_config = (trf_mgmt_config_t *)ptr; + + printf("Downlink Bandwidth : %d\n", + dtoh32(ptrf_mgmt_config->downlink_bandwidth)); + printf("Uplink Bandwidth : %d\n", + dtoh32(ptrf_mgmt_config->uplink_bandwidth)); + printf("\n"); + + printf("Minimum Tx Bandwidth[BK] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[0])); + printf("Minimum Tx Bandwidth[BE] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[1])); + printf("Minimum Tx Bandwidth[VI] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[2])); + printf("\n"); + + printf("Minimum Rx Bandwidth[BK] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[0])); + printf("Minimum Rx Bandwidth[BE] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[1])); + printf("Minimum Rx Bandwidth[VI] : %d\n", + dtoh32(ptrf_mgmt_config->min_tx_bandwidth[2])); + } + else { + /* arg count */ + while (argv[argc]) + argc++; + + /* required arguments */ + if (argc < 5) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 5, argc); + return BCME_USAGE_ERROR; + } + + if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return rc; + + ptrf_mgmt_config = (trf_mgmt_config_t *)buf; + buf_len = sizeof(trf_mgmt_config_t); + + memcpy(buf, ptr, buf_len); + + ptrf_mgmt_config->downlink_bandwidth = htod32((int32)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + ptrf_mgmt_config->uplink_bandwidth = htod32((int32)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + for (i = 0, total_bandwidth = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) { + ptrf_mgmt_config->min_tx_bandwidth[i] = + htod32((int32)strtol(*argv++, &endptr, 0)); + + if (*endptr != '\0') + return BCME_USAGE_ERROR; + total_bandwidth += ptrf_mgmt_config->min_tx_bandwidth[i]; + } + + if (total_bandwidth != 100) { + fprintf(stderr, + "Sum of gauranteed bandwidth levels must equal 100 (got %d)\n", + total_bandwidth); + return BCME_BADARG; + } + + if (argc > 5) { + for (i = 0, total_bandwidth = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) { + ptrf_mgmt_config->min_rx_bandwidth[i] = + htod32((int32)strtol(*argv++, &endptr, 0)); + + if (*endptr != '\0') + return BCME_USAGE_ERROR; + total_bandwidth += ptrf_mgmt_config->min_rx_bandwidth[i]; + } + + if (total_bandwidth != 100) { + fprintf(stderr, + "Sum of gauranteed rx bandwidth levels must equal 100 (got %d)\n", + total_bandwidth); + return BCME_BADARG; + } + } else { + for (i = 0, total_bandwidth = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) { + ptrf_mgmt_config->min_rx_bandwidth[i] = ptrf_mgmt_config->min_tx_bandwidth[i]; + } + } + + rc = wlu_var_setbuf(wl, cmd->name, ptrf_mgmt_config, buf_len); + } + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* + * Get/set traffic management operational flags. We use this to change flags that + * can't be set by GUI. This allows us to configure certain options that we may want to + * enable/disable in the shipping product. + */ +static int +wl_trf_mgmt_flags(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + uint32 flags; + char *endptr = NULL; + int rc = -1; + void *ptr = NULL; + + if (!*++argv) { + /* + * Get current traffic management bandwidth settings. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return rc; + + flags = *(uint32 *)ptr; + + printf("Flags : 0x%04X\n", flags); + } + else { + /* arg count */ + while (argv[argc]) + argc++; + + /* required arguments */ + if (argc != 1) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 1, argc); + return BCME_USAGE_ERROR; + } + + flags = htod32((int32)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') { + return BCME_USAGE_ERROR; + } + rc = wlu_var_setbuf(wl, cmd->name, &flags, sizeof(uint32)); + } + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* Print traffic management statistics. */ +static void +wl_trf_mgmt_print_stats(void *ptr, uint index) +{ + trf_mgmt_stats_array_t *ptrf_mgmt_statistics_array; + trf_mgmt_stats_t *ptrf_mgmt_statistics; + + ptrf_mgmt_statistics_array = (trf_mgmt_stats_array_t *)ptr; + + ptrf_mgmt_statistics = &ptrf_mgmt_statistics_array->tx_queue_stats[index]; + + printf("Statistics for Tx Queue[%d]\n", index); + printf("\n"); + printf("Num. packets processed : %d\n", + dtoh32(ptrf_mgmt_statistics->num_processed_packets)); + printf("Num. bytes processed : %d\n", + dtoh32(ptrf_mgmt_statistics->num_processed_bytes)); + printf("Num. packets discarded : %d\n", + dtoh32(ptrf_mgmt_statistics->num_discarded_packets)); + + ptrf_mgmt_statistics = &ptrf_mgmt_statistics_array->rx_queue_stats[index]; + + printf("\n"); + printf("Statistics for Rx Queue[%d]\n", index); + printf("\n"); + printf("Num. packets processed : %d\n", + dtoh32(ptrf_mgmt_statistics->num_processed_packets)); + printf("Num. bytes processed : %d\n", + dtoh32(ptrf_mgmt_statistics->num_processed_bytes)); + printf("Num. packets discarded : %d\n", + dtoh32(ptrf_mgmt_statistics->num_discarded_packets)); + + printf("\n"); +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* Get traffic management statistics. */ +static int +wl_trf_mgmt_stats(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + uint i; + int rc = -1; + char *endptr = NULL; + void *ptr = NULL; + + /* + * Get current traffic management statistics. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return rc; + + if (!*++argv) { + /* + * Print all of the current traffic management statistics. + */ + for (i = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) { + wl_trf_mgmt_print_stats(ptr, i); + } + } + else { + /* arg count */ + while (argv[argc]) + argc++; + + /* required arguments */ + if (argc != 1) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 1, argc); + return BCME_USAGE_ERROR; + } + + i = htod16((int16)strtol(*argv, &endptr, 0)); + if (i >= TRF_MGMT_MAX_PRIORITIES) { + fprintf(stderr, "Index must be < %d)\n", TRF_MGMT_MAX_PRIORITIES); + return BCME_BADARG; + } + + /* Print the current traffic management statistics for the specified queue index. */ + wl_trf_mgmt_print_stats(ptr, i); + } + + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* Clears the traffic management statistics. */ +static int +wl_trf_mgmt_stats_clear(void *wl, cmd_t *cmd, char **argv) +{ + int rc = -1; + + UNUSED_PARAMETER(argv); + + rc = wlu_var_setbuf(wl, cmd->name, NULL, 0); + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* Print traffic management shaping info. */ +static void +wl_trf_mgmt_print_global_shaping_info(void *ptr) +{ + trf_mgmt_shaping_info_array_t *ptrf_mgmt_shaping_info_array; + trf_mgmt_global_info_t *ptrf_mgmt_global_info; + + ptrf_mgmt_shaping_info_array = (trf_mgmt_shaping_info_array_t *)ptr; + + ptrf_mgmt_global_info = &ptrf_mgmt_shaping_info_array->tx_global_shaping_info; + + printf("Global shaping info. for Tx Queues\n"); + printf("\n"); + printf("Maximum bytes/second : %d\n", + ptrf_mgmt_global_info->maximum_bytes_per_second); + printf("Maximum bytes/sampling period : %d\n", + ptrf_mgmt_global_info->maximum_bytes_per_sampling_period); + printf("Total bytes consumed per second : %d\n", + ptrf_mgmt_global_info->total_bytes_consumed_per_second); + printf("Total bytes consumed per sampling period : %d\n", + ptrf_mgmt_global_info->total_bytes_consumed_per_sampling_period); + printf("Unused bytes for current sampling period : %d\n", + ptrf_mgmt_global_info->total_unused_bytes_per_sampling_period); + + printf("\n"); + + ptrf_mgmt_global_info = &ptrf_mgmt_shaping_info_array->rx_global_shaping_info; + + printf("Global shaping info. for Rx Queues\n"); + printf("\n"); + printf("Maximum bytes/second : %d\n", + ptrf_mgmt_global_info->maximum_bytes_per_second); + printf("Maximum bytes/sampling period : %d\n", + ptrf_mgmt_global_info->maximum_bytes_per_sampling_period); + printf("Total bytes consumed per second : %d\n", + ptrf_mgmt_global_info->total_bytes_consumed_per_second); + printf("Total bytes consumed per sampling period : %d\n", + ptrf_mgmt_global_info->total_bytes_consumed_per_sampling_period); + printf("Unused bytes for current sampling period : %d\n", + ptrf_mgmt_global_info->total_unused_bytes_per_sampling_period); + + printf("\n"); +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +static void +wl_trf_mgmt_print_shaping_info(void *ptr, uint index) +{ + trf_mgmt_shaping_info_array_t *ptrf_mgmt_shaping_info_array; + trf_mgmt_shaping_info_t *ptrf_mgmt_shaping_info; + + ptrf_mgmt_shaping_info_array = (trf_mgmt_shaping_info_array_t *)ptr; + + ptrf_mgmt_shaping_info = &ptrf_mgmt_shaping_info_array->tx_queue_shaping_info[index]; + + printf("Shaping info. for Tx Queue[%d]\n", index); + printf("\n"); + printf("Gauranteed bandwidth percentage : %d%%\n", + dtoh32(ptrf_mgmt_shaping_info->gauranteed_bandwidth_percentage)); + printf("Guaranteed bytes/second : %d\n", + dtoh32(ptrf_mgmt_shaping_info->guaranteed_bytes_per_second)); + printf("Guaranteed bytes/sampling period : %d\n", + dtoh32(ptrf_mgmt_shaping_info->guaranteed_bytes_per_sampling_period)); + printf("Num. bytes produced per second : %d\n", + dtoh32(ptrf_mgmt_shaping_info->num_bytes_produced_per_second)); + printf("Num. bytes consumed per second : %d\n", + dtoh32(ptrf_mgmt_shaping_info->num_bytes_consumed_per_second)); + printf("Num. packets pending : %d\n", + dtoh32(ptrf_mgmt_shaping_info->num_queued_packets)); + printf("Num. bytes pending : %d\n", + dtoh32(ptrf_mgmt_shaping_info->num_queued_bytes)); + + ptrf_mgmt_shaping_info = &ptrf_mgmt_shaping_info_array->rx_queue_shaping_info[index]; + + printf("\n"); + printf("Shaping info. for Rx Queue[%d]\n", index); + printf("\n"); + printf("Gauranteed bandwidth percentage : %d%%\n", + dtoh32(ptrf_mgmt_shaping_info->gauranteed_bandwidth_percentage)); + printf("Guaranteed bytes/second : %d\n", + dtoh32(ptrf_mgmt_shaping_info->guaranteed_bytes_per_second)); + printf("Guaranteed bytes/sampling period : %d\n", + dtoh32(ptrf_mgmt_shaping_info->guaranteed_bytes_per_sampling_period)); + printf("Num. bytes produced per second : %d\n", + dtoh32(ptrf_mgmt_shaping_info->num_bytes_produced_per_second)); + printf("Num. bytes consumed per second : %d\n", + dtoh32(ptrf_mgmt_shaping_info->num_bytes_consumed_per_second)); + printf("Num. packets pending : %d\n", + dtoh32(ptrf_mgmt_shaping_info->num_queued_packets)); + printf("Num. bytes pending : %d\n", + dtoh32(ptrf_mgmt_shaping_info->num_queued_bytes)); + + printf("\n"); +} +#endif /* TRAFFIC_MGMT */ + +#ifdef TRAFFIC_MGMT +/* Get traffic management shaping info. */ +static int +wl_trf_mgmt_shaping_info(void *wl, cmd_t *cmd, char **argv) +{ + uint argc = 0; + uint i; + int rc = -1; + char *endptr = NULL; + void *ptr = NULL; + + /* + * Get current traffic management shaping info. + */ + if ((rc = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return rc; + + if (!*++argv) { + /* + * Print all of the current traffic management shaping info. + */ + wl_trf_mgmt_print_global_shaping_info(ptr); + + for (i = 0; i < TRF_MGMT_MAX_PRIORITIES; i++) { + wl_trf_mgmt_print_shaping_info(ptr, i); + } + } + else { + /* arg count */ + while (argv[argc]) + argc++; + + /* required arguments */ + if (argc != 1) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", 1, argc); + return BCME_USAGE_ERROR; + } + + i = htod16((int16)strtol(*argv, &endptr, 0)); + if (i >= TRF_MGMT_MAX_PRIORITIES) { + fprintf(stderr, "Index must be < %d)\n", TRF_MGMT_MAX_PRIORITIES); + return BCME_BADARG; + } + + /* Print the current traffic management shaping info for the specified queue index. */ + wl_trf_mgmt_print_global_shaping_info(ptr); + wl_trf_mgmt_print_shaping_info(ptr, i); + } + + + return rc; +} +#endif /* TRAFFIC_MGMT */ + +static int +wl_obss_scan(void *wl, cmd_t *cmd, char **argv) +{ + int err = -1; + wl_obss_scan_arg_t obss_scan_arg; + char *endptr = NULL; + uint buflen; + uint argc = 0; + + if (!*++argv) { + void *ptr = NULL; + wl_obss_scan_arg_t *obss_scan_param; + + err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr); + if (err < 0) + return err; + + obss_scan_param = (wl_obss_scan_arg_t *)ptr; + printf("%d %d %d %d %d %d %d\n", + dtoh16(obss_scan_param->passive_dwell), + dtoh16(obss_scan_param->active_dwell), + dtoh16(obss_scan_param->bss_widthscan_interval), + dtoh16(obss_scan_param->passive_total), + dtoh16(obss_scan_param->active_total), + dtoh16(obss_scan_param->chanwidth_transition_delay), + dtoh16(obss_scan_param->activity_threshold)); + return 0; + } + + /* arg count */ + while (argv[argc]) + argc++; + + buflen = WL_OBSS_SCAN_PARAM_LEN; + memset((uint8 *)&obss_scan_arg, 0, buflen); + + /* required argments */ + if (argc < WL_MIN_NUM_OBSS_SCAN_ARG) { + fprintf(stderr, "Too few/many arguments (require %d, got %d)\n", + WL_MIN_NUM_OBSS_SCAN_ARG, argc); + return BCME_USAGE_ERROR; + } + + obss_scan_arg.passive_dwell = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + obss_scan_arg.active_dwell = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + obss_scan_arg.bss_widthscan_interval = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + obss_scan_arg.passive_total = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + obss_scan_arg.active_total = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + obss_scan_arg.chanwidth_transition_delay = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + obss_scan_arg.activity_threshold = htod16((int16)strtol(*argv++, &endptr, 0)); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + if (wl_obss_scan_params_range_chk(&obss_scan_arg)) + return BCME_RANGE; + + err = wlu_var_setbuf(wl, cmd->name, &obss_scan_arg, buflen); + + return err; +} + +#ifdef RWL_WIFI +/* Function added to support RWL_WIFI Transport +* Used to find the remote server with proper mac address given by +* the user,this cmd is specific to RWL_WIFIi protocol +*/ +static int wl_wifiserver(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + + if ((ret = wlu_iovar_set(wl, cmd->name, *argv, strlen(*argv))) < 0) { + printf("Error finding the remote server %s\n", argv[0]); + return ret; + } + return ret; +} +#endif +static int +wl_obss_coex_action(void *wl, cmd_t *cmd, char **argv) +{ + int err; + char var[256]; + wl_action_obss_coex_req_t *req = (wl_action_obss_coex_req_t *)var; + int val; + int num = 0; + uint8 options = 0; + + argv++; + memset(&var, 0, sizeof(wl_action_obss_coex_req_t)); + while (*argv) { + if (!strncmp(*argv, "-i", 2) && ((options & 0x1) != 0x1)) { + argv++; + if (!*argv) + return BCME_USAGE_ERROR; + val = atoi(*argv); + if ((val != 0) && (val != 1)) + return BCME_BADARG; + req->info |= val ? WL_COEX_40MHZ_INTOLERANT : 0; + options |= 0x1; + } + else if (!strncmp(*argv, "-w", 2) && ((options & 0x2) != 0x2)) { + argv++; + if (!*argv) + return BCME_USAGE_ERROR; + val = atoi(*argv); + if ((val != 0) && (val != 1)) + return BCME_BADARG; + req->info |= val ? WL_COEX_WIDTH20 : 0; + options |= 0x2; + } + else if (!strncmp(*argv, "-c", 2) && ((options & 0x4) != 0x4)) { + argv++; + while (*argv) { + if (isdigit((unsigned char)(**argv))) { + val = htod32(strtoul(*argv, NULL, 0)); + if ((val == 0) || (val > 14)) { + printf("Invalid channel %d\n", val); + return BCME_BADARG; + } + req->ch_list[num] = (uint8)val; + num++; + argv++; + if (num > 14) { + printf("Too many channels (max 14)\n"); + return BCME_BADARG; + } + } else + break; + } + if (!num) { + printf("With option '-c' specified, a channel list is required\n"); + return BCME_BADARG; + } + req->num = num; + options |= 0x4; + continue; + } + else + return BCME_USAGE_ERROR; + argv++; + } + if (!options) + return BCME_BADARG; + err = wlu_var_setbuf(wl, cmd->name, &var, (sizeof(wl_action_obss_coex_req_t) + + (req->num ? (req->num - 1) * sizeof(uint8) : 0))); + return err; +} + +static int +wl_srchmem(void *wl, cmd_t *cmd, char **argv) +{ + int ret = 0; + struct args { + int reg; + uint32 ssidlen; + uint8 ssid[DOT11_MAX_SSID_LEN]; + } x; + char *endptr; + uint argc; + char *iovar; + + UNUSED_PARAMETER(cmd); + + memset(&x, 0, sizeof(x)); + + /* save command name */ + iovar = argv[0]; + argv++; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* required arg: reg offset */ + if (argc < 1) + return BCME_USAGE_ERROR; + + x.reg = strtol(argv[0], &endptr, 0); + if (*endptr != '\0' || x.reg > 15) + return BCME_USAGE_ERROR; + + if (argc > 2) + return BCME_USAGE_ERROR; + + if (argc == 2) { + uint32 len; + + len = strlen(argv[1]); + if (len > sizeof(x.ssid)) { + printf("ssid too long\n"); + return BCME_BADARG; + } + memcpy(x.ssid, argv[1], len); + x.ssidlen = len; + } + + /* issue the get or set ioctl */ + if (argc == 1) { + x.reg = htod32(x.reg); + + ret = wlu_iovar_getbuf(wl, iovar, &x, sizeof(x), buf, WLC_IOCTL_SMLEN); + if (ret < 0) { + printf("get returned error 0x%x\n", ret); + return (ret); + } + + wl_hexdump((uchar *)buf, sizeof(x.ssidlen) + sizeof(x.ssid)); + } else { + x.reg = htod32(x.reg); + x.ssidlen = htod32(x.ssidlen); + + ret = wlu_iovar_set(wl, iovar, &x, sizeof(x)); + if (ret < 0) { + printf("set returned error 0x%x\n", ret); + return (ret); + } + } + + return (ret); +} + +cntry_name_t cntry_names[] = { + +{"AFGHANISTAN", "AF"}, +{"ALBANIA", "AL"}, +{"ALGERIA", "DZ"}, +{"AMERICAN SAMOA", "AS"}, +{"ANDORRA", "AD"}, +{"ANGOLA", "AO"}, +{"ANGUILLA", "AI"}, +{"ANTARCTICA", "AQ"}, +{"ANTIGUA AND BARBUDA", "AG"}, +{"ARGENTINA", "AR"}, +{"ARMENIA", "AM"}, +{"ARUBA", "AW"}, +{"ASCENSION ISLAND", "AC"}, +{"AUSTRALIA", "AU"}, +{"AUSTRIA", "AT"}, +{"AZERBAIJAN", "AZ"}, +{"BAHAMAS", "BS"}, +{"BAHRAIN", "BH"}, +{"BANGLADESH", "BD"}, +{"BARBADOS", "BB"}, +{"BELARUS", "BY"}, +{"BELGIUM", "BE"}, +{"BELIZE", "BZ"}, +{"BENIN", "BJ"}, +{"BERMUDA", "BM"}, +{"BHUTAN", "BT"}, +{"BOLIVIA", "BO"}, +{"BOSNIA AND HERZEGOVINA", "BA"}, +{"BOTSWANA", "BW"}, +{"BOUVET ISLAND", "BV"}, +{"BRAZIL", "BR"}, +{"BRITISH INDIAN OCEAN TERRITORY", "IO"}, +{"BRUNEI DARUSSALAM", "BN"}, +{"BULGARIA", "BG"}, +{"BURKINA FASO", "BF"}, +{"BURUNDI", "BI"}, +{"CAMBODIA", "KH"}, +{"CAMEROON", "CM"}, +{"CANADA", "CA"}, +{"CAPE VERDE", "CV"}, +{"CAYMAN ISLANDS", "KY"}, +{"CENTRAL AFRICAN REPUBLIC", "CF"}, +{"CHAD", "TD"}, +{"CHILE", "CL"}, +{"CHINA", "CN"}, +{"CHRISTMAS ISLAND", "CX"}, +{"CLIPPERTON ISLAND", "CP"}, +{"COCOS (KEELING) ISLANDS", "CC"}, +{"COLOMBIA", "CO"}, +{"COMOROS", "KM"}, +{"CONGO", "CG"}, +{"CONGO, THE DEMOCRATIC REPUBLIC OF THE", "CD"}, +{"COOK ISLANDS", "CK"}, +{"COSTA RICA", "CR"}, +{"COTE D'IVOIRE", "CI"}, +{"CROATIA", "HR"}, +{"CUBA", "CU"}, +{"CYPRUS", "CY"}, +{"CZECH REPUBLIC", "CZ"}, +{"DENMARK", "DK"}, +{"DJIBOUTI", "DJ"}, +{"DOMINICA", "DM"}, +{"DOMINICAN REPUBLIC", "DO"}, +{"ECUADOR", "EC"}, +{"EGYPT", "EG"}, +{"EL SALVADOR", "SV"}, +{"EQUATORIAL GUINEA", "GQ"}, +{"ERITREA", "ER"}, +{"ESTONIA", "EE"}, +{"ETHIOPIA", "ET"}, +{"FALKLAND ISLANDS (MALVINAS)", "FK"}, +{"FAROE ISLANDS", "FO"}, +{"FIJI", "FJ"}, +{"FINLAND", "FI"}, +{"FRANCE", "FR"}, +{"FRENCH GUIANA", "GF"}, +{"FRENCH POLYNESIA", "PF"}, +{"FRENCH SOUTHERN TERRITORIES", "TF"}, +{"GABON", "GA"}, +{"GAMBIA", "GM"}, +{"GEORGIA", "GE"}, +{"GERMANY", "DE"}, +{"GHANA", "GH"}, +{"GIBRALTAR", "GI"}, +{"GREECE", "GR"}, +{"GREENLAND", "GL"}, +{"GRENADA", "GD"}, +{"GUADELOUPE", "GP"}, +{"GUAM", "GU"}, +{"GUATEMALA", "GT"}, +{"GUERNSEY", "GG"}, +{"GUINEA", "GN"}, +{"GUINEA-BISSAU", "GW"}, +{"GUYANA", "GY"}, +{"HAITI", "HT"}, +{"HEARD ISLAND AND MCDONALD ISLANDS", "HM"}, +{"HOLY SEE (VATICAN CITY STATE)", "VA"}, +{"HONDURAS", "HN"}, +{"HONG KONG", "HK"}, +{"HUNGARY", "HU"}, +{"ICELAND", "IS"}, +{"INDIA", "IN"}, +{"INDONESIA", "ID"}, +{"IRAN, ISLAMIC REPUBLIC OF", "IR"}, +{"IRAQ", "IQ"}, +{"IRELAND", "IE"}, +{"ISRAEL", "IL"}, +{"ITALY", "IT"}, +{"JAMAICA", "JM"}, +{"JAPAN", "JP"}, +{"JERSEY", "JE"}, +{"JORDAN", "JO"}, +{"KAZAKHSTAN", "KZ"}, +{"KENYA", "KE"}, +{"KIRIBATI", "KI"}, +{"KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF", "KP"}, +{"KOREA, REPUBLIC OF", "KR"}, +{"KUWAIT", "KW"}, +{"KYRGYZSTAN", "KG"}, +{"LAO PEOPLE'S DEMOCRATIC REPUBLIC", "LA"}, +{"LATVIA", "LV"}, +{"LEBANON", "LB"}, +{"LESOTHO", "LS"}, +{"LIBERIA", "LR"}, +{"LIBYAN ARAB JAMAHIRIYA", "LY"}, +{"LIECHTENSTEIN", "LI"}, +{"LITHUANIA", "LT"}, +{"LUXEMBOURG", "LU"}, +{"MACAO", "MO"}, +{"MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF", "MK"}, +{"MADAGASCAR", "MG"}, +{"MALAWI", "MW"}, +{"MALAYSIA", "MY"}, +{"MALDIVES", "MV"}, +{"MALI", "ML"}, +{"MALTA", "MT"}, +{"MAN, ISLE OF", "IM"}, +{"MARSHALL ISLANDS", "MH"}, +{"MARTINIQUE", "MQ"}, +{"MAURITANIA", "MR"}, +{"MAURITIUS", "MU"}, +{"MAYOTTE", "YT"}, +{"MEXICO", "MX"}, +{"MICRONESIA, FEDERATED STATES OF", "FM"}, +{"MOLDOVA, REPUBLIC OF", "MD"}, +{"MONACO", "MC"}, +{"MONGOLIA", "MN"}, +{"MONTENEGRO", "ME"}, +{"MONTSERRAT", "MS"}, +{"MOROCCO", "MA"}, +{"MOZAMBIQUE", "MZ"}, +{"MYANMAR", "MM"}, +{"NAMIBIA", "NA"}, +{"NAURU", "NR"}, +{"NEPAL", "NP"}, +{"NETHERLANDS", "NL"}, +{"NETHERLANDS ANTILLES", "AN"}, +{"NEW CALEDONIA", "NC"}, +{"NEW ZEALAND", "NZ"}, +{"NICARAGUA", "NI"}, +{"NIGER", "NE"}, +{"NIGERIA", "NG"}, +{"NIUE", "NU"}, +{"NORFOLK ISLAND", "NF"}, +{"NORTHERN MARIANA ISLANDS", "MP"}, +{"NORWAY", "NO"}, +{"OMAN", "OM"}, +{"PAKISTAN", "PK"}, +{"PALAU", "PW"}, +{"PALESTINIAN TERRITORY, OCCUPIED", "PS"}, +{"PANAMA", "PA"}, +{"PAPUA NEW GUINEA", "PG"}, +{"PARAGUAY", "PY"}, +{"PERU", "PE"}, +{"PHILIPPINES", "PH"}, +{"PITCAIRN", "PN"}, +{"POLAND", "PL"}, +{"PORTUGAL", "PT"}, +{"PUERTO RICO", "PR"}, +{"QATAR", "QA"}, +{"Q1", "Q1"}, +{"REUNION", "RE"}, +{"ROMANIA", "RO"}, +{"RUSSIAN FEDERATION", "RU"}, +{"RWANDA", "RW"}, +{"SAINT HELENA", "SH"}, +{"SAINT KITTS AND NEVIS", "KN"}, +{"SAINT LUCIA", "LC"}, +{"SAINT PIERRE AND MIQUELON", "PM"}, +{"SAINT VINCENT AND THE GRENADINES", "VC"}, +{"SAMOA", "WS"}, +{"SAN MARINO", "SM"}, +{"SAO TOME AND PRINCIPE", "ST"}, +{"SAUDI ARABIA", "SA"}, +{"SENEGAL", "SN"}, +{"SERBIA", "RS"}, +{"SEYCHELLES", "SC"}, +{"SIERRA LEONE", "SL"}, +{"SINGAPORE", "SG"}, +{"SLOVAKIA", "SK"}, +{"SLOVENIA", "SI"}, +{"SOLOMON ISLANDS", "SB"}, +{"SOMALIA", "SO"}, +{"SOUTH AFRICA", "ZA"}, +{"SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS", "GS"}, +{"SPAIN", "ES"}, +{"SRI LANKA", "LK"}, +{"SUDAN", "SD"}, +{"SURINAME", "SR"}, +{"SVALBARD AND JAN MAYEN", "SJ"}, +{"SWAZILAND", "SZ"}, +{"SWEDEN", "SE"}, +{"SWITZERLAND", "CH"}, +{"SYRIAN ARAB REPUBLIC", "SY"}, +{"TAIWAN, PROVINCE OF CHINA", "TW"}, +{"TAJIKISTAN", "TJ"}, +{"TANZANIA, UNITED REPUBLIC OF", "TZ"}, +{"THAILAND", "TH"}, +{"TIMOR-LESTE (EAST TIMOR)", "TL"}, +{"TOGO", "TG"}, +{"TOKELAU", "TK"}, +{"TONGA", "TO"}, +{"TRINIDAD AND TOBAGO", "TT"}, +{"TRISTAN DA CUNHA", "TA"}, +{"TUNISIA", "TN"}, +{"TURKEY", "TR"}, +{"TURKMENISTAN", "TM"}, +{"TURKS AND CAICOS ISLANDS", "TC"}, +{"TUVALU", "TV"}, +{"UGANDA", "UG"}, +{"UKRAINE", "UA"}, +{"UNITED ARAB EMIRATES", "AE"}, +{"UNITED KINGDOM", "GB"}, +{"UNITED STATES", "US"}, +{"UNITED STATES MINOR OUTLYING ISLANDS", "UM"}, +{"URUGUAY", "UY"}, +{"UZBEKISTAN", "UZ"}, +{"VANUATU", "VU"}, +{"VENEZUELA", "VE"}, +{"VIET NAM", "VN"}, +{"VIRGIN ISLANDS, BRITISH", "VG"}, +{"VIRGIN ISLANDS, U.S.", "VI"}, +{"WALLIS AND FUTUNA", "WF"}, +{"WESTERN SAHARA", "EH"}, +{"YEMEN", "YE"}, +{"YUGOSLAVIA", "YU"}, +{"ZAMBIA", "ZM"}, +{"ZIMBABWE", "ZW"}, +{"RADAR CHANNELS", "RDR"}, +{"ALL CHANNELS", "ALL"}, +{NULL, NULL} +}; + +static void +wl_print_mcsset(char *mcsset) +{ + int i; + + printf("MCS SET : [ "); + for (i = 0; i < (MCSSET_LEN * 8); i++) + if (isset(mcsset, i)) + printf("%d ", i); + printf("]\n"); +} + +static void +wl_print_vhtmcsset(uint16 *mcsset) +{ + int i, j; + + for (i = 0; i < VHT_CAP_MCS_MAP_NSS_MAX; i++) { + if (mcsset[i]) { + if (i == 0) + printf("VHT SET : "); + else + printf(" : "); + for (j = 0; j <= 9; j++) + if (isbitset(mcsset[i], j)) + printf("%dx%d ", j, i + 1); + printf("\n"); + } else { + break; + } + } +} + +static int +wl_txmcsset(void *wl, cmd_t *cmd, char **argv) +{ + int err; + + if ((err = wl_var_get(wl, cmd, argv)) < 0) + return err; + wl_print_mcsset(buf); + + return err; +} + +static int +wl_rxmcsset(void *wl, cmd_t *cmd, char **argv) +{ + int err; + + if ((err = wl_var_get(wl, cmd, argv)) < 0) + return err; + + wl_print_mcsset(buf); + + return err; +} + +static int +wl_mimo_stf(void *wl, cmd_t *cmd, char **argv) +{ + char var[256]; + int32 int_val; + bool get = TRUE; + uint32 len = 0; + void *ptr = NULL; + char *endptr; + int i = 0, j = 0; + int ret = 0; + + while (argv[i]) + i++; + + if (i > 4) + return BCME_USAGE_ERROR; + + /* toss the command name */ + argv++; + j = 1; + + if (i == 1) { + int_val = -1; + memcpy(&var[len], (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + } + else { + if (isdigit((unsigned char)(**argv))) { + get = FALSE; + int_val = htod32(strtoul(*argv, &endptr, 0)); + if ((int_val != 0) && (int_val != 1)) { + fprintf(stderr, "wl mimo_ss_stf: bad stf mode.\n"); + return BCME_BADARG; + } + memcpy(var, (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + argv++; + j++; + } + + if (j == i) { + int_val = -1; + memcpy(&var[len], (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + } + else if (!strncmp(*argv, "-b", 2)) { + argv++; + j++; + if (j == i) + return BCME_BADARG; + + if (!strcmp(*argv, "a")) + int_val = 1; + else if (!strcmp(*argv, "b")) + int_val = 0; + else { + fprintf(stderr, + "wl mimo_ss_stf: wrong -b option, \"-b a\" or \"-b b\"\n"); + return BCME_USAGE_ERROR; + } + j++; + if (j < i) + return BCME_BADARG; + memcpy(&var[len], (char *)&int_val, sizeof(int_val)); + len += sizeof(int_val); + } + } + + if (get) { + if ((ret = wlu_var_getbuf(wl, cmd->name, var, sizeof(var), &ptr)) < 0) + return ret; + + printf("0x%x\n", dtoh32(*(int *)ptr)); + } + else + ret = wlu_var_setbuf(wl, cmd->name, &var, sizeof(var)); + return ret; +} + +#ifdef WLEXTLOG +static int +wl_extlog(void *wl, cmd_t *cmd, char **argv) +{ + int argc; + char *endptr; + int err; + int from_last; + int i, j; + char *log_p = NULL; + wlc_extlog_req_t r_args; + wlc_extlog_results_t *results; + void *ptr = NULL; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc > 3) + return BCME_USAGE_ERROR; + + if (argc == 1) + from_last = 0; + else { + from_last = htod32(strtoul(argv[1], &endptr, 0)); + if ((from_last != 0) && (from_last != 1)) + return BCME_BADARG; + } + + r_args.from_last = from_last; + if (argc == 3) + r_args.num = htod32(strtoul(argv[2], &endptr, 0)); + else + r_args.num = 32; + + if ((err = wlu_var_getbuf(wl, cmd->name, &r_args, sizeof(wlc_extlog_req_t), &ptr)) < 0) + return err; + + results = (wlc_extlog_results_t *)buf; + + printf("get external log records: %d\n", results->num); + if (!results->num) + return 0; + + if (results->version != EXTLOG_CUR_VER) { + printf("version mismatch: version = 0x%x, expected 0x%0x\n", + results->version, EXTLOG_CUR_VER); + return 0; + } + + log_p = (char *)&results->logs[0]; + + printf("Seq:\tTime(ms) Log\n"); + for (i = 0; i < (int)results->num; i++) { + printf("%d:\t%d\t ", ((log_record_t*)log_p)->seq_num, + ((log_record_t*)log_p)->time); + for (j = 0; j < FMTSTR_MAX_ID; j++) + if (((log_record_t*)log_p)->id == extlog_fmt_str[j].id) + break; + if (j == FMTSTR_MAX_ID) { + printf("fmt string not found for id %d\n", ((log_record_t*)log_p)->id); + log_p += results->record_len; + continue; + } + + switch (extlog_fmt_str[j].arg_type) { + case LOG_ARGTYPE_NULL: + printf("%s", extlog_fmt_str[j].fmt_str); + break; + + case LOG_ARGTYPE_STR: + printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->str); + break; + + case LOG_ARGTYPE_INT: + printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->arg); + break; + + case LOG_ARGTYPE_INT_STR: + printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->arg, + ((log_record_t*)log_p)->str); + break; + + case LOG_ARGTYPE_STR_INT: + printf(extlog_fmt_str[j].fmt_str, ((log_record_t*)log_p)->str, + ((log_record_t*)log_p)->arg); + break; + } + log_p += results->record_len; + } + + return 0; + +} + +static int +wl_extlog_cfg(void *wl, cmd_t *cmd, char **argv) +{ + int argc; + int err = 0; + char *endptr; + wlc_extlog_cfg_t *r_cfg; + wlc_extlog_cfg_t w_cfg; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc == 1) { + err = wl_var_get(wl, cmd, argv); + if (err < 0) + return err; + r_cfg = (wlc_extlog_cfg_t *)buf; + printf("max_number=%d, module=%x, level=%d, flag=%d, version=0x%04x\n", + r_cfg->max_number, r_cfg->module, r_cfg->level, + r_cfg->flag, r_cfg->version); + } + else if (argc == 4) { + w_cfg.module = htod16((uint16)(strtoul(argv[1], &endptr, 0))); + w_cfg.level = (uint8)strtoul(argv[2], &endptr, 0); + w_cfg.flag = (uint8)strtoul(argv[3], &endptr, 0); + err = wlu_var_setbuf(wl, cmd->name, &w_cfg, sizeof(wlc_extlog_cfg_t)); + } + else { + fprintf(stderr, "illegal command!\n"); + return BCME_USAGE_ERROR; + } + + return err; +} +#endif /* WLEXTLOG */ + +static int +wl_assertlog(void *wl, cmd_t *cmd, char **argv) +{ + int argc; + int err; + int i; + char *log_p = NULL; + assertlog_results_t *results; + void *ptr = NULL; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc > 1) + return BCME_USAGE_ERROR; + + if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return err; + + results = (assertlog_results_t *)buf; + + printf("get external assert logs: %d\n", results->num); + if (!results->num) + return 0; + + if (results->version != ASSERTLOG_CUR_VER) { + printf("Version mismatch: version = 0x%x, expected 0x%x\n", + results->version, ASSERTLOG_CUR_VER); + return 0; + } + + log_p = (char *)&results->logs[0]; + + printf("id: \ttime(ms) \tstring\n"); + for (i = 0; i < (int)results->num; i++) { + printf("%d: \t%d \t%s", i, ((assert_record_t *)log_p)->time, + ((assert_record_t *)log_p)->str); + log_p += results->record_len; + } + + return 0; +} + +extern cca_congest_channel_req_t * +cca_per_chan_summary(cca_congest_channel_req_t *input, + cca_congest_channel_req_t *avg, bool percent); + +extern int +cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer); + +static const char * +cca_level(int score, int med, int hi) +{ + if (score < med) + return ("Low"); + if (score >= med && score < hi) + return ("Medium"); + if (score >= hi) + return ("High"); + return NULL; +} + +static const char *cca_errors[] = { + "No error", + "Preferred band", + "Dwell Duration too low", + "Channel prefs", + "Interference too high", + "Only 1 channel inoput" +}; + +static int +wl_cca_get_stats(void *wl, cmd_t *cmd, char **argv) +{ + cca_congest_channel_req_t *results; + cca_congest_channel_req_t req; + cca_congest_t *chptr; + cca_congest_channel_req_t *avg[MAX_CCA_CHANNELS]; /* Max num of channels */ + void *ptr = NULL; + char *param, *val_p; + int base, limit, i, channel, err = 0; + int ibss_per, obss_per, inter_per, val; + const char *ibss_lvl = NULL; + const char *obss_lvl = NULL; + const char *inter_lvl = NULL; + int tmp_channel; + chanspec_t new_chanspec, cur_chanspec; + bool do_average = TRUE; + bool do_individ = FALSE; + bool do_analyze = TRUE; + bool curband = FALSE; + int avg_chan_idx = 0; + uint32 flags; + + + req.num_secs = 10; + tmp_channel = 0xff; + + argv++; + + /* Parse args */ + while ((param = *argv++) != NULL) { + if (stricmp(param, "-n") == 0) { + do_analyze = FALSE; + continue; + } + if (stricmp(param, "-i") == 0) { + do_individ = TRUE; + continue; + } + if (stricmp(param, "-curband") == 0) { + curband = TRUE; + continue; + } + + if ((val_p = *argv++) == NULL) { + printf("Need value following %s\n", param); + return BCME_USAGE_ERROR; + } + if (stricmp(param, "-c") == 0) { + tmp_channel = (int)strtoul(val_p, NULL, 0); + } + + if (stricmp(param, "-cs") == 0) { + if ((new_chanspec = wf_chspec_aton(val_p))) + tmp_channel = wf_chspec_ctlchan(new_chanspec); + } + + if (stricmp(param, "-s") == 0) { + req.num_secs = (int)strtoul(val_p, NULL, 0); + if (req.num_secs == 0 || req.num_secs > MAX_CCA_SECS) { + printf("%d: Num of seconds must be <= %d\n", + req.num_secs, MAX_CCA_SECS); + return BCME_USAGE_ERROR; + } + } + } + if (!do_average && !do_individ) { + printf("Must pick at least one of averages or individual secs\n"); + return BCME_USAGE_ERROR; + } + + if (tmp_channel == 0) { + /* do all channels */ + base = 1; limit = 255; + } else { + /* Use current channel as default if none specified */ + if (tmp_channel == 0xff) { + if ((err = wlu_iovar_getint(wl, "chanspec", (int*)&val)) < 0) { + printf("CCA: Can't get currrent chanspec\n"); + return err; + } + cur_chanspec = wl_chspec32_from_driver(val); + tmp_channel = wf_chspec_ctlchan(cur_chanspec); + printf("Using channel %d\n", tmp_channel); + } + base = limit = tmp_channel; + } + + + for (channel = base; channel <= limit; channel++) { + + /* Get stats for each channel */ + req.chanspec = CH20MHZ_CHSPEC(channel); + req.chanspec = wl_chspec_to_driver(req.chanspec); + if ((err = wlu_var_getbuf(wl, cmd->name, &req, sizeof(req), &ptr)) < 0) + return err; + + results = (cca_congest_channel_req_t *)ptr; + results->chanspec = wl_chspec_from_driver(results->chanspec); + if (results->chanspec == 0 || results->num_secs == 0) + continue; + + if (results->num_secs > MAX_CCA_SECS) { + printf("Bogus num of seconds returned %d\n", results->num_secs); + return -1; + } + + /* Summarize and save summary for this channel */ + if (do_average) { + avg[avg_chan_idx] = (cca_congest_channel_req_t *) + malloc(sizeof(cca_congest_channel_req_t)); + if (avg[avg_chan_idx] == NULL) { + printf("unable to allocate memory\n"); + return BCME_NOMEM; + } + cca_per_chan_summary(results, avg[avg_chan_idx], 1); + if (avg[avg_chan_idx]->num_secs) + avg_chan_idx++; + } + + /* printf stats for each second of each channel */ + if (do_individ) { + if (channel == base) + printf("chan dur ibss obss" + " interf time\n"); + for (i = 0; i < results->num_secs; i++) { + chptr = &results->secs[i]; + if (chptr->duration) { + /* Percentages */ + ibss_per = chptr->congest_ibss * 100 /chptr->duration; + obss_per = chptr->congest_obss * 100 /chptr->duration; + inter_per = chptr->interference * 100 /chptr->duration; + /* Levels */ + ibss_lvl = cca_level(ibss_per, IBSS_MED, IBSS_HI); + obss_lvl = cca_level(obss_per, OBSS_MED, OBSS_HI); + inter_lvl = cca_level(inter_per, INTERFER_MED, INTERFER_HI); + + printf("%-3u %4d %4u %2d%% %-6s %4u %2d%% %-6s %4u %2d%% %-6s %d\n", + CHSPEC_CHANNEL(results->chanspec), + chptr->duration, + chptr->congest_ibss, ibss_per, ibss_lvl, + chptr->congest_obss, obss_per, obss_lvl, + chptr->interference, inter_per, inter_lvl, + chptr->timestamp); + } + } + } + } + + /* Print summary stats of each channel */ + if (do_average) { + int j; + printf("Summaries:\n"); + printf("chan dur ibss obss interf num seconds\n"); + for (j = 0; j < avg_chan_idx; j++) { + /* Percentages */ + ibss_per = avg[j]->secs[0].congest_ibss; + obss_per = avg[j]->secs[0].congest_obss; + inter_per = avg[j]->secs[0].interference; + /* Levels */ + ibss_lvl = cca_level(ibss_per, IBSS_MED, IBSS_HI); + obss_lvl = cca_level(obss_per, OBSS_MED, OBSS_HI); + inter_lvl = cca_level(inter_per, INTERFER_MED, INTERFER_HI); + + if (avg[j]->num_secs) { + printf("%-3u %4d %4s %2d%% %-6s %4s %2d%% %-6s %4s %2d%% %-6s %d\n", + CHSPEC_CHANNEL(avg[j]->chanspec), + avg[j]->secs[0].duration, + "", avg[j]->secs[0].congest_ibss, ibss_lvl, + "", avg[j]->secs[0].congest_obss, obss_lvl, + "", avg[j]->secs[0].interference, inter_lvl, + avg[j]->num_secs); + } + } + } + + if (!do_analyze) + return err; + + if ((err = wlu_iovar_getint(wl, "chanspec", (int *)&val)) < 0) { + printf("CCA: Can't get currrent chanspec\n"); + return err; + } + cur_chanspec = wl_chspec32_from_driver(val); + flags = 0; + if (curband) { + if (CHSPEC_IS5G(cur_chanspec)) + flags |= CCA_FLAG_5G_ONLY; + if (CHSPEC_IS2G(cur_chanspec)) + flags |= CCA_FLAG_2G_ONLY; + } + + if ((err = cca_analyze(avg, avg_chan_idx, flags, &new_chanspec)) != 0) { + printf("Cannot find a good channel due to: %s\n", cca_errors[err]); + return BCME_ERROR; + } + printf("Recommended channel: %d\n", wf_chspec_ctlchan(new_chanspec)); + + return 0; +} + +static int +wl_itfr_get_stats(void *wl, cmd_t *cmd, char **argv) +{ + int err; + interference_source_rep_t *iftr_stats = NULL; + const char *iftr_source[] = {"none", "wireless phone", "wireless video camera", + "microwave oven", "wireless baby monitor", "bluetooth device", + "wireless video camera or baby monitor", "bluetooth or baby monitor", + "video camera or phone", "unidentified"}; /* sync with interference_source_t */ + + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, (void*)&iftr_stats)) < 0) + return err; + + if (iftr_stats->flags & ITFR_NOISY_ENVIRONMENT) + printf("Feature is stopped due to noisy environment\n"); + else + printf("Interference %s detected. last interference at timestamp %d: " + "source is %s on %s channel\n", + (iftr_stats->flags & ITFR_INTERFERENCED) ? "is" : "is not", + iftr_stats->timestamp, iftr_source[iftr_stats->source], + (iftr_stats->flags & ITFR_HOME_CHANNEL) ? "home" : "non-home"); + + return err; +} + +static int +wl_chanim_acs_record(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr = NULL; + int err = 0, i; + wl_acs_record_t *result; + + /* need to add to this str if new acs trigger type is added */ + const char *trig_str[] = {"None", "IOCTL", "CHANIM", "TIMER", "BTA"}; + + UNUSED_PARAMETER(argv); + + if ((err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return err; + + result = (wl_acs_record_t *) ptr; + + if (!result->count) { + printf("There is no ACS recorded\n"); + return err; + } + + printf("current timestamp: %u (ms)\n", result->timestamp); + + printf("Timestamp(ms) ACS Trigger Selected Channel Glitch Count CCA Count\n"); + for (i = 0; i < result->count; i++) { + uint8 idx = CHANIM_ACS_RECORD - result->count + i; + chanim_acs_record_t * record = &result->acs_record[idx]; + + record->selected_chspc = wl_chspec_from_driver(record->selected_chspc); + + printf("%10u \t%s \t%10d \t%12d \t%8d\n", record->timestamp, + trig_str[record->trigger], wf_chspec_ctlchan(record->selected_chspc), + record->glitch_cnt, record->ccastats); + } + return err; +} + +static int +wl_chanim_stats(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_chanim_stats_t *list; + wl_chanim_stats_t param; + chanim_stats_t *stats; + void *ptr; + int j; + + UNUSED_PARAMETER(argv); + + param.buflen = htod32(sizeof(wl_chanim_stats_t)); + param.count = htod32(WL_CHANIM_COUNT_ONE); + + if ((err = wlu_var_getbuf(wl, cmd->name, ¶m, sizeof(wl_chanim_stats_t), &ptr)) < 0) { + printf("failed to get chanim results"); + return err; + } + + list = (wl_chanim_stats_t*)ptr; + + list->buflen = dtoh32(list->buflen); + list->version = dtoh32(list->version); + list->count = dtoh32(list->count); + + printf("version: %d \n", list->version); + + if (list->buflen == 0) { + list->version = 0; + list->count = 0; + } else if (list->version != WL_CHANIM_STATS_VERSION) { + printf("Sorry, your driver has wl_chanim_stats version %d " + "but this program supports only version %d.\n", + list->version, WL_CHANIM_STATS_VERSION); + list->buflen = 0; + list->count = 0; + } + + stats = list->stats; + stats->glitchcnt = htod32(stats->glitchcnt); + stats->badplcp = htod32(stats->badplcp); + stats->chanspec = htod16(stats->chanspec); + stats->timestamp = htod32(stats->timestamp); + + printf("chanspec tx inbss obss nocat nopkt doze txop " + "goodtx badtx glitch badplcp knoise idle timestamp\n"); + printf("0x%4x\t", stats->chanspec); + for (j = 0; j < CCASTATS_MAX; j++) + printf("%d\t", stats->ccastats[j]); + printf("%d\t%d\t%d\t%d\t%d", dtoh32(stats->glitchcnt), dtoh32(stats->badplcp), + stats->bgnoise, stats->chan_idle, dtoh32(stats->timestamp)); + printf("\n"); + + return (err); +} + +static int +wl_txdelay_params(void *wl, cmd_t *cmd, char **argv) +{ + int err; + txdelay_params_t param; + int argc; + + argv++; + + if (*argv == NULL) { + /* get current txdelay params */ + if ((err = wlu_iovar_get(wl, cmd->name, (void *) ¶m, + (sizeof(txdelay_params_t)))) < 0) + return (err); + + printf("Txdelay params: ratio[%d] cnt[%d] period[%d] tune[%d]\n", + param.ratio, param.cnt, param.period, param.tune); + } + else { + char *endptr; + /* Validate num of entries */ + for (argc = 0; argv[argc]; argc++); + if (argc != 4) + return BCME_USAGE_ERROR; + + argc = 0; + param.ratio = strtol(argv[argc], &endptr, 0); + argc++; + param.cnt = strtol(argv[argc], &endptr, 0); + argc++; + param.period = strtol(argv[argc], &endptr, 0); + argc++; + param.tune = strtol(argv[argc], &endptr, 0); + + /* Set txdelay params */ + err = wlu_iovar_set(wl, cmd->name, (void *) ¶m, + (sizeof(txdelay_params_t))); + } + return (err); +} + +static int +wl_intfer_params(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_intfer_params_t param; + int argc; + char *endptr = NULL; + + argv++; + + if (*argv == NULL) { + /* get current txdelay params */ + if ((err = wlu_iovar_get(wl, cmd->name, (void *) ¶m, + (sizeof(wl_intfer_params_t)))) < 0) + goto error; + + if (param.version != INTFER_VERSION) { + printf("Interference params structure version (%d) is not the " + "version (%d) supported by this tool", + INTFER_VERSION, param.version); + err = BCME_USAGE_ERROR; + } + else + printf("Intference params: period[%x] cnt[%x] txfail_thresh[%x]" + " tcptxfail_thresh[%x]\n", param.period, param.cnt, + param.txfail_thresh, param.tcptxfail_thresh); + } + else { + /* Validate num of entries */ + err = BCME_USAGE_ERROR; + + for (argc = 0; argv[argc]; argc++); + if (argc != 4) + goto error; + + param.period = (uint8)strtol(argv[0], &endptr, 0); + if (*endptr != '\0') + goto error; + + param.cnt = (uint8)strtol(argv[1], &endptr, 0); + if (*endptr != '\0') + goto error; + + param.txfail_thresh = (uint8)strtol(argv[2], &endptr, 0); + if (*endptr != '\0') + goto error; + + param.tcptxfail_thresh = (uint8)strtol(argv[3], &endptr, 0); + if (*endptr != '\0') + goto error; + + /* Set intfer params */ + param.version = INTFER_VERSION; + err = wlu_iovar_set(wl, cmd->name, (void *) ¶m, + (sizeof(wl_intfer_params_t))); + } +error: + return (err); +} + +#ifdef WLP2P +static int +wl_p2p_state(void *wl, cmd_t *cmd, char **argv) +{ + wl_p2p_disc_st_t st; + int count; + char *endptr; + + argv++; + + count = ARGCNT(argv); + if (count < 1) + return BCME_USAGE_ERROR; + + st.state = (uint8) strtol(argv[0], &endptr, 0); + if (st.state == WL_P2P_DISC_ST_LISTEN) { + if (count != 3) + return BCME_USAGE_ERROR; + if ((st.chspec = wf_chspec_aton(argv[1])) == 0) { + fprintf(stderr, "error parsing chanspec arg \"%s\"\n", argv[1]); + return BCME_BADARG; + } + st.chspec = wl_chspec_to_driver(st.chspec); + if (st.chspec == INVCHANSPEC) { + return BCME_USAGE_ERROR; + } + st.dwell = (uint16) strtol(argv[2], &endptr, 0); + } + + return wlu_var_setbuf(wl, cmd->name, &st, sizeof(st)); +} + +static int +wl_p2p_scan(void *wl, cmd_t *cmd, char **argv) +{ + wl_p2p_scan_t *params = NULL; + int params_size = 0; + int malloc_size = 0; + int sparams_size = 0; + int err = 0; + + if (*(argv + 1) != NULL) { + malloc_size = sizeof(wl_p2p_scan_t); + switch (toupper(**(argv + 1))) { + case 'S': + malloc_size += WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); + break; + case 'E': + malloc_size += OFFSETOF(wl_escan_params_t, params) + + WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); + break; + } + } + if (malloc_size == 0) { + fprintf(stderr, "wrong syntax, need 'S' or 'E'\n"); + return BCME_BADARG; + } + + malloc_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + params = (wl_p2p_scan_t *)malloc(malloc_size); + if (params == NULL) { + fprintf(stderr, "Error allocating %d bytes for scan params\n", malloc_size); + return BCME_NOMEM; + } + memset(params, 0, malloc_size); + + switch (toupper(**(argv + 1))) { + case 'S': { + wl_scan_params_t *sparams = (wl_scan_params_t *)(params+1); + sparams_size = malloc_size - sizeof(wl_p2p_scan_t); + + params->type = 'S'; + + if ((err = wl_scan_prep(wl, cmd, argv + 1, sparams, &sparams_size)) == 0) + params_size = sizeof(wl_p2p_scan_t) + sparams_size; + break; + } + + case 'E': { + wl_escan_params_t *eparams = (wl_escan_params_t *)(params+1); + sparams_size = malloc_size - sizeof(wl_p2p_scan_t) - sizeof(wl_escan_params_t); + + params->type = 'E'; + + eparams->version = htod32(ESCAN_REQ_VERSION); + eparams->action = htod16(WL_SCAN_ACTION_START); + + srand((unsigned)time(NULL)); + eparams->sync_id = htod16(rand() & 0xffff); + + if ((err = wl_scan_prep(wl, cmd, argv + 1, &eparams->params, &sparams_size)) == 0) + params_size = sizeof(wl_p2p_scan_t) + sizeof(wl_escan_params_t) + + sparams_size; + break; + } + } + + if (!err) + err = wlu_iovar_setbuf(wl, cmd->name, params, params_size, buf, WLC_IOCTL_MAXLEN); + + free(params); + return err; +} + +static int +wl_p2p_ifadd(void *wl, cmd_t *cmd, char **argv) +{ + wl_p2p_if_t ifreq; + int count; + + argv++; + + count = ARGCNT(argv); + if (count < 2) + return BCME_USAGE_ERROR; + + if (!wl_ether_atoe(argv[0], &ifreq.addr)) + return BCME_USAGE_ERROR; + + if (stricmp(argv[1], "go") == 0) + ifreq.type = WL_P2P_IF_GO; + else if (stricmp(argv[1], "client") == 0) + ifreq.type = WL_P2P_IF_CLIENT; + else if (stricmp(argv[1], "dyngo") == 0) + ifreq.type = WL_P2P_IF_DYNBCN_GO; + else + return BCME_USAGE_ERROR; + + if (ifreq.type == WL_P2P_IF_GO || ifreq.type == WL_P2P_IF_DYNBCN_GO) { + if (count > 2) { + if ((ifreq.chspec = wf_chspec_aton(argv[2])) == 0) { + fprintf(stderr, "error parsing chanspec arg \"%s\"\n", argv[2]); + return BCME_BADARG; + } + ifreq.chspec = wl_chspec_to_driver(ifreq.chspec); + if (ifreq.chspec == INVCHANSPEC) { + return BCME_BADARG; + } + } + else + ifreq.chspec = 0; + } + + return wlu_var_setbuf(wl, cmd->name, &ifreq, sizeof(ifreq)); +} + +static int +wl_p2p_ifdel(void *wl, cmd_t *cmd, char **argv) +{ + struct ether_addr addr; + int count; + + argv++; + + count = ARGCNT(argv); + if (count != 1) + return BCME_USAGE_ERROR; + + if (!wl_ether_atoe(argv[0], &addr)) + return BCME_USAGE_ERROR; + + return wlu_var_setbuf(wl, cmd->name, &addr, sizeof(addr)); +} + +static int +wl_p2p_ifupd(void *wl, cmd_t *cmd, char **argv) +{ + wl_p2p_if_t ifreq; + int count; + int ret; + int bsscfg_idx = 0; + int consumed = 0; + + argv++; + + /* parse a bsscfg_idx option if present */ + if ((ret = wl_cfg_option(argv, cmd->name, &bsscfg_idx, &consumed)) != 0) + return ret; + argv += consumed; + if (consumed == 0) + bsscfg_idx = -1; + + count = ARGCNT(argv); + if (count < 2) + return BCME_USAGE_ERROR; + + if (!wl_ether_atoe(argv[0], &ifreq.addr)) + return BCME_USAGE_ERROR; + + if (stricmp(argv[1], "go") == 0) + ifreq.type = WL_P2P_IF_GO; + else if (stricmp(argv[1], "client") == 0) + ifreq.type = WL_P2P_IF_CLIENT; + else + return BCME_USAGE_ERROR; + + ifreq.chspec = 0; + + if (bsscfg_idx == -1) + return wlu_var_setbuf(wl, cmd->name, &ifreq, sizeof(ifreq)); + return wlu_bssiovar_setbuf(wl, cmd->name, bsscfg_idx, + &ifreq, sizeof(ifreq), + buf, WLC_IOCTL_MAXLEN); +} + +static int +wl_p2p_if(void *wl, cmd_t *cmd, char **argv) +{ + struct ether_addr addr; + int count; + wl_p2p_ifq_t *ptr; + int err; + + argv++; + + count = ARGCNT(argv); + if (count != 1) + return BCME_USAGE_ERROR; + + if (!wl_ether_atoe(argv[0], &addr)) + return BCME_USAGE_ERROR; + + err = wlu_var_getbuf(wl, cmd->name, &addr, sizeof(addr), (void*)&ptr); + if (err >= 0) + printf("%u %s\n", dtoh32(ptr->bsscfgidx), (ptr->ifname)); + + return err; +} + +static int +wl_p2p_ops(void *wl, cmd_t *cmd, char **argv) +{ + wl_p2p_ops_t ops; + int count; + char *endptr; + + argv++; + + count = ARGCNT(argv); + if (count < 1) { + wl_p2p_ops_t *ops; + int err; + + err = wlu_var_getbuf(wl, cmd->name, NULL, 0, (void *)&ops); + if (err != BCME_OK) { + fprintf(stderr, "%s: error %d\n", cmd->name, err); + return err; + } + + printf("ops: %u ctw: %u\n", ops->ops, ops->ctw); + + return BCME_OK; + } + + ops.ops = (uint8) strtol(argv[0], &endptr, 0); + if (ops.ops != 0) { + if (count != 2) + return BCME_USAGE_ERROR; + ops.ctw = (uint8) strtol(argv[1], &endptr, 0); + } + else + ops.ctw = 0; + + return wlu_var_setbuf(wl, cmd->name, &ops, sizeof(ops)); +} + +static int +wl_p2p_noa(void *wl, cmd_t *cmd, char **argv) +{ + int count; + wl_p2p_sched_t *noa; + int len; + int i; + char *endptr; + + argv ++; + + strcpy(buf, cmd->name); + + count = ARGCNT(argv); + if (count < 2) { + int err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MAXLEN); + wl_p2p_sched_t *sched; + int i; + + if (err != BCME_OK) { + fprintf(stderr, "%s: error %d\n", cmd->name, err); + return err; + } + + sched = (wl_p2p_sched_t *)buf; + for (i = 0; i < 16; i ++) { + if (sched->desc[i].count == 0) + break; + printf("start: %u interval: %u duration: %u count: %u\n", + sched->desc[i].start, sched->desc[i].interval, + sched->desc[i].duration, sched->desc[i].count); + } + + return BCME_OK; + } + + len = strlen(buf); + + noa = (wl_p2p_sched_t *)&buf[len + 1]; + len += 1; + + noa->type = (uint8)strtol(argv[0], &endptr, 0); + len += sizeof(noa->type); + noa->action = (uint8)strtol(argv[1], &endptr, 0); + len += sizeof(noa->action); + + argv += 2; + count -= 2; + + /* action == -1 is to cancel the current schedule */ + if (noa->action == WL_P2P_SCHED_ACTION_RESET) { + /* the fixed portion of wl_p2p_sched_t with action == WL_P2P_SCHED_ACTION_RESET + * is required to cancel the curret schedule. + */ + len += (char *)&noa->desc[0] - ((char *)buf + len); + } + /* Take care of any special cases only and let all other cases fall through + * as normal 'start/interval/duration/count' descriptions. + * All cases start with 'type' 'action' 'option'. + * Any count value greater than 255 is to repeat unlimited. + */ + else { + switch (noa->type) { + case WL_P2P_SCHED_TYPE_ABS: + case WL_P2P_SCHED_TYPE_REQ_ABS: + if (count < 1) + return BCME_USAGE_ERROR; + noa->option = (uint8)strtol(argv[0], &endptr, 0); + len += sizeof(noa->option); + argv += 1; + count -= 1; + break; + } + + /* add any paddings before desc field */ + len += (char *)&noa->desc[0] - ((char *)buf + len); + + switch (noa->type) { + case WL_P2P_SCHED_TYPE_ABS: + switch (noa->option) { + case WL_P2P_SCHED_OPTION_BCNPCT: + if (count == 1) { + noa->desc[0].duration = htod32(strtol(argv[0], &endptr, 0)); + noa->desc[0].start = 100 - noa->desc[0].duration; + } + else if (count == 2) { + noa->desc[0].start = htod32(strtol(argv[0], &endptr, 0)); + noa->desc[0].duration = htod32(strtol(argv[1], &endptr, 0)); + } + else { + fprintf(stderr, "Usage: wl p2p_noa 0 %d 1 " + "<start-pct> <duration-pct>\n", + noa->action); + return BCME_USAGE_ERROR; + } + len += sizeof(wl_p2p_sched_desc_t); + break; + + default: + if (count < 4 || (count % 4) != 0) { + fprintf(stderr, "Usage: wl p2p_noa 0 %d 0 " + "<start> <interval> <duration> <count> ...\n", + noa->action); + return BCME_USAGE_ERROR; + } + goto normal; + } + break; + + default: + if (count != 4) { + fprintf(stderr, "Usage: wl p2p_noa 1 %d " + "<start> <interval> <duration> <count> ...\n", + noa->action); + return BCME_USAGE_ERROR; + } + /* fall through... */ + normal: + for (i = 0; i < count; i += 4) { + noa->desc[i / 4].start = htod32(strtoul(argv[i], &endptr, 0)); + noa->desc[i / 4].interval = htod32(strtol(argv[i + 1], &endptr, 0)); + noa->desc[i / 4].duration = htod32(strtol(argv[i + 2], &endptr, 0)); + noa->desc[i / 4].count = htod32(strtol(argv[i + 3], &endptr, 0)); + len += sizeof(wl_p2p_sched_desc_t); + } + break; + } + } + + return wlu_set(wl, WLC_SET_VAR, buf, len); +} +#endif /* WLP2P */ + +static int +wl_rpmt(void *wl, cmd_t *cmd, char **argv) +{ + int count; + int len; + char *endptr; + uint32 val; + + argv ++; + + count = ARGCNT(argv); + if (count != 2) { + return BCME_USAGE_ERROR; + } + + strcpy(buf, cmd->name); + len = strlen(buf) + 1; + + val = htod32(strtoul(argv[0], &endptr, 0)); + memcpy(&buf[len], &val, sizeof(uint32)); + len += sizeof(uint32); + val = htod32(strtoul(argv[1], &endptr, 0)); + memcpy(&buf[len], &val, sizeof(uint32)); + len += sizeof(uint32); + + return wlu_set(wl, WLC_SET_VAR, buf, len); +} + +static int +wl_ledbh(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_led_info_t led; + void *ptr = NULL; + + memset(&led, 0, sizeof(wl_led_info_t)); + if (*++argv == NULL) { + printf("Usage: ledbh [led#] [behavior#]\n"); + return BCME_USAGE_ERROR; + } + led.index = (int)strtoul(*argv, NULL, 10); + + if (led.index > 3) { + printf("only 4 led supported\n"); + return BCME_BADARG; + } + + if (*++argv) { /* set */ + /* Read the original back so we don't toggle the activehi */ + if ((err = wlu_var_getbuf(wl, cmd->name, (void*)&led, + sizeof(wl_led_info_t), &ptr)) < 0) { + printf("wl_ledbh: fail to get. code %x\n", err); + } + led.behavior = (int)strtoul(*argv, NULL, 10); + led.activehi = ((wl_led_info_t*)ptr)->activehi; + + if ((err = wlu_var_setbuf(wl, cmd->name, (void*)&led, + sizeof(wl_led_info_t))) < 0) { + printf("wl_ledbh: fail to set\n"); + } + } else { /* get */ + wl_led_info_t *ledo; + + if ((err = wlu_var_getbuf(wl, cmd->name, (void*)&led, + sizeof(wl_led_info_t), &ptr)) < 0) { + printf("wl_ledbh: fail to get\n"); + } + ledo = (wl_led_info_t*)ptr; + + printf("led %d behavior %d\n", ledo->index, ledo->behavior); + } + + return err; +} + +static int +wl_led_blink_sync(void *wl, cmd_t *cmd, char **argv) +{ + int argc; + int err = 0; + int in_arg[2]; + void *ptr = NULL; + char *endptr; + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc > 3 || argc < 2) + return BCME_USAGE_ERROR; + + in_arg[0] = htod32((uint32)(strtoul(argv[1], &endptr, 0))); + + if (in_arg[0] > 3) { + printf("only 4 led supported\n"); + return BCME_BADARG; + } + + if (argc == 2) { + err = wlu_var_getbuf(wl, cmd->name, (void*)in_arg, sizeof(int), &ptr); + if (err < 0) + return err; + printf("led%d, blink_sync is %s\n", in_arg[0], + (dtoh32(*(int*)ptr) != 0) ? "TRUE" : "FALSE"); + } + else if (argc == 3) { + in_arg[1] = htod32((uint32)(strtoul(argv[2], &endptr, 0))); + err = wlu_var_setbuf(wl, cmd->name, in_arg, sizeof(in_arg)); + } + else { + fprintf(stderr, "illegal command!\n"); + return BCME_USAGE_ERROR; + } + + return err; +} + +/* RM Enable Capabilities */ +static dbg_msg_t rrm_msgs[] = { + {DOT11_RRM_CAP_LINK, "Link_Measurement"}, /* bit0 */ + {DOT11_RRM_CAP_NEIGHBOR_REPORT, "Neighbor_Report"}, /* bit1 */ + {DOT11_RRM_CAP_PARALLEL, "Parallel_Measurement"}, /* bit2 */ + {DOT11_RRM_CAP_REPEATED, "Repeated_Measurement"}, /* bit3 */ + {DOT11_RRM_CAP_BCN_PASSIVE, "Beacon_Passive"}, /* bit4 */ + {DOT11_RRM_CAP_BCN_ACTIVE, "Beacon_Active"}, /* bit5 */ + {DOT11_RRM_CAP_BCN_TABLE, "Beacon_Table"}, /* bit6 */ + {DOT11_RRM_CAP_BCN_REP_COND, "Beacon_measurement_Reporting_Condition"}, /* bit7 */ + {DOT11_RRM_CAP_FM, "Frame_Measurement"}, /* bit8 */ + {DOT11_RRM_CAP_CLM, "Channel_load_Measurement"}, /* bit9 */ + {DOT11_RRM_CAP_NHM, "Noise_Histogram_measurement"}, /* bit10 */ + {DOT11_RRM_CAP_SM, "Statistics_Measurement"}, /* bit11 */ + {DOT11_RRM_CAP_LCIM, "LCI_Measurement"}, /* bit12 */ + {DOT11_RRM_CAP_LCIA, "LCI_Azimuth"}, /* bit13 */ + {DOT11_RRM_CAP_TSCM, "Tx_Stream_Category_Measurement"}, /* bit14 */ + {DOT11_RRM_CAP_TTSCM, "Triggered_Tx_stream_Category_Measurement"}, /* bit15 */ + {DOT11_RRM_CAP_AP_CHANREP, "AP_Channel_Report"}, /* bit16 */ + {DOT11_RRM_CAP_RMMIB, "RM_MIB"}, /* bit17 */ + /* bit 18-26, unused */ + {DOT11_RRM_CAP_MPTI, "Measurement_Pilot_Transmission_Information"}, /* bit27 */ + {DOT11_RRM_CAP_NBRTSFO, "Neighbor_Report_TSF_Offset"}, /* bit28 */ + {DOT11_RRM_CAP_RCPI, "RCPI_Measurement"}, /* bit29 */ + {DOT11_RRM_CAP_RSNI, "RSNI_Measurement"}, /* bit30 */ + {DOT11_RRM_CAP_BSSAAD, "BSS_Average_Access_Delay"}, /* bit31 */ + {DOT11_RRM_CAP_BSSAAC, "BSS_Available_Admission_Capacity"}, /* bit32 */ + {DOT11_RRM_CAP_AI, "Antenna_Information"}, /* bit33 */ + {0, NULL} +}; + +static bool rrm_input_validation(uint val, uint hval, dbg_msg_t *dbg_msg) +{ + int i; + uint32 flag = 0; + + if ((val == 0) && (hval == 0)) + return TRUE; + + for (i = 0; dbg_msg[i].value <= DOT11_RRM_CAP_BSSAAD; i++) + flag |= 1 << dbg_msg[i].value; + flag = ~flag; + if (val & flag) + return FALSE; + + flag = 0; + if (hval != 0) { + for (; dbg_msg[i].value; i++) { + flag |= 1 << (dbg_msg[i].value - DOT11_RRM_CAP_BSSAAC); + } + flag = ~flag; + if (hval & flag) + return FALSE; + } + + return TRUE; +} + +static int +wl_rrm(void *wl, cmd_t *cmd, char **argv) +{ + int err, i; + uint hval = 0, val = 0, len, found, rmcap_del = 0, rmcap2_del = 0; + uint rmcap_add = 0, rmcap2_add = 0; + char *endptr = NULL; + dbg_msg_t *dbg_msg = rrm_msgs; + void *ptr = NULL; + dot11_rrm_cap_ie_t rrm_cap, *reply; + uint high = 0, low = 0, bit = 0, hbit = 0; + const char *cmdname = "rrm"; + + UNUSED_PARAMETER(cmd); + + err = wlu_var_getbuf_sm(wl, cmdname, &rrm_cap, sizeof(rrm_cap), &ptr); + if (err < 0) + return err; + reply = (dot11_rrm_cap_ie_t *)ptr; + + high = reply->cap[4]; + low = reply->cap[0] | (reply->cap[1] << 8) | (reply->cap[2] << 16) | (reply->cap[3] << 24); + if (!*++argv) { + if (high != 0) + printf("0x%x%08x", high, low); + else + printf("0x%x ", low); + for (i = 0; ((bit = dbg_msg[i].value) <= DOT11_RRM_CAP_BSSAAD); i++) { + if (low & (1 << bit)) + printf(" %s", dbg_msg[i].string); + } + for (; (hbit = dbg_msg[i].value); i++) { + if (high & (1 << hbit)) + printf(" %s", dbg_msg[i].string); + } + printf("\n"); + + return err; + } + while (*argv) { + char *s = *argv; + char t[32]; + + found = 0; + if (*s == '+' || *s == '-') + s++; + else { + /* used for clearing previous value */ + rmcap_del = ~0; + rmcap2_del = ~0; + } + val = strtoul(s, &endptr, 0); + /* Input is decimal number or hex with prefix 0x and > 32 bits */ + if (val == 0xFFFFFFFF) { + if (!(*s == '0' && *(s+1) == 'x')) { + fprintf(stderr, + "Msg bits >32 take only numerical input in hex\n"); + val = 0; + } else { + /* Input number with prefix 0x */ + char c[32] = "0x"; + len = strlen(s); + hval = strtoul(strncpy(t, s, len-8), &endptr, 0); + *endptr = 0; + s = s + strlen(t); + s = strcat(c, s); + val = strtoul(s, &endptr, 0); + /* Input number > 64bit */ + if (hval == 0xFFFFFFFF) { + fprintf(stderr, "Invalid entry for RM Capabilities\n"); + hval = 0; + val = 0; + } + } + } + /* validet the input number */ + if (!rrm_input_validation(val, hval, dbg_msg)) + goto usage; + /* Input is a string */ + if (*endptr != '\0') { + for (i = 0; ((bit = dbg_msg[i].value) <= DOT11_RRM_CAP_BSSAAD); i++) { + if (stricmp(dbg_msg[i].string, s) == 0) { + found = 1; + break; + } + } + if (!found) { + for (; (hbit = dbg_msg[i].value); i++) { + if (stricmp(dbg_msg[i].string, s) == 0) + break; + } + if (hbit) + hval = 1 << (hbit - DOT11_RRM_CAP_BSSAAC); + else + hval = 0; + } else { + val = 1 << bit; + } + if (!val && !hval) + goto usage; + } + if (**argv == '-') { + rmcap_del |= val; + if (!found) + rmcap2_del |= hval; + } + else { + rmcap_add |= val; + if (!found) + rmcap2_add |= hval; + } + ++argv; + } + + low &= ~rmcap_del; + high &= ~rmcap2_del; + low |= rmcap_add; + high |= rmcap2_add; + + rrm_cap.cap[4] = high; + rrm_cap.cap[0] = low & 0x000000ff; + rrm_cap.cap[1] = (low & 0x0000ff00) >> 8; + rrm_cap.cap[2] = (low & 0x00ff0000) >> 16; + rrm_cap.cap[3] = (low & 0xff000000) >> 24; + + err = wlu_var_setbuf(wl, cmdname, &rrm_cap, sizeof(dot11_rrm_cap_ie_t)); + return err; + +usage: + fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n"); + fprintf(stderr, "Use a + or - prefix to make an incremental change."); + for (i = 0; (bit = dbg_msg[i].value) <= DOT11_RRM_CAP_BSSAAD; i++) { + fprintf(stderr, "\n0x%04x %s", (1 << bit), dbg_msg[i].string); + } + for (; (hbit = dbg_msg[i].value); i++) { + hbit -= DOT11_RRM_CAP_BSSAAC; + fprintf(stderr, "\n0x%x00000000 %s", (1 << hbit), dbg_msg[i].string); + } + fprintf(stderr, "\n"); + return BCME_OK; +} + +static int +wl_rrm_stat_req(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + const char *cmdname = "rrm_stat_req"; + statreq_t sreq_buf; + + UNUSED_PARAMETER(cmd); + memset(&sreq_buf, 0, sizeof(statreq_t)); + + if (argv[1]) { + /* da */ + if (!wl_ether_atoe(argv[1], &sreq_buf.da)) { + printf("wl_rrm_stat_req parsing da failed\n"); + return BCME_USAGE_ERROR; + } + } + /* random interval */ + if (argv[2]) { + sreq_buf.random_int = htod32(strtoul(argv[2], NULL, 0)); + } + /* duration */ + if (argv[3]) { + sreq_buf.dur = htod32(strtoul(argv[3], NULL, 0)); + } + /* peer address */ + if (argv[4]) { + if (!wl_ether_atoe(argv[4], &sreq_buf.peer)) { + printf("wl_rrm_stat_req parsing peer failed\n"); + return BCME_USAGE_ERROR; + } + } + /* group id */ + if (argv[5]) { + sreq_buf.group_id = + htod32(strtoul(argv[5], NULL, 0)); + } + /* repetitions */ + if (argv[6]) { + sreq_buf.reps = htod32(strtoul(argv[6], NULL, 0)); + } + err = wlu_iovar_set(wl, cmdname, &sreq_buf, sizeof(sreq_buf)); + return err; +} + +static int +wl_rrm_frame_req(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + const char *cmdname = "rrm_frame_req"; + framereq_t freq_buf; + + UNUSED_PARAMETER(cmd); + + memset(&freq_buf, 0, sizeof(framereq_t)); + if (argv[1]) { + /* Regulatory class */ + freq_buf.reg = htod32(strtoul(argv[1], NULL, 0)); + } + + /* da */ + if (argv[2]) { + if (!wl_ether_atoe(argv[2], &freq_buf.da)) { + printf("wl_rrm_frame_req parsing da failed\n"); + return BCME_USAGE_ERROR; + } + } + /* duration */ + if (argv[3]) { + freq_buf.dur = htod32(strtoul(argv[3], NULL, 0)); + } + /* random interval */ + if (argv[4]) { + freq_buf.random_int = htod32(strtoul(argv[4], NULL, 0)); + } + /* channel */ + if (argv[5]) { + freq_buf.chan = htod32(strtoul(argv[5], NULL, 0)); + } + /* transmit address */ + if (argv[6]) { + if (!wl_ether_atoe(argv[6], &freq_buf.ta)) { + printf("wl_rrm_frame_req parsing ta failed\n"); + return BCME_USAGE_ERROR; + } + } + /* repetitions */ + if (argv[7]) { + freq_buf.reps = htod32(strtoul(argv[7], NULL, 0)); + } + err = wlu_iovar_set(wl, cmdname, &freq_buf, sizeof(freq_buf)); + return err; +} + +static int +wl_rrm_chload_req(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + const char *cmdname = "rrm_chload_req"; + rrmreq_t chreq_buf; + + UNUSED_PARAMETER(cmd); + memset(&chreq_buf, 0, sizeof(rrmreq_t)); + + if (argv[1]) { + /* Regulatory class */ + chreq_buf.reg = htod32(strtoul(argv[1], NULL, 0)); + } + /* da */ + if (argv[2]) { + if (!wl_ether_atoe(argv[2], &chreq_buf.da)) { + printf("wl_rrm_chload_req parsing da failed\n"); + return BCME_USAGE_ERROR; + } + } + /* duration */ + if (argv[3]) { + chreq_buf.dur = htod32(strtoul(argv[3], NULL, 0)); + } + /* random interval */ + if (argv[4]) { + chreq_buf.random_int = htod32(strtoul(argv[4], NULL, 0)); + } + /* channel */ + if (argv[5]) { + chreq_buf.chan = htod32(strtoul(argv[5], NULL, 0)); + } + /* repetitions */ + if (argv[6]) { + chreq_buf.reps = htod32(strtoul(argv[6], NULL, 0)); + } + err = wlu_iovar_set(wl, cmdname, &chreq_buf, sizeof(chreq_buf)); + return err; +} + +static int +wl_rrm_noise_req(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + const char *cmdname = "rrm_noise_req"; + rrmreq_t nreq_buf; + + UNUSED_PARAMETER(cmd); + printf("wl_rrm_noise_req\n"); + + memset(&nreq_buf, 0, sizeof(rrmreq_t)); + if (argv[1]) { + /* Regulatory class */ + nreq_buf.reg = htod32(strtoul(argv[1], NULL, 0)); + } + /* da */ + if (argv[2]) { + if (!wl_ether_atoe(argv[2], &nreq_buf.da)) { + printf("wl_rrm_noise_req parsing da failed\n"); + return BCME_USAGE_ERROR; + } + } + /* duration */ + if (argv[3]) { + nreq_buf.dur = htod32(strtoul(argv[3], NULL, 0)); + + } + /* random interval */ + if (argv[4]) { + nreq_buf.random_int = htod32(strtoul(argv[4], NULL, 0)); + } + /* channel */ + if (argv[5]) { + nreq_buf.chan = htod32(strtoul(argv[5], NULL, 0)); + } + /* repetitions */ + if (argv[6]) { + nreq_buf.reps = htod32(strtoul(argv[6], NULL, 0)); + } + err = wlu_iovar_set(wl, cmdname, &nreq_buf, sizeof(nreq_buf)); + return err; +} + +static int +wl_rrm_bcn_req(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + uint8 mode = 0; + const char *cmdname = "rrm_bcn_req"; + bcnreq_t bcnreq_buf; + wlc_ssid_t ssid; + + UNUSED_PARAMETER(cmd); + memset(&bcnreq_buf, 0, sizeof(bcnreq_t)); + + if (argv[1]) { + /* bcn mode: ACTIVE/PASSIVE/SCAN_CACHE */ + mode = htod32(strtoul(argv[1], NULL, 0)); + if (mode > 2) { + printf("wl_rrm_bcn_req parsing bcn mode failed\n"); + return BCME_BADARG; + } + bcnreq_buf.bcn_mode = mode; + } + /* da */ + if (argv[2]) { + if (!wl_ether_atoe(argv[2], &bcnreq_buf.da)) { + printf("wl_rrm_bcn_req parsing da failed\n"); + return BCME_USAGE_ERROR; + } + } + /* duration */ + if (argv[3]) { + bcnreq_buf.dur = htod32(strtoul(argv[3], NULL, 0)); + } + + /* random interval */ + if (argv[4]) { + bcnreq_buf.random_int = htod32(strtoul(argv[4], NULL, 0)); + } + + /* channel */ + if (argv[5]) { + bcnreq_buf.channel = htod32(strtoul(argv[5], NULL, 0)); + } + printf("wl_rrm_bcn_req:bcn mode: %d, duration: %d, " + "chan: %d\n", mode, + bcnreq_buf.dur, bcnreq_buf.channel); + + /* SSID */ + if (argv[6]) { + uint32 len; + + len = strlen(argv[6]); + if (len > DOT11_MAX_SSID_LEN) { + printf("ssid too long\n"); + return BCME_BADARG; + } + memset(&ssid, 0, sizeof(wlc_ssid_t)); + memcpy(ssid.SSID, argv[6], len); + ssid.SSID_len = len; + memcpy(&bcnreq_buf.ssid, &ssid, sizeof(wlc_ssid_t)); + } + + /* repetitions */ + if (argv[7]) { + bcnreq_buf.reps = htod32(strtoul(argv[7], NULL, 0)); + } + + err = wlu_iovar_set(wl, cmdname, &bcnreq_buf, sizeof(bcnreq_buf)); + return err; +} + +static int +wl_rrm_lm_req(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + const char *cmdname = "rrm_lm_req"; + + struct ether_addr da; + UNUSED_PARAMETER(cmd); + + if (argv[1]) { + if (!wl_ether_atoe(argv[1], &da)) { + printf("wl_rrm_lm_req parsing arg1 failed\n"); + return BCME_USAGE_ERROR; + } + } + err = wlu_iovar_set(wl, cmdname, &da, sizeof(da)); + return err; +} + +static int +wl_rrm_nbr_req(void *wl, cmd_t *cmd, char **argv) +{ + int err, buflen; + wlc_ssid_t ssid; + + UNUSED_PARAMETER(cmd); + + strcpy(buf, "rrm_nbr_req"); + buflen = strlen("rrm_nbr_req") + 1; + + if (*++argv) { + uint32 len; + + len = strlen(*argv); + if (len > DOT11_MAX_SSID_LEN) { + printf("ssid too long\n"); + return BCME_BADARG; + } + memset(&ssid, 0, sizeof(wlc_ssid_t)); + memcpy(ssid.SSID, *argv, len); + ssid.SSID_len = len; + memcpy(&buf[buflen], &ssid, sizeof(wlc_ssid_t)); + buflen += sizeof(wlc_ssid_t); + } + + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + return err; +} + +/* For mapping customer's user space command, two calls of the same iovar. */ +static int +wl_rrm_nbr_list(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0, buflen, i; + uint16 list_cnt; + nbr_element_t *nbr_elt; + uint8 *ptr; + + UNUSED_PARAMETER(cmd); + + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(buf, "rrm_nbr_list"); + buflen = strlen("rrm_nbr_list") + 1; + + if (*++argv != NULL) + return BCME_USAGE_ERROR; + + if ((err = wlu_get(wl, WLC_GET_VAR, buf, buflen)) < 0) + return err; + + list_cnt = *(uint16 *)buf; + + if (list_cnt == 0) + return err; + + memset(buf, 0, WLC_IOCTL_MAXLEN); + strcpy(buf, "rrm_nbr_list"); + buflen = strlen("rrm_nbr_list") + 1; + + memcpy(&buf[buflen], &list_cnt, sizeof(uint16)); + + printf("RRM Neighbor Report List:\n"); + + if ((err = wlu_get(wl, WLC_GET_VAR, buf, WLC_IOCTL_MAXLEN)) < 0) + return err; + + ptr = (uint8 *)buf; + + for (i = 0; i < list_cnt; i++) { + nbr_elt = (nbr_element_t *)ptr; + printf("AP %2d: ", i + 1); + printf("bssid %02x:%02x:%02x:%02x:%02x:%02x ", nbr_elt->bssid.octet[0], + nbr_elt->bssid.octet[1], nbr_elt->bssid.octet[2], nbr_elt->bssid.octet[3], + nbr_elt->bssid.octet[4], nbr_elt->bssid.octet[5]); + + printf("bssid_info %08x ", load32_ua(&nbr_elt->bssid_info)); + printf("reg %2d channel %3d phytype %d\n", nbr_elt->reg, + nbr_elt->channel, nbr_elt->phytype); + + ptr += TLV_HDR_LEN + DOT11_NEIGHBOR_REP_IE_FIXED_LEN; + } + + return err; +} + +static int +wl_rrm_nbr_del_nbr(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + const char *cmdname = "rrm_nbr_del_nbr"; + struct ether_addr ea; + + UNUSED_PARAMETER(cmd); + + if (*++argv == NULL) { + printf("no bssid specified\n"); + return BCME_USAGE_ERROR; + } else { + if (!wl_ether_atoe(*argv, &ea)) { + printf("Incorrect bssid format\n"); + return BCME_ERROR; + } + err = wlu_iovar_set(wl, cmdname, &ea, sizeof(ea)); + } + + return err; +} + +static int +wl_rrm_nbr_add_nbr(void *wl, cmd_t *cmd, char **argv) +{ + int argc; + int err = 0; + const char *cmdname = "rrm_nbr_add_nbr"; + nbr_element_t nbr_elt; + + UNUSED_PARAMETER(cmd); + memset(&nbr_elt, 0, sizeof(nbr_element_t)); + + for (argc = 0; argv[argc]; argc++) + ; + + if (argc != 6) + return BCME_USAGE_ERROR; + + /* bssid */ + if (!wl_ether_atoe(argv[1], &nbr_elt.bssid)) { + printf("wl_rrm_nbr_add_nbr parsing bssid failed\n"); + return BCME_USAGE_ERROR; + } + + /* bssid info */ + nbr_elt.bssid_info = htod32(strtoul(argv[2], NULL, 0)); + + /* Regulatory class */ + nbr_elt.reg = htod32(strtoul(argv[3], NULL, 0)); + + /* channel */ + nbr_elt.channel = htod32(strtoul(argv[4], NULL, 0)); + + /* phytype */ + nbr_elt.phytype = htod32(strtoul(argv[5], NULL, 0)); + + nbr_elt.id = DOT11_MNG_NEIGHBOR_REP_ID; + nbr_elt.len = DOT11_NEIGHBOR_REP_IE_FIXED_LEN; + + err = wlu_iovar_set(wl, cmdname, &nbr_elt, TLV_HDR_LEN + DOT11_NEIGHBOR_REP_IE_FIXED_LEN); + return err; +} + +static dbg_msg_t wl_wnm_msgs[] = { + {WL_WNM_BSSTRANS, "BSS-Transition"}, + {WL_WNM_PROXYARP, "Proxy-ARP"}, + {WL_WNM_MAXIDLE, "BSS-Max-Idle-Period"}, + {WL_WNM_TIMBC, "TIM-Broadcast"}, + {WL_WNM_TFS, "Traffic-Filtering"}, + {WL_WNM_SLEEP, "WNM-Sleep-Mode"}, + {WL_WNM_DMS, "Directed-Multicast"}, + {WL_WNM_FMS, "Flexible-Multicast"}, + {WL_WNM_NOTIF, "Notification"}, + {0, ""} +}; + +static int +wl_wnm(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + uint val; + int wnmmask; + char *s; + + ret = wlu_iovar_getint(wl, cmd->name, &wnmmask); + if (ret < 0) + return ret; + + if (!*++argv) { + printf("0x%x:", wnmmask); + for (i = 0; wl_wnm_msgs[i].value; i++) + if (wnmmask & wl_wnm_msgs[i].value) + printf(" %s", wl_wnm_msgs[i].string); + printf("\n"); + return 0; + } + + s = *argv; + if (*s == '+' || *s == '-') + s++; + + if (!*s) + goto usage; + + val = strtoul(s, &s, 0); + if (*s) + goto usage; + + if (**argv == '+') + wnmmask |= val; + else if (**argv == '-') + wnmmask &= ~val; + else + wnmmask = val; + + return wlu_iovar_setint(wl, cmd->name, wnmmask); + +usage: + fprintf(stderr, "WNM mask is a bitfield from the following set. " + "Use + or - prefix to combine with current value:\n"); + + for (i = 0; wl_wnm_msgs[i].value; i++) + fprintf(stderr, " 0x%04x %s\n", wl_wnm_msgs[i].value, wl_wnm_msgs[i].string); + + return 0; +} + +static int +wl_wnm_bsstq(void *wl, cmd_t *cmd, char **argv) +{ + int err, buflen; + wlc_ssid_t ssid; + + UNUSED_PARAMETER(cmd); + + strcpy(buf, "wnm_bsstrans_query"); + buflen = strlen("wnm_bsstrans_query") + 1; + + if (*++argv) { + uint32 len; + + len = strlen(*argv); + if (len > DOT11_MAX_SSID_LEN) { + printf("ssid too long\n"); + return (-1); + } + memset(&ssid, 0, sizeof(wlc_ssid_t)); + memcpy(ssid.SSID, *argv, len); + ssid.SSID_len = len; + memcpy(&buf[buflen], &ssid, sizeof(wlc_ssid_t)); + buflen += sizeof(wlc_ssid_t); + } + + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + return err; +} + +#define TCLAS_ARG_CHECK(argv, str) \ + do { \ + if (*++(argv) == NULL) { \ + printf("TCLAS Frame Classifier: %s not provided\n", (str)); \ + return BCME_ERROR; \ + } \ + } while (0) + +static int +wl_tclas_add(void *wl, cmd_t *cmd, char **argv) +{ + int err = -1, buflen; + dot11_tclas_fc_t *fc; + + UNUSED_PARAMETER(cmd); + + buflen = sprintf(buf, "%s", *argv) + 1; + + /* Check the user priority value */ + TCLAS_ARG_CHECK(argv, "user priority"); + buf[buflen++] = (uint8)strtoul(*argv, NULL, 0); + + /* unaligned! */ + fc = (dot11_tclas_fc_t *) (buf + buflen); + memset((void *)fc, 0, sizeof(dot11_tclas_fc_t)); + + /* Parse frame classifier type and mask */ + TCLAS_ARG_CHECK(argv, "type"); + fc->hdr.type = (uint8)strtoul(*argv, NULL, 0); + + TCLAS_ARG_CHECK(argv, "mask"); + fc->hdr.mask = (uint8)strtoul(*argv, NULL, 0); + if (fc->hdr.type == DOT11_TCLAS_FC_0_ETH) { + dot11_tclas_fc_0_eth_t *fc_eth = (dot11_tclas_fc_0_eth_t *)fc; + + TCLAS_ARG_CHECK(argv, "src mac"); + if (strlen(*argv) > 1) { + if (!wl_ether_atoe(*argv, (struct ether_addr *)fc_eth->sa)) { + printf(" ERROR: no valid src ether addr provided\n"); + return BCME_ERROR; + } + } + else + memset(fc_eth->sa, 0, ETHER_ADDR_LEN); + + TCLAS_ARG_CHECK(argv, "dst mac"); + if (strlen(*argv) > 1) { + if (!wl_ether_atoe(*argv, (struct ether_addr *)fc_eth->da)) { + printf(" ERROR: no valid dst ether addr provided\n"); + return BCME_ERROR; + } + } + else + memset(fc_eth->da, 0, ETHER_ADDR_LEN); + + TCLAS_ARG_CHECK(argv, "ether type"); + fc_eth->eth_type = hton16((uint16)strtoul(*argv, NULL, 0)); + + buflen += DOT11_TCLAS_FC_0_ETH_LEN; + + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + } + else if (fc->hdr.type == DOT11_TCLAS_FC_1_IP || + fc->hdr.type == DOT11_TCLAS_FC_4_IP_HIGHER) { + uint8 version; + + TCLAS_ARG_CHECK(argv, "ip version"); + version = (uint8)strtoul(*argv, NULL, 0); + if (version == IP_VER_6) { + dot11_tclas_fc_4_ipv6_t *fc_ipv6 = (dot11_tclas_fc_4_ipv6_t *)fc; + uint32 fl; + + fc_ipv6->version = version; + + TCLAS_ARG_CHECK(argv, "ipv6 source ip"); + if (!wl_atoipv6(*argv, (struct ipv6_addr *)&fc_ipv6->saddr)) { + printf("incorrect ipv6 source ip format\n"); + return BCME_ERROR; + } + + TCLAS_ARG_CHECK(argv, "ipv6 dest ip"); + if (!wl_atoipv6(*argv, (struct ipv6_addr *)&fc_ipv6->daddr)) { + printf("incorrect ipv6 dest ip format\n"); + return BCME_ERROR; + } + + TCLAS_ARG_CHECK(argv, "ipv6 source port"); + fc_ipv6->src_port = hton16((uint16)strtoul(*argv, NULL, 0)); + + TCLAS_ARG_CHECK(argv, "ipv6 dest port"); + fc_ipv6->dst_port = hton16((uint16)strtoul(*argv, NULL, 0)); + + TCLAS_ARG_CHECK(argv, "ipv6 dscp"); + fc_ipv6->dscp = (uint8)strtoul(*argv, NULL, 0); + + TCLAS_ARG_CHECK(argv, "ipv6 next header"); + fc_ipv6->nexthdr = (uint8)strtoul(*argv, NULL, 0); + + TCLAS_ARG_CHECK(argv, "ipv6 flow label"); + fl = (uint32) strtoul(*argv, NULL, 0); + fc_ipv6->flow_lbl[2] = (fl >> 16) & 0xFF; + fc_ipv6->flow_lbl[1] = (fl >> 8) & 0xFF; + fc_ipv6->flow_lbl[0] = (fl >> 0) & 0xFF; + + buflen += DOT11_TCLAS_FC_4_IPV6_LEN; + + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + } else + if (version == IP_VER_4) { + dot11_tclas_fc_1_ipv4_t *fc_ipv4 = (dot11_tclas_fc_1_ipv4_t *)fc; + + fc_ipv4->version = version; + + TCLAS_ARG_CHECK(argv, "ipv4 source ip"); + if (!wl_atoip(*argv, (struct ipv4_addr *)&fc_ipv4->src_ip)) { + printf("incorrect source ip format\n"); + return BCME_ERROR; + } + + TCLAS_ARG_CHECK(argv, "ipv4 dest ip"); + if (!wl_atoip(*argv, (struct ipv4_addr *)&fc_ipv4->dst_ip)) { + printf("incorrect dest ip format\n"); + return BCME_ERROR; + } + + TCLAS_ARG_CHECK(argv, "ipv4 source port"); + fc_ipv4->src_port = (uint16)strtoul(*argv, NULL, 0); + fc_ipv4->src_port = hton16(fc_ipv4->src_port); + + TCLAS_ARG_CHECK(argv, "ipv4 dest port"); + fc_ipv4->dst_port = (uint16)strtoul(*argv, NULL, 0); + fc_ipv4->dst_port = hton16(fc_ipv4->dst_port); + + TCLAS_ARG_CHECK(argv, "ipv4 dscp"); + fc_ipv4->dscp = (uint8)strtoul(*argv, NULL, 0); + + TCLAS_ARG_CHECK(argv, "ipv4 protocol"); + fc_ipv4->protocol = (uint8)strtoul(*argv, NULL, 0); + + buflen += DOT11_TCLAS_FC_1_IPV4_LEN; + + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + } else + return BCME_ERROR; + } else { + printf("Unsupported frame classifier type 0x%2x\n", fc->hdr.type); + return BCME_ERROR; + } + + return err; +} + +static int +wl_tclas_del(void *wl, cmd_t *cmd, char **argv) +{ + int err, buflen, totlen; + + UNUSED_PARAMETER(cmd); + + buflen = sprintf(buf, "%s", *argv) + 1; + totlen = buflen + 2; + + /* Set initial length */ + buf[buflen] = 0; /* first value present for init index */ + buf[buflen + 1] = 0; /* second value present for delete count */ + + /* Check idx and add if present */ + if (*++argv == NULL) + goto set; + buf[buflen] = 1; + buf[buflen + 1] = (uint8)strtoul(*argv, NULL, 0); + + /* Check len and add if present */ + if (*++argv == NULL) + goto set; + buf[buflen] = 2; + buf[buflen + 2] = (uint8)strtoul(*argv, NULL, 0); + + if (*++argv) { + printf("Too much args provided\n"); + return BCME_ERROR; + } +set: + err = wlu_set(wl, WLC_SET_VAR, buf, totlen); + + return err; +} + + +static void +wl_tclas_dump(wl_tclas_t *tclas) +{ + dot11_tclas_fc_hdr_t *fc = &tclas->fc.hdr; + dot11_tclas_fc_0_eth_t *eth = &tclas->fc.t0_eth; + dot11_tclas_fc_1_ipv4_t *ipv4 = &tclas->fc.t1_ipv4; + dot11_tclas_fc_4_ipv6_t *ipv6 = &tclas->fc.t4_ipv6; + +#define TCDMP(x) ((fc->mask & (x))?'+':'-') + + printf("up %d type %d mask 0x%x ", tclas->user_priority, fc->type, fc->mask); + + /* Check frame classifier parameter type */ + if (fc->type == DOT11_TCLAS_FC_0_ETH) { + printf("(Eth: "); + printf("%cSA %s ", TCDMP(1), wl_ether_etoa((struct ether_addr*)eth->sa)); + printf("%cDA %s ", TCDMP(2), wl_ether_etoa((struct ether_addr*)eth->da)); + printf("%ctype 0x%04x", TCDMP(4), ntoh16(eth->eth_type)); + printf(")\n"); + } else if (fc->type == DOT11_TCLAS_FC_1_IP || + (fc->type == DOT11_TCLAS_FC_4_IP_HIGHER && ipv4->version == IP_VER_4)) { + /* Check parameter type 1/4 IPv4 version */ + printf("(IPv4: "); + printf("%cver %d ", TCDMP(1), ipv4->version); + printf("%csip %s ", TCDMP(2), wl_iptoa((struct ipv4_addr *)&ipv4->src_ip)); + printf("%cdip %s ", TCDMP(4), wl_iptoa((struct ipv4_addr *)&ipv4->dst_ip)); + printf("%csp %d ", TCDMP(8), ntoh16(ipv4->src_port)); + printf("%cdp %d ", TCDMP(16), ntoh16(ipv4->dst_port)); + printf("%cdscp 0x%x ", TCDMP(32), ipv4->dscp); + printf("%cprot %d", TCDMP(64), ipv4->protocol); + printf(")\n"); + } else if (fc->type == DOT11_TCLAS_FC_4_IP_HIGHER && ipv6->version == IP_VER_6) { + /* Check parameter type 4 IPv6 version */ + printf("(IPv6: "); + printf("%cver %d ", TCDMP(1), ipv6->version); + printf("%csip %s ", TCDMP(2), wl_ipv6toa(ipv6->saddr)); + printf("%cdip %s ", TCDMP(4), wl_ipv6toa(ipv6->daddr)); + printf("%csp %d ", TCDMP(8), ntoh16(ipv6->src_port)); + printf("%cdp %d ", TCDMP(16), ntoh16(ipv6->dst_port)); + printf("%cdscp 0x%x ", TCDMP(32), ipv6->dscp); + printf("%cprot %d", TCDMP(64), ipv6->nexthdr); + printf("%cfl %d", TCDMP(64), + ipv6->flow_lbl[2]<<16 | ipv6->flow_lbl[1]<<8 | ipv6->flow_lbl[0]); + printf(")\n"); + } else { + printf("(type unsupported)\n"); + } +} + +static int +wl_tclas_list_parse(wl_tclas_list_t *list) +{ + uint32 i; + uint8 *ptr = (uint8 *)&list->tclas[0]; + int retlen = 0; + + for (i = 0; i < list->num; i++) { + wl_tclas_t *tclas = (wl_tclas_t *)ptr; + + printf("tclas idx %d: ", i); + + wl_tclas_dump(tclas); + + retlen += WL_TCLAS_FIXED_SIZE + tclas->fc_len; + + /* Move to the next tclas frame classifier parameter */ + ptr += WL_TCLAS_FIXED_SIZE + tclas->fc_len; + } + + return retlen; +} + +static int +wl_tclas_list(void *wl, cmd_t *cmd, char **argv) +{ + int err; + wl_tclas_list_t *tclas_list = NULL; + void *ptr = NULL; + + if (*++argv) { + printf("Too much args provided\n"); + return BCME_ERROR; + } + + err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr); + if (err == BCME_OK) { + tclas_list = (wl_tclas_list_t *)ptr; + if (tclas_list->num == 0) + printf("No tclas frame classifier parameter entry\n"); + else + wl_tclas_list_parse(tclas_list); + } + + return err; +} + +#ifdef WLWNM +static int +wl_wnm_tfsreq_add(void *wl, cmd_t *cmd, char **argv) +{ + int argc; + int err = -1, buflen; + wl_tfs_req_t tfs_req; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + strcpy(buf, "wnm_tfsreq_add"); + buflen = strlen("wnm_tfsreq_add") + 1; + + if (argc != 5 || *++(argv) == NULL) { + printf("Incorrect args provided\n"); + return BCME_ERROR; + } + + tfs_req.tfs_id = (uint8)strtoul(*argv++, NULL, 0); + + if (*argv != NULL) + tfs_req.tfs_actcode = (uint8)strtoul(*argv++, NULL, 0); + else { + printf("Incorrect args provided\n"); + return BCME_ERROR; + } + + if (*argv != NULL) + tfs_req.tfs_subelem_id = (uint8)strtoul(*argv++, NULL, 0); + else { + printf("Incorrect args provided\n"); + return BCME_ERROR; + } + + if (*argv != NULL) + tfs_req.send = strtoul(*argv, NULL, 0) == 0 ? FALSE : TRUE; + else { + printf("Incorrect args provided\n"); + return BCME_ERROR; + } + + if (tfs_req.tfs_id == 0 || + tfs_req.tfs_actcode > 3 || + tfs_req.tfs_subelem_id > 1) { + printf("Input args not in range\n"); + return BCME_ERROR; + } + + buf[buflen++] = tfs_req.tfs_id; + buf[buflen++] = tfs_req.tfs_actcode; + buf[buflen++] = tfs_req.tfs_subelem_id; + buf[buflen++] = tfs_req.send; + + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + return err; +} + +static int +wl_wnm_dms_set(void *wl, cmd_t *cmd, char **argv) +{ + int err, buflen; + wl_dms_set_t *dms_set; + + UNUSED_PARAMETER(cmd); + + buflen = sprintf(buf, "%s", *argv) + 1; + dms_set = (wl_dms_set_t *) (buf + buflen); + dms_set->user_id = 0; + dms_set->tclas_proc = 0; + buflen += sizeof(wl_dms_set_t); + + if (*++(argv) == NULL) { + printf("Missing <send> argument\n"); + return BCME_ERROR; + } + dms_set->send = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv) == NULL) + goto set; + dms_set->user_id = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv) == NULL) + goto set; + dms_set->tclas_proc = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv)) { + printf("extra argument\n"); + return BCME_ERROR; + } +set: + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + return err; +} + +static int +wl_wnm_dms_status(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + wl_dms_status_t *dms_list = (wl_dms_status_t *)buf; + uint8 *p = (uint8 *)dms_list->desc; + + strcpy(buf, argv[0]); + + ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN); + if (ret < 0) + return ret; + + dms_list->cnt = dtoh32(dms_list->cnt); + + while (dms_list->cnt--) { + + wl_dms_desc_t *desc = (wl_dms_desc_t *)p; + + printf("DMS desc UserID %d:\n", desc->user_id); + printf("\tstatus:%d token:%d DMS ID:%d TCLAS proc:%d\n", + desc->status, desc->token, desc->dms_id, desc->tclas_proc); + + p += WL_DMS_DESC_FIXED_SIZE; + + if (desc->mac_len) { + printf("\tRegistered STA:\n"); + + while (desc->mac_len) { + printf("\t\t- %s\n", wl_ether_etoa((struct ether_addr*)p)); + p += ETHER_ADDR_LEN; + desc->mac_len -= ETHER_ADDR_LEN; + } + } + + printf("\tTCLAS:\n"); + while (desc->tclas_len) { + wl_tclas_t *tclas = (wl_tclas_t *)p; + + printf("\t\t- "); + wl_tclas_dump(tclas); + + p += WL_TCLAS_FIXED_SIZE + tclas->fc_len; + desc->tclas_len -= WL_TCLAS_FIXED_SIZE + tclas->fc_len; + } + } + + return 0; +} + +static int +wl_wnm_dms_term(void *wl, cmd_t *cmd, char **argv) +{ + int err, buflen; + wl_dms_term_t *dms_term; + + UNUSED_PARAMETER(cmd); + + buflen = sprintf(buf, "%s", *argv) + 1; + + dms_term = (wl_dms_term_t *) (buf + buflen); + dms_term->user_id = 0; + buflen += sizeof(wl_dms_term_t); + + if (*++(argv) == NULL) { + printf("Missing <del> argument\n"); + return BCME_ERROR; + } + dms_term->del = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv) == NULL) + goto set; + dms_term->user_id = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv)) { + printf("extra argument\n"); + return BCME_ERROR; + } +set: + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + return err; +} + +static int +wl_wnm_service_term(void *wl, cmd_t *cmd, char **argv) +{ + int err, buflen; + wl_service_term_t *term; + + UNUSED_PARAMETER(cmd); + + buflen = sprintf(buf, "%s", *argv) + 1; + + term = (wl_service_term_t *) (buf + buflen); + term->u.dms.user_id = 0; + buflen += sizeof(wl_service_term_t); + + if (*++(argv) == NULL) { + printf("Missing <service> argument\n"); + return BCME_ERROR; + } + term->service = (uint8) strtoul(*argv, NULL, 0); + + /* Need per service processing from here? */ + if (*++(argv) == NULL) { + printf("Missing <del> argument\n"); + return BCME_ERROR; + } + term->u.dms.del = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv) == NULL) + goto set; + term->u.dms.user_id = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv)) { + printf("extra argument\n"); + return BCME_ERROR; + } +set: + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + return err; +} + +static int +wl_wnm_timbc_offset(void *wl, cmd_t *cmd, char **argv) +{ + wl_timbc_offset_t *timbc_offset; + char *p = buf; + int size; + UNUSED_PARAMETER(cmd); + + size = sprintf(p, "%s", *argv++) + 1; + + if (*argv == NULL) { + /* retrieve bss idle period if argument count incorrect */ + int err = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN); + if (err < 0) + return err; + + timbc_offset = (wl_timbc_offset_t *)buf; + printf("TIMBC offset: %d, tsf_present: %d, fix_interval: %d, rate_override: %d\n", + timbc_offset->offset, timbc_offset->tsf_present, timbc_offset->fix_intv, + timbc_offset->rate_override); + + return BCME_OK; + + } else { + if (!isdigit((int)*argv[0])) + return BCME_ERROR; + + timbc_offset = (wl_timbc_offset_t *)(p + size); + + timbc_offset->offset = (int16)strtoul(*argv++, NULL, 0); + timbc_offset->tsf_present = TRUE; + timbc_offset->fix_intv = 0; + timbc_offset->rate_override = 0; + + if (*argv != NULL) { + timbc_offset->tsf_present = (bool)strtoul(*argv++, NULL, 0); + if (*argv != NULL) { + timbc_offset->fix_intv = (uint16)strtoul(*argv++, NULL, 0); + if (*argv != NULL) { + timbc_offset->rate_override = + (uint16)strtoul(*argv++, NULL, 0); + } + } + } + + return wlu_set(wl, WLC_SET_VAR, buf, size + sizeof(wl_timbc_offset_t)); + } +} + +static int +wl_wnm_timbc_set(void *wl, cmd_t *cmd, char **argv) +{ + int err, buflen; + wl_timbc_set_t *req; + + UNUSED_PARAMETER(cmd); + + buflen = sprintf(buf, "%s", *argv) + 1; + + req = (wl_timbc_set_t *) (buf + buflen); + req->flags = 0; + req->rate_min = 0; + req->rate_max = 0; + buflen += sizeof(wl_timbc_set_t); + + if (*++(argv) == NULL) { + printf("Missing <interval> argument\n"); + return BCME_ERROR; + } + req->interval = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv) == NULL) + goto set; + req->flags = (uint8) strtoul(*argv, NULL, 0); + + if (*++(argv) == NULL) + goto set; + req->rate_min = htod16(rate_string2int(*argv)); + + if (*++(argv) == NULL) + goto set; + req->rate_max = htod16(rate_string2int(*argv)); + + if (*++(argv)) { + printf("Too many arguments\n"); + return BCME_ERROR; + } +set: + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + return err; +} + +static int +wl_wnm_timbc_status(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + wl_timbc_status_t *status = (wl_timbc_status_t *)buf; + char hrate[16], lrate[16]; + + strcpy(buf, argv[0]); + + ret = wlu_get(wl, cmd->get, buf, WLC_IOCTL_MAXLEN); + if (ret < 0) + return ret; + + printf("TIM BC current status: %d status_ap: %d\n" + " interval: %d offset: %d\n" + " high rate: %s low rate: %s\n", + status->status_sta, + status->status_ap, + status->interval, status->offset, + rate_int2string(hrate, status->rate_high), + rate_int2string(lrate, status->rate_low)); + + return BCME_OK; +} + +static int +wl_wnm_maxidle(void *wl, cmd_t *cmd, char **argv) +{ + struct { + int period; + int protect; + } params = { 0, 0 }; + char *endptr; + + if (*++argv == NULL) { + /* retrieve bss idle period if argument count incorrect */ + int err = wlu_iovar_getint(wl, cmd->name, ¶ms.period); + if (err < 0) + return err; + + printf("BSS Max Idle Period: %d\n", dtoh32(params.period)); + return BCME_OK; + + } else { + /* parse the idle period */ + params.period = strtoul(*argv++, &endptr, 0); + htod32(params.period); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + + /* parse the optional keep-alive protect flag */ + if (*argv) { + params.protect = strtoul(*argv, &endptr, 0); + htod32(params.protect); + if (*endptr != '\0') + return BCME_USAGE_ERROR; + } + + return wlu_var_setbuf(wl, cmd->name, ¶ms, sizeof(params)); + } +} + +static int +wl_wnm_bsstrans_req(void *wl, cmd_t *cmd, char **argv) +{ + int err = -1; + wl_bsstrans_req_t bsstrans_req; + int buflen = sprintf(buf, "%s", *argv) + 1; + int tmp; + + UNUSED_PARAMETER(cmd); + + /* req mode parsing */ + if (*++argv == NULL) { + fprintf(stderr, "%s: error: reqmode missing\n", __FUNCTION__); + return BCME_ERROR; + } + bsstrans_req.reqmode = strtoul(*argv, NULL, 0); + + /* tbtt parsing */ + if (*++argv == NULL) { + fprintf(stderr, "%s: error: tbtt missing\n", __FUNCTION__); + return BCME_ERROR; + } + tmp = strtoul(*argv, NULL, 0); + if (tmp > 65535 || tmp < 0) { + fprintf(stderr, "%s: error: tbtt out of range(%d)\n", __FUNCTION__, tmp); + return BCME_ERROR; + } + else + bsstrans_req.tbtt = tmp; + + /* dur parsing */ + if (*++argv == NULL) { + fprintf(stderr, "%s: error: dur missing\n", __FUNCTION__); + return BCME_ERROR; + } + tmp = strtoul(*argv, NULL, 0); + if (tmp > 65535 || tmp < 0) { + fprintf(stderr, "%s: error: dur out of range(%d)\n", __FUNCTION__, tmp); + return BCME_ERROR; + } + else + bsstrans_req.dur = tmp; + + /* unicast/broadcast parsing */ + if (*++argv != NULL) + bsstrans_req.unicast = strtoul(*argv, NULL, 0); + else + bsstrans_req.unicast = 1; + + memcpy(&buf[buflen], &bsstrans_req, sizeof(bsstrans_req)); + buflen += sizeof(bsstrans_req); + + err = wlu_set(wl, WLC_SET_VAR, buf, buflen); + + return err; +} + +/* + * Get or Set wnm keepalive configuration + */ +static int +wl_wnm_keepalives_max_idle(void *wl, cmd_t *cmd, char **argv) +{ + int err, argc; + keepalives_max_idle_t keepalive; + + UNUSED_PARAMETER(cmd); + + argv++; + + if (*argv == NULL) { + /* get current params */ + if ((err = wlu_iovar_get(wl, cmd->name, (void *) &keepalive, + (sizeof(keepalive)))) < 0) + return (err); + + printf("Keepalives_max_idle parameters -\n"); + printf("num_of_keepalives_per_bss_max_idle\t\t= %d\nmkeep_alive_index\t= %d" + "\nmax_interval\t= %d\n", keepalive.keepalive_count, + keepalive.mkeepalive_index, keepalive.max_interval); + } else { + char *endptr; + /* Validate num of entries */ + for (argc = 0; argv[argc]; argc++); + if (argc < 2 || argc > 3) + return BCME_ERROR; + + keepalive.keepalive_count = strtol(argv[0], &endptr, 0); + keepalive.mkeepalive_index = strtol(argv[1], &endptr, 0); + if (argc == 3) + keepalive.max_interval = strtol(argv[2], &endptr, 0); + else + keepalive.max_interval = 0; + + /* Set params */ + err = wlu_iovar_set(wl, cmd->name, (void *) &keepalive, + (sizeof(keepalives_max_idle_t))); + } + + return err; +} + +#endif /* WLWNM */ + +static int +wl_tsf(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "tsf"; + struct tsf { + uint32 low; + uint32 high; + } tsf_buf; + char *endptr; + int err; + + UNUSED_PARAMETER(cmd); + + /* toss the command name */ + argv++; + + if (*argv == NULL) { + /* get */ + err = wlu_iovar_get(wl, cmdname, &tsf_buf, sizeof(tsf_buf)); + if (err) + return err; + printf("0x%08X 0x%08X\n", htod32(tsf_buf.high), htod32(tsf_buf.low)); + } else { + /* set */ + if (argv[1] == NULL) + return BCME_USAGE_ERROR; + + tsf_buf.high = (uint32)strtoul(*argv, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "%s: %s: error parsing \"%s\" as an integer\n", + wlu_av0, cmdname, *argv); + return BCME_USAGE_ERROR; + } + + argv++; + tsf_buf.low = (uint32)strtoul(*argv, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "%s: %s: error parsing \"%s\" as an integer\n", + wlu_av0, cmdname, *argv); + return BCME_USAGE_ERROR; + } + + tsf_buf.low = dtoh32(tsf_buf.low); + tsf_buf.high = dtoh32(tsf_buf.high); + + err = wlu_iovar_set(wl, cmdname, &tsf_buf, sizeof(tsf_buf)); + if (err) + return err; + } + + return err; +} + +static int +wl_mfp_config(void *wl, cmd_t *cmd, char **argv) +{ + int argc; + int err = 0; + int flag = 0; + const char *cmdname = "mfp"; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc > 1 && argv[1]) { + flag = htod32(atoi(argv[1])); + *(int *)buf = flag; + } + + err = wlu_iovar_set(wl, cmdname, buf, 256); + + return (err); + +} + +static int +wl_mfp_sha256(void *wl, cmd_t *cmd, char **argv) +{ + int argc; + int err = 0; + int flag = 0; + const char *cmdname = "mfp_sha256"; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc > 1 && argv[1]) { + flag = htod32(atoi(argv[1])); + *(int *)buf = flag; + err = wlu_iovar_set(wl, cmdname, buf, 256); + } else { + /* get */ + err = wlu_iovar_getint(wl, cmdname, &flag); + if (err == BCME_OK) + printf("%d\n", flag); + } + + return (err); + +} + +static int +wl_mfp_sa_query(void *wl, cmd_t *cmd, char **argv) +{ + wl_sa_query_t * query; + int argc; + int err = 0; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if ((query = (wl_sa_query_t *) malloc(sizeof(wl_sa_query_t))) == NULL) { + printf("unable to allocate frame \n"); + return BCME_NOMEM; + } + memset(query, 0, sizeof(wl_sa_query_t)); + + /* add the flag */ + if (argc > 1 && argv[1]) { + query->flag = htod32(atoi(argv[1])); + } + + /* add the action */ + if (argc > 2 && argv[2]) { + query->action = htod32(atoi(argv[2])); + } + + /* add the id */ + if (argc > 3 && argv[3]) { + query->id = htod32(atoi(argv[3])); + } + + err = wlu_var_setbuf(wl, "mfp_sa_query", query, sizeof(wl_sa_query_t)); + + free(query); + + return (err); + +} + +static int +wl_mfp_disassoc(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "mfp_disassoc"; + int argc; + int flag; + char varbuf[256]; + int err; + + UNUSED_PARAMETER(cmd); + memset(varbuf, 0, 256); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* add the action */ + if (argc > 1 && argv[1]) { + flag = htod32(atoi(argv[1])); + *(int *)varbuf = flag; + } + if (argc > 2 && argv[2]) { + flag = htod32(atoi(argv[2])); + *(int *)(varbuf + sizeof(flag)) = flag; + } + + err = wlu_iovar_set(wl, cmdname, varbuf, 256); + + return err; +} + +static int +wl_mfp_deauth(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "mfp_deauth"; + int argc; + int flag; + char varbuf[256]; + int err; + + UNUSED_PARAMETER(cmd); + + memset(varbuf, 0, 256); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* add the action */ + if (argc > 1 && argv[1]) { + flag = htod32(atoi(argv[1])); + *(int *)varbuf = flag; + } + if (argc > 2 && argv[2]) { + flag = htod32(atoi(argv[2])); + *(int *)(varbuf + sizeof(flag)) = flag; + } + + err = wlu_iovar_set(wl, cmdname, varbuf, 256); + + return err; +} + +static int +wl_mfp_assoc(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "mfp_assoc"; + int argc; + int flag; + char varbuf[256]; + int err; + + UNUSED_PARAMETER(cmd); + memset(varbuf, 0, 256); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* add the action */ + if (argc > 1 && argv[1]) { + flag = htod32(atoi(argv[1])); + *(int *)varbuf = flag; + } + if (argc > 2 && argv[2]) { + flag = htod32(atoi(argv[2])); + *(int *)(varbuf + sizeof(int)) = flag; + } + + err = wlu_iovar_set(wl, cmdname, varbuf, 256); + + return err; +} + +static int +wl_mfp_auth(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "mfp_auth"; + int argc; + int flag; + char varbuf[256]; + int err; + + UNUSED_PARAMETER(cmd); + memset(varbuf, 0, 256); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* add the action */ + if (argc > 1 && argv[1]) { + flag = htod32(atoi(argv[1])); + *(int *)varbuf = flag; + } + if (argc > 2 && argv[2]) { + flag = htod32(atoi(argv[2])); + *(int *)(varbuf + sizeof(int)) = flag; + } + + err = wlu_iovar_set(wl, cmdname, varbuf, 256); + + return err; +} + + +static int +wl_mfp_reassoc(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "mfp_reassoc"; + int argc; + int flag; + char varbuf[256]; + int err; + + UNUSED_PARAMETER(cmd); + memset(varbuf, 0, 256); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + /* add the action */ + if (argc > 1 && argv[1]) { + flag = htod32(atoi(argv[1])); + *(int *)varbuf = flag; + } + if (argc > 2 && argv[2]) { + flag = htod32(atoi(argv[2])); + *(int *)(varbuf + sizeof(int)) = flag; + } + + err = wlu_iovar_set(wl, cmdname, varbuf, 256); + + return err; +} + + +#ifdef EVENT_LOG_COMPILE +static int wl_event_log_set_init(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "event_log_set_init"; + wl_el_set_params_t pars; + int argc; + int err; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc != 3) { + return BCME_USAGE_ERROR; + } + + memset(&pars, sizeof(wl_el_set_params_t), 0); + pars.set = atoi(argv[1]); + pars.size = htod32(atoi(argv[2])); + + err = wlu_iovar_set(wl, cmdname, &pars, sizeof(wl_el_set_params_t)); + + return err; +} + +static int wl_event_log_set_expand(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "event_log_set_expand"; + wl_el_set_params_t pars; + int argc; + int err; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc != 3) { + return BCME_USAGE_ERROR; + } + + memset(&pars, sizeof(wl_el_set_params_t), 0); + pars.set = atoi(argv[1]); + pars.size = htod32(atoi(argv[2])); + + err = wlu_iovar_set(wl, cmdname, &pars, sizeof(wl_el_set_params_t)); + + return err; +} + +static int wl_event_log_set_shrink(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "event_log_set_shrink"; + wl_el_set_params_t pars; + int argc; + int err; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc != 2) { + return BCME_USAGE_ERROR; + } + + memset(&pars, sizeof(wl_el_set_params_t), 0); + pars.set = atoi(argv[1]); + + err = wlu_iovar_set(wl, cmdname, &pars, sizeof(wl_el_set_params_t)); + + return err; +} + +static int wl_event_log_tag_control(void *wl, cmd_t *cmd, char **argv) +{ + const char *cmdname = "event_log_tag_control"; + wl_el_tag_params_t pars; + int argc; + int err; + int flags = 0; + + UNUSED_PARAMETER(cmd); + + /* arg count */ + for (argc = 0; argv[argc]; argc++) + ; + + if (argc < 4) { + return BCME_USAGE_ERROR; + } + + argv++; + + memset(&pars, sizeof(wl_el_tag_params_t), 0); + pars.tag = htod16(atoi(*argv++)); + pars.set = atoi(*argv++); + + while (*argv) { + if (!strcmp(*argv, "LOG")) { + flags |= EVENT_LOG_TAG_FLAG_LOG; + } else if (!strcmp(*argv, "PRINT")) { + flags |= EVENT_LOG_TAG_FLAG_PRINT; + } else if (!strcmp(*argv, "NONE")) { + flags |= EVENT_LOG_TAG_FLAG_NONE; + } else { + return BCME_USAGE_ERROR; + } + argv++; + } + + pars.flags = flags; + + err = wlu_iovar_set(wl, cmdname, &pars, sizeof(wl_el_set_params_t)); + + return err; +} +#endif /* EVENT_LOG_COMPILE */ + + +static int +wl_spatial_policy(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr = NULL; + int err, i, *reply; + int mode[SPATIAL_MODE_MAX_IDX] = {-1, -1, -1, -1, -1}; + + /* Order is 2G, 5G-LOW, 5G-MID, 5G-HIGH, 5G-UPPER + * if only one argument given, than all band or sub-band take the + * same value + */ + if (!*++argv) { + bool all_same = TRUE; + if ((err = wlu_var_getbuf(wl, cmd->name, &mode, sizeof(mode), &ptr)) < 0) + return err; + reply = (int *)ptr; + for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++) { + /* check if return values for each band/sub-band is same or not */ + if (reply[i-1] != reply[i]) + all_same = FALSE; + } + if (all_same) + printf("%2d\n", reply[0]); + else { + printf("2.4GHz : %2d\n", reply[SPATIAL_MODE_2G_IDX]); + printf("5GHz (lower) : %2d\n", reply[SPATIAL_MODE_5G_LOW_IDX]); + printf("5GHz (middle): %2d\n", reply[SPATIAL_MODE_5G_MID_IDX]); + printf("5GHz (high) : %2d\n", reply[SPATIAL_MODE_5G_HIGH_IDX]); + printf("5GHz (upper) : %2d\n", reply[SPATIAL_MODE_5G_UPPER_IDX]); + } + return 0; + } + mode[0] = atoi(*argv); + if (!*++argv) { + for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++) + mode[i] = mode[0]; + } else { + for (i = 1; i < SPATIAL_MODE_MAX_IDX; i++) { + mode[i] = atoi(*argv); + if (!*++argv && i < (SPATIAL_MODE_MAX_IDX - 1)) { + printf("error: missing arguments\n"); + return BCME_USAGE_ERROR; + } + } + } + err = wlu_var_setbuf(wl, cmd->name, &mode, sizeof(mode)); + return err; +} + +static int +wl_ratetbl_ppr(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr = NULL; + int err, i, *reply; + int val[12]; + + /* Order is 2G, 5G-LOW, 5G-MID, 5G-HIGH, 5G-UPPER + * if only one argument given, than all band or sub-band take the + * same value + */ + memset(&val, 0, sizeof(val)); + if (!*++argv) { + if ((err = wlu_var_getbuf(wl, cmd->name, &val, sizeof(val), &ptr)) < 0) + return err; + reply = (int *)ptr; + for (i = 0; i < 12; i++) + printf("%s: %2d\n", (reply[i] & 0x80) ? "OFDM" : "CCK ", (reply[i] & 0x7f)); + return 0; + } + val[0] = atoi(*argv++); + val[1] = atoi(*argv++); + err = wlu_var_setbuf(wl, cmd->name, &val, sizeof(val)); + return err; +} + +static int +wlu_mempool(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + int ret; + int i; + wl_mempool_stats_t *stats; + bcm_mp_stats_t *mp_stats; + + + UNUSED_PARAMETER(argv); + + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr)) < 0) + return ret; + + stats = (wl_mempool_stats_t *) ptr; + mp_stats = stats->s; + + printf("%-8s %8s %8s %8s %8s %8s\n", "Name", "SZ", "Max", "Curr", "HiWater", "Failed"); + for (i = 0; i < stats->num; i++) { + printf("%-8s %8d %8d %8d %8d %8d\n", mp_stats->name, (int) mp_stats->objsz, + mp_stats->nobj, mp_stats->num_alloc, mp_stats->high_water, + mp_stats->failed_alloc); + + mp_stats++; + } + + return (0); +} + +static int +wl_ie(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + int err; + uchar *data; + int bsscfg_idx = 0; + int consumed = 0; + int iecount; + ie_setbuf_t *ie_setbuf; + ie_getbuf_t param; + uchar datalen, type, count, col; + + /* parse a bsscfg_idx option if present */ + if ((err = wl_cfg_option(argv + 1, argv[0], &bsscfg_idx, &consumed)) != 0) + return err; + if (consumed) + argv = argv + consumed; + else + bsscfg_idx = -1; + + if (!*++argv) { + fprintf(stderr, "missing parameter type\n"); + return BCME_USAGE_ERROR; + } + /* get IE type */ + type = (uchar)atoi(argv[0]); + + if (!*++argv) { + param.id = type; + ptr = buf; + if (bsscfg_idx == -1) + err = wlu_var_getbuf(wl, cmd->name, ¶m, sizeof(param), &ptr); + else + err = wl_bssiovar_getbuf(wl, cmd->name, bsscfg_idx, ¶m, sizeof(param), + buf, WLC_IOCTL_MAXLEN); + if (err == 0) { + data = (uchar *)ptr; + datalen = data[1]+2; + printf("%s len %d\n", cmd->name, datalen); + printf("%s Data:\n", cmd->name); + for (count = 0; (count < datalen);) { + for (col = 0; (col < MAX_DATA_COLS) && + (count < datalen); col++, count++) { + printf("%02x", *data++); + } + printf("\n"); + } + } + else { + fprintf(stderr, "Error %d getting IOVar\n", err); + } + return err; + } + + /* get IE length */ + datalen = (uchar)atoi(argv[0]); + + if (datalen > 0) { + if (!argv[1]) { + fprintf(stderr, "Data bytes should be specified for IE of length %d\n", + datalen); + return BCME_USAGE_ERROR; + } + else { + /* Ensure each data byte is 2 characters long */ + if ((int)strlen (argv[1]) < (datalen * 2)) { + fprintf(stderr, "Please specify all the data bytes for this IE\n"); + return BCME_BADARG; + } + } + } + + if ((datalen == 0) && (argv[1] != NULL)) + fprintf(stderr, "Ignoring data bytes for IE of length %d\n", datalen); + + count = sizeof(ie_setbuf_t) + datalen - 1; + data = malloc(count); + if (data == NULL) { + fprintf(stderr, "memory alloc failure\n"); + return BCME_NOMEM; + } + + ie_setbuf = (ie_setbuf_t *) data; + /* Copy the ie SET command ("add") to the buffer */ + strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); + ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); + + /* Now, add the IE to the buffer */ + ie_setbuf->ie_buffer.ie_list[0].ie_data.id = type; + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = datalen; + + if (datalen > 0) { + if ((err = get_ie_data ((uchar *)argv[1], + (uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], + datalen))) { + free(data); + fprintf(stderr, "Error parsing data arg\n"); + return err; + } + } + + if (bsscfg_idx == -1) + err = wlu_var_setbuf(wl, cmd->name, data, count); + else + err = wlu_bssiovar_setbuf(wl, cmd->name, bsscfg_idx, + data, count, buf, WLC_IOCTL_MAXLEN); + + free(data); + return (err); +} + +static int +wl_wnm_url(void *wl, cmd_t *cmd, char **argv) +{ + void *ptr; + int err; + uchar *data; + uchar datalen, count; + wnm_url_t *url; + + if (!*++argv) { + err = wlu_var_getbuf(wl, cmd->name, NULL, 0, &ptr); + if (err == 0) { + data = (uchar *)ptr; + datalen = data[0]; + data ++; + *(data + datalen) = '\0'; + printf("%s URL len %d\n", cmd->name, datalen); + printf("%s URL: %s\n", cmd->name, data); + } + else { + fprintf(stderr, "Error %d getting IOVar\n", err); + } + return err; + } + + /* get URL length */ + datalen = (uchar)atoi(argv[0]); + + if (datalen > 0) { + if (!argv[1]) { + fprintf(stderr, "URL string should be specified for URL length %d\n", + datalen); + return BCME_BADARG; + } + else { + if ((int)strlen (argv[1]) != datalen) { + fprintf(stderr, "length is not matching to string\n"); + return BCME_BADARG; + } + } + } + + if ((datalen == 0) && (argv[1] != NULL)) + fprintf(stderr, "Ignoring data bytes for length %d\n", datalen); + + count = sizeof(wnm_url_t) + datalen - 1; + data = malloc(count); + if (data == NULL) { + fprintf(stderr, "memory alloc failure\n"); + return BCME_NOMEM; + } + + url = (wnm_url_t *) data; + url->len = datalen; + if (datalen > 0) { + memcpy(url->data, argv[1], datalen); + } + + err = wlu_var_setbuf(wl, cmd->name, data, count); + + free(data); + return (err); +} + +/* Restore the ignored warnings status */ + + +static int +wl_sleep_ret_ext(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int argc, i; + uint32 val; + char *endptr = NULL; + wl_pm2_sleep_ret_ext_t sleep_ret_ext; + wl_pm2_sleep_ret_ext_t* sleep_ret_ext_ptr; + + /* Skip the command name */ + UNUSED_PARAMETER(cmd); + argv++; + + /* If no arguments are given, print the existing settings */ + argc = ARGCNT(argv); + if (argc == 0) { + char *logic_str; + + /* Get and print the values */ + if ((ret = wlu_var_getbuf_med(wl, cmd->name, NULL, 0, (void*) &sleep_ret_ext_ptr))) + return ret; + + if (sleep_ret_ext_ptr->logic == WL_DFRTS_LOGIC_OFF) + logic_str = "DISABLED"; + else if (sleep_ret_ext_ptr->logic == WL_DFRTS_LOGIC_OR) + logic_str = "OR"; + else if (sleep_ret_ext_ptr->logic == WL_DFRTS_LOGIC_AND) + logic_str = "AND"; + else + logic_str = "ERROR"; + + printf("logic: %d (%s)\n", + sleep_ret_ext_ptr->logic, logic_str); + if (sleep_ret_ext_ptr->logic != WL_DFRTS_LOGIC_OFF) { + printf("low_ms: %d\n", sleep_ret_ext_ptr->low_ms); + printf("high_ms: %d\n", sleep_ret_ext_ptr->high_ms); + printf("rx_pkts_threshold: %d\n", + sleep_ret_ext_ptr->rx_pkts_threshold); + printf("tx_pkts_threshold: %d\n", + sleep_ret_ext_ptr->tx_pkts_threshold); + printf("txrx_pkts_threshold: %d\n", + sleep_ret_ext_ptr->txrx_pkts_threshold); + printf("rx_bytes_threshold: %d\n", + sleep_ret_ext_ptr->rx_bytes_threshold); + printf("tx_bytes_threshold: %d\n", + sleep_ret_ext_ptr->tx_bytes_threshold); + printf("txrx_bytes_threshold: %d\n", + sleep_ret_ext_ptr->txrx_bytes_threshold); + } + return 0; + } + + memset(&sleep_ret_ext, 0, sizeof(wl_pm2_sleep_ret_ext_t)); + i = 0; + + /* Get the first 'logic' argument. */ + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + if (val != WL_DFRTS_LOGIC_OFF && val != WL_DFRTS_LOGIC_OR && + val != WL_DFRTS_LOGIC_AND) { + printf("Invalid logic value %u\n", val); + goto usage; + } + sleep_ret_ext.logic = val; + ++i; + + /* If logic is 0 (disable) then no more arguments are needed */ + if (sleep_ret_ext.logic == 0) + goto set; + + if (argc < 9) + goto usage; + + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + sleep_ret_ext.low_ms = val; + ++i; + + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + sleep_ret_ext.high_ms = val; + ++i; + + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + sleep_ret_ext.rx_pkts_threshold = val; + ++i; + + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + sleep_ret_ext.tx_pkts_threshold = val; + ++i; + + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + sleep_ret_ext.txrx_pkts_threshold = val; + ++i; + + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + sleep_ret_ext.rx_bytes_threshold = val; + ++i; + + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + sleep_ret_ext.tx_bytes_threshold = val; + ++i; + + val = strtoul(argv[i], &endptr, 0); + if (*endptr != '\0') + goto usage; + sleep_ret_ext.txrx_bytes_threshold = val; + ++i; + + if (i != argc) + goto usage; + +set: + return wlu_var_setbuf(wl, cmd->name, &sleep_ret_ext, + sizeof(wl_pm2_sleep_ret_ext_t)); + +usage: + printf("Usage: %s [logic] [<low_ms> <high_ms>" + " <rxP> <txP> <txrxP> <rxB> <txB> <txrxB>\n", wlu_av0); + printf("Parameters:\n"); + printf("logic : 0=disable, 1=OR, 2=AND all non-zero switching thresholds.\n"); + printf("low_ms : Low pm2_sleep_ret value.\n"); + printf("high_ms : High pm2_sleep_ret value.\n"); + printf("rxP : Switching threshold in # of rx packets.\n"); + printf(" eg. Switch from the low to high FRTS value if rxP or\n"); + printf(" more packets are received in a PM2 radio wake period.\n"); + printf(" 0 means ignore this threshold.\n"); + printf("txP : Switching threshold in # of tx packets.\n"); + printf("txrxP : Switching threshold in # of combined tx+rx packets.\n"); + printf("rxB : Switching threshold in # of rx bytes.\n"); + printf("txB : Switching threshold in # of tx bytes.\n"); + printf("txrxB : Switching threshold in # of combined tx+rx bytes.\n"); + return -1; +} + +static int wl_stamon_sta_config(void *wl, cmd_t *cmd, char **argv) +{ + int err = 0; + wlc_stamon_sta_config_t stamon_cfg; + + memset(&stamon_cfg, 0, sizeof(wlc_stamon_sta_config_t)); + if (!*++argv) { + err = wlu_iovar_get(wl, cmd->name, &stamon_cfg, + sizeof(wlc_stamon_sta_config_t)); + if (!err) + printf("%s \n", wl_ether_etoa(&stamon_cfg.ea)); + } else { + if (!stricmp(*argv, "add")) + stamon_cfg.cmd = STAMON_CFG_CMD_ADD; + else if (!stricmp(*argv, "del")) + stamon_cfg.cmd = STAMON_CFG_CMD_DEL; + else { + printf("error: unknown operation option%s\n", *argv); + err = -1; + } + + if (!err) { + argv++; + if (!*argv || !wl_ether_atoe(*argv, &stamon_cfg.ea)) { + printf(" ERROR: no valid ether addr provided\n"); + err = -1; + } else { + err = wlu_iovar_set(wl, cmd->name, + &stamon_cfg, sizeof(wlc_stamon_sta_config_t)); + } + } + } + + return err; +} + +static monitor_promisc_level_msg_t wl_monpromisc_level_msgs[] = { + {WL_MONPROMISC_PROMISC, "promisc"}, + {WL_MONPROMISC_CTRL, "ctrl"}, + {WL_MONPROMISC_FCS, "fcs"}, + {0, NULL} +}; + +static int +wl_monitor_promisc_level(void *wl, cmd_t *cmd, char **argv) +{ + int ret, i; + uint val = 0, last_val = 0; + uint promiscbitmap = 0, promiscbitmap_add = 0, promiscbitmap_del = 0; + char *endptr; + const char *cmdname = "monitor_promisc_level"; + + UNUSED_PARAMETER(cmd); + if ((ret = wlu_iovar_getint(wl, cmdname, (int *)&promiscbitmap) < 0)) { + return ret; + } + promiscbitmap = dtoh32(promiscbitmap); + if (!*++argv) { + printf("0x%x ", promiscbitmap); + for (i = 0; (val = wl_monpromisc_level_msgs[i].value); i++) { + if ((promiscbitmap & val) && (val != last_val)) + printf(" %s", wl_monpromisc_level_msgs[i].string); + last_val = val; + } + printf("\n"); + return (0); + } + while (*argv) { + char *s = *argv; + if (*s == '+' || *s == '-') + s++; + else + promiscbitmap_del = ~0; /* make the whole list absolute */ + val = strtoul(s, &endptr, 0); + if (val == 0xFFFFFFFF) { + fprintf(stderr, + "Bits >32 are not supported on this driver version\n"); + val = 1; + } + /* not an integer if not all the string was parsed by strtoul */ + if (*endptr != '\0') { + for (i = 0; (val = wl_monpromisc_level_msgs[i].value); i++) + if (stricmp(wl_monpromisc_level_msgs[i].string, s) == 0) + break; + if (!val) + goto usage; + } + if (**argv == '-') + promiscbitmap_del |= val; + else + promiscbitmap_add |= val; + ++argv; + } + promiscbitmap &= ~promiscbitmap_del; + promiscbitmap |= promiscbitmap_add; + promiscbitmap = htod32(promiscbitmap); + return (wlu_iovar_setint(wl, cmdname, (int)promiscbitmap)); + +usage: + fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n"); + fprintf(stderr, "Use a + or - prefix to make an incremental change."); + for (i = 0; (val = wl_monpromisc_level_msgs[i].value); i++) { + if (val != last_val) + fprintf(stderr, "\n0x%04x %s", val, wl_monpromisc_level_msgs[i].string); + else + fprintf(stderr, ", %s", wl_monpromisc_level_msgs[i].string); + last_val = val; + } + fprintf(stderr, "\n"); + return 0; +} + +#if defined(DWDS) +static int +wl_dwds_config(void *wl, cmd_t *cmd, char **argv) +{ + wlc_dwds_config_t dwds; + int err; + + memset(&dwds, 0, sizeof(wlc_dwds_config_t)); + + if (!*++argv) { + printf("error: missing arguments\n"); + return -1; + } + + if (!stricmp(*argv, "enable")) + dwds.enable = 1; + else if (!stricmp(*argv, "disable")) + dwds.enable = 0; + else { + printf("error: unknown mode option %s\n", *argv); + return -1; + } + argv++; + /* look for sta/dwds */ + if (!stricmp(*argv, "sta")) + dwds.mode = 1; + else if (!stricmp(*argv, "ap")) + dwds.mode = 0; + else { + printf("error: unknown mode option %s\n", *argv); + return -1; + } + + argv++; + /* convert the ea string into an ea struct */ + if (!*argv || !wl_ether_atoe(*argv, &dwds.ea)) { + printf(" ERROR: no valid ether addr provided\n"); + return -1; + } + + if ((err = wlu_iovar_set(wl, cmd->name, &dwds, sizeof(wlc_dwds_config_t))) < 0) + return err; + + return (0); + +} +#endif /* DWDS */ + +static int +wl_bss_peer_info(void *wl, cmd_t *cmd, char **argv) +{ + bss_peer_list_info_t *info; + bss_peer_info_t *peer_info; + bss_peer_info_param_t param; + int err, i; + void *ptr; + + memset(¶m, 0, sizeof(bss_peer_info_param_t)); + param.version = htod16(BSS_PEER_INFO_PARAM_CUR_VER); + + if (*++argv) { + if (!wl_ether_atoe(*argv, ¶m.ea)) { + printf(" ERROR: no valid ether addr provided\n"); + return -1; + } + } + + if ((err = wlu_var_getbuf_med(wl, cmd->name, ¶m, sizeof(bss_peer_info_param_t), + &ptr)) < 0) + return err; + + info = (bss_peer_list_info_t*)ptr; + + if ((dtoh16(info->version) != BSS_PEER_LIST_INFO_CUR_VER) || + (dtoh16(info->bss_peer_info_len) != sizeof(bss_peer_info_t))) { + printf("BSS peer info version/structure size mismatch driver %d firmware %d \r\n", + BSS_PEER_LIST_INFO_CUR_VER, dtoh16(info->version)); + return -1; + } + + if (WLC_IOCTL_MEDLEN < (BSS_PEER_LIST_INFO_FIXED_LEN + + (dtoh32(info->count) * sizeof(bss_peer_info_t)))) { + printf("ERROR : peer list received exceed the buffer size\r\n"); + } + + for (i = 0; i < (int)dtoh32(info->count); i++) { + peer_info = &info->peer_info[i]; + peer_info->rateset.count = dtoh32(peer_info->rateset.count); + printf("PEER%d: MAC: %s: RSSI %d TxRate %d kbps RxRate %d kbps age : %ds\r\n", + i, wl_ether_etoa(&peer_info->ea), peer_info->rssi, + dtoh32(peer_info->tx_rate), dtoh32(peer_info->rx_rate), + dtoh32(peer_info->age)); + printf("\t rateset "); + dump_rateset(peer_info->rateset.rates, peer_info->rateset.count); + printf("\r\n"); + } + + return 0; +} + +static int +wl_aibss_txfail_config(void *wl, cmd_t *cmd, char **argv) +{ + int ret = USAGE_ERROR; + aibss_txfail_config_t txfail_config; + + if (!*++argv) { + /* Get */ + memset(&txfail_config, 0, sizeof(txfail_config)); + /* get current rateset */ + if ((ret = wlu_iovar_get(wl, cmd->name, &txfail_config, + sizeof(txfail_config))) < 0) + goto error; + + printf("AIBSS TXFAIL config beacon timeout duration: %d \r\n" + "Max consecutive Tx failure before TXFAIL event:%d \r\n", + txfail_config.bcn_timeout, txfail_config.max_tx_retry); + } + else { + char *p = argv[0]; + char *endptr = NULL; + + /* Extract the content */ + if (!p || *p == '\0') + goto error; + + txfail_config.bcn_timeout = strtoul(p, &endptr, 0); + + p = endptr; + /* check and skip , */ + if (*p == '\0' || *++p == '\0') + goto error; + + txfail_config.max_tx_retry = strtoul(p, &endptr, 0); + + + if (*endptr != '\0') + goto error; + txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0; + txfail_config.len = sizeof(txfail_config); + ret = wlu_iovar_set(wl, cmd->name, (void *) &txfail_config, + sizeof(txfail_config)); + } + +error: + return ret; +} + +static int +wl_bssload_static(void *wl, cmd_t *cmd, char **argv) +{ + int err = -1; + wl_bssload_static_t bssload; + + UNUSED_PARAMETER(cmd); + + /* get */ + if (!argv[1]) { + if ((err = wlu_iovar_get(wl, cmd->name, &bssload, sizeof(bssload))) < 0) + return err; + if (bssload.is_static) { + printf("station count: %d\n", dtoh16(bssload.sta_count)); + printf("channel utilization: %d\n", bssload.chan_util); + printf("avail admission capacity: %d\n", dtoh16(bssload.aac)); + } + } + else { + /* set */ + argv++; + memset(&bssload, 0, sizeof(bssload)); + if (!stricmp(*argv, "off")) { + bssload.is_static = FALSE; + } + else { + bssload.sta_count = htod16(strtoul(*argv, NULL, 0)); + + if (*++argv == NULL) { + printf("wl_bssload_static: " + "channel utilization not provided\n"); + return -1; + } + bssload.chan_util = strtoul(*argv, NULL, 0); + + if (*++argv == NULL) { + printf("wl_bssload_static: " + "avail admission capacity not provided\n"); + return -1; + } + bssload.aac = htod16(strtoul(*argv, NULL, 0)); + + bssload.is_static = TRUE; + } + + err = wlu_iovar_set(wl, cmd->name, &bssload, sizeof(bssload)); + } + + return err; +} + +#ifdef TBTT_OFFSET_STAT +static int +wl_tbtt_offset_stat(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + tbtt_offset_stat_t *tbtt_offset_stat = NULL; + + UNUSED_PARAMETER(argv); + + /* Get only */ + if ((ret = wlu_var_getbuf(wl, cmd->name, NULL, 0, (void **)(&tbtt_offset_stat))) < 0) + return (ret); + + printf("avg: %d\nmin: %d\nmax: %d\n", + dtoh32(tbtt_offset_stat->tbtt_offset_avg), + dtoh32(tbtt_offset_stat->tbtt_offset_min), + dtoh32(tbtt_offset_stat->tbtt_offset_max)); + + return 0; +} +#endif /* TBTT_OFFSET_STAT */ + +#ifdef WIN32 +#pragma warning(pop) +#endif
diff --git a/src/wl/exe/wlu.h b/src/wl/exe/wlu.h new file mode 100644 index 0000000..5fde76d --- /dev/null +++ b/src/wl/exe/wlu.h
@@ -0,0 +1,115 @@ +/* + * Common code for wl command line utility + * + * Copyright 2002, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied or + * duplicated in any form, in whole or in part, without the prior written + * permission of Broadcom Corporation. + * + * $Id: wlu.h 432727 2013-10-29 12:39:22Z $ + */ + +#ifndef _wlu_h_ +#define _wlu_h_ + +#include "wlu_cmd.h" + +extern const char *wlu_av0; +extern int g_wlc_idx; + +/* parse common option */ +extern int wl_option(char ***pargv, char **pifname, int *phelp); +extern void wl_cmd_init(void); +extern void wlu_init(void); + +/* print usage */ +extern void wl_cmd_usage(FILE *fid, cmd_t *cmd); +extern void wl_usage(FILE *fid, cmd_t *port_cmds); +extern void wl_cmds_usage(FILE *fid, cmd_t *port_cmds); + +/* print helpers */ +extern void wl_printlasterror(void *wl); +extern void wl_printint(int val); + +/* pretty print an SSID */ +extern int wl_format_ssid(char* buf, uint8* ssid, int ssid_len); + +/* pretty hex print a contiguous buffer */ +extern void wl_hexdump(uchar *buf, uint nbytes); + +/* check driver version */ +extern int wl_check(void *wl); + +/* wl functions used by the ndis wl. */ +extern void dump_rateset(uint8 *rates, uint count); +extern uint freq2channel(uint freq); +extern int wl_ether_atoe(const char *a, struct ether_addr *n); +extern char *wl_ether_etoa(const struct ether_addr *n); +struct ipv4_addr; /* forward declaration */ +extern int wl_atoip(const char *a, struct ipv4_addr *n); +extern char *wl_iptoa(const struct ipv4_addr *n); +extern cmd_func_t wl_int; +extern cmd_func_t wl_varint; +extern void wl_dump_raw_ie(bcm_tlv_t *ie, uint len); +extern int wl_mk_ie_setbuf(const char *command, uint32 pktflag_ok, char **argv, + vndr_ie_setbuf_t **buf, int *buf_len); +extern cmd_func_t wl_list_ie; + +extern void wl_printlasterror(void *wl); +extern bool wc_cmd_check(const char *cmd); + + +/* functions for downloading firmware to a device via serial or other transport */ + +#ifdef BCMDLL +#ifdef LOCAL +extern FILE *dll_fd; +#else +extern void * dll_fd_out; +extern void * dll_fd_in; +#endif +#undef printf +#undef fprintf +#define printf printf_to_fprintf /* printf to stdout */ +#define fprintf fprintf_to_fprintf /* fprintf to stderr */ +extern void fprintf_to_fprintf(FILE * stderror, const char *fmt, ...); +extern void printf_to_fprintf(const char *fmt, ...); +extern void raw_puts(const char *buf, void *dll_fd_out); +#define fputs(buf, stdout) raw_puts(buf, dll_fd_out) +#endif /* BCMDLL */ + +#define RAM_SIZE_4325 0x60000 +#define RAM_SIZE_4329 0x48000 +#define RAM_SIZE_43291 0x60000 +#define RAM_SIZE_4330_a1 0x3c000 +#define RAM_SIZE_4330_b0 0x48000 + +/* useful macros */ +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) +#endif /* ARRAYSIZE */ + +/* buffer length needed for wl_format_ssid + * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL + */ +#define SSID_FMT_BUF_LEN (4*32+1) /* Length for SSID format string */ + +#define USAGE_ERROR -1 /* Error code for Usage */ +#define CMD_DEPRECATED -4 /* Commands that are functionally deprecated or don't provide + * a useful value to a specific OS port of wl + */ + +/* integer output format */ +#define INT_FMT_DEC 0 /* signed integer */ +#define INT_FMT_UINT 1 /* unsigned integer */ +#define INT_FMT_HEX 2 /* hexdecimal */ + +/* command line argument usage */ +#define CMD_ERR -1 /* Error for command */ +#define CMD_OPT 0 /* a command line option */ +#define CMD_WL 1 /* the start of a wl command */ + +#endif /* _wlu_h_ */
diff --git a/src/wl/exe/wlu_client_shared.c b/src/wl/exe/wlu_client_shared.c new file mode 100644 index 0000000..1ad7950 --- /dev/null +++ b/src/wl/exe/wlu_client_shared.c
@@ -0,0 +1,1220 @@ +/* + * Common code for remotewl client + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_client_shared.c 430139 2013-10-17 11:15:17Z $ + */ +#ifdef WIN32 +#define NEED_IR_TYPES + +#include <winsock2.h> +#include <windows.h> +#include <ntddndis.h> +#include <epictrl.h> +#include <irelay.h> +#include <winioctl.h> +#include <nuiouser.h> +#else /* LINUX */ +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <net/if.h> +#include <unistd.h> +#endif /* WIN32 */ +#include <stdio.h> +#include <stdlib.h> +#include <malloc.h> +#include <assert.h> +#include <ctype.h> +#include <string.h> +#include <typedefs.h> +#include <wlioctl.h> +#include <proto/ethernet.h> +#include <bcmendian.h> +#include <bcmutils.h> +#include <bcmcdc.h> +#include <proto/802.11.h> +#include <signal.h> +#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR) +#include <rwl_wifi.h> +#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */ +#include "wlu.h" +#include "wlu_remote.h" +#include "wlu_pipe.h" +#include "wlu_client_shared.h" + +char* remote_vista_cmds[] = {"join", "sup_wpa", "wsec", "set_pmk", "legacylink", "list", + "disassoc", "xlist", NULL}; +int vista_cmd_index; +#define SHELL_CMD_LEN (256) + +#ifdef RWL_SOCKET +extern int validate_server_address(); +static int rwl_socket_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf); +#endif +static int rwl_dongle_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf, int cmd); +#ifdef RWL_WIFI +static int rwl_wifi_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf); +#endif +/* We don't want the server to allocate bigger buffers for some of the commands + * like scanresults. Server can still allocate 8K memory and send the response + * in fragments. This is used in case of Get commands only. + */ +#define SERVER_RESPONSE_MAX_BUF_LEN 8192 + +extern unsigned short g_rwl_servport; +extern char *g_rwl_servIP; +int g_child_pid; +#ifdef RWL_WIFI +/* dword align allocation */ +static union { + char bufdata[WLC_IOCTL_MAXLEN]; + uint32 alignme; +} bufstruct_wlu; +static char *g_rwl_aligned_buf = (char*) &bufstruct_wlu.bufdata; + +extern char *g_rwl_buf_mac; +#endif +#ifdef RWL_SOCKET +/* Make initial connection from client to server through sockets */ +static int +rwl_connect_socket_server(void) +{ + int SockDes = -1; + struct sockaddr_in servAddr; + memset(&servAddr, 0, sizeof(servAddr)); + if ((SockDes = (*(int *)rwl_open_pipe(remote_type, "\0", 0, 0))) == FAIL) + return FAIL; + if (!validate_server_address()) + return FAIL; + DPRINT_DBG(OUTPUT, "ServerIP:%s,ServerPort:%d\n", g_rwl_servIP, g_rwl_servport); + servAddr.sin_family = AF_INET; + servAddr.sin_port = hton16(g_rwl_servport); + servAddr.sin_addr.s_addr = inet_addr(g_rwl_servIP); + + if (rwl_sockconnect(SockDes, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) { + rwl_close_pipe(remote_type, (void*) &SockDes); + return FAIL; + } + return SockDes; +} + +/* This routine is used for both Get and Set Ioctls for the socket */ +static int +rwl_information_socket(void *wl, int cmd, void* input_buf, unsigned long *input_len, + unsigned long *tx_len, uint flags) +{ + int error, Sockfd; + rem_ioctl_t *rem_ptr = NULL; + + if ((Sockfd = rwl_connect_socket_server()) < 0) { + DPRINT_ERR(ERR, "Error in getting the Socket Descriptor\n"); + return FAIL; + } + wl = (void *)(&Sockfd); + + if (remote_CDC_tx(wl, cmd, input_buf, *input_len, + *tx_len, flags, 0) < 0) { + DPRINT_ERR(ERR, "query_info_fe: Send command failed\n"); + rwl_close_pipe(remote_type, wl); + return FAIL; + } + + if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) { + DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed\n"); + rwl_close_pipe(remote_type, wl); + return FAIL; + } + rwl_swap_header(rem_ptr, NETWORK_TO_HOST); + + if (rem_ptr->msg.len > *input_len) { + DPRINT_ERR(ERR, "query_info_fe: needed size(%d) > " + "actual size(%ld)\n", rem_ptr->msg.len, *input_len); + rwl_close_pipe(remote_type, wl); + return FAIL; + } + + if (remote_CDC_rx(wl, rem_ptr, input_buf, *input_len, 0) == FAIL) { + DPRINT_ERR(ERR, "query_info_fe: No results!\n"); + rwl_close_pipe(remote_type, wl); + return FAIL; + } + + if (rem_ptr->msg.flags & REMOTE_REPLY) + error = rem_ptr->msg.cmd; + else + error = 0; + + rwl_close_pipe(remote_type, wl); + + return error; +} +#endif /* RWL_SOCKET */ +/* + * Receives the fragmented response from serial server. + * Called from rwl_queryinformation_fe front end function for dongle case only when + * the client expects data in chunks more than DATA_FRAME_LEN * (960) bytes. + */ +static int +rwl_serial_fragmented_response_fe(void *wl, rem_ioctl_t *rem_ptr, void* input_buf, +unsigned long *bytes_to_read) +{ + int error; + uint32 total_numread; + uchar *local_buf, *local_result; + uint frames_to_read, frame_count; + + DPRINT_DBG(OUTPUT, "rem_ptr->msg.len=%d \t rem_ptr->data_len=%d\n", + rem_ptr->msg.len, rem_ptr->data_len); + + /* Calculate the number of frames for the response */ + if (rem_ptr->data_len == 0) { + DPRINT_ERR(ERR, "data_len is:%d\n", rem_ptr->data_len); + return (FAIL); + } + frames_to_read = (*bytes_to_read)/rem_ptr->data_len; + if ((*bytes_to_read) % rem_ptr->data_len > 0) + frames_to_read += 1; + + DPRINT_DBG(OUTPUT, "No of frames=%d\n", frames_to_read); + + if ((local_result = (uchar*)malloc(rem_ptr->msg.len)) == NULL) { + DPRINT_ERR(ERR, "Malloc failed for serial fragmented frame" + "local result \n"); + return FAIL; + } + + /* Response will come in DATA_FRAME_LEN + REMOTE_SIZE (960+16) bytes + * packet with CDC header and then followed by response. + */ + total_numread = 0; + frame_count = 0; + while (total_numread != *bytes_to_read) { + local_buf = (uchar*)malloc(rem_ptr->data_len); + if (local_buf == NULL) { + free(local_result); + return FAIL; + } + + DPRINT_DBG(OUTPUT, "Total bytes=%d\n", total_numread); + DPRINT_DBG(OUTPUT, "Frame (Reverse):%d\n", frames_to_read); + + if (remote_CDC_rx(wl, rem_ptr, local_buf, rem_ptr->data_len, 0) == -1) { + free(local_buf); + free(local_result); + return FAIL; + } + + /* Concatenate the response to loc_res. */ + memcpy(&local_result[frame_count*DATA_FRAME_LEN], local_buf, + rem_ptr->data_len); + + total_numread += rem_ptr->data_len; + frame_count++; + frames_to_read--; + + DPRINT_DBG(OUTPUT, "Total bytes=%d\n", total_numread); + + if (frames_to_read == 0) { + /* When all the frames are received copy the data to original buf */ + memcpy(input_buf, local_result, total_numread); + if (rem_ptr->msg.flags & REMOTE_REPLY) { + error = rem_ptr->msg.cmd; + } + } + + if (total_numread != *bytes_to_read) { + /* Receive the next header */ + if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) { + DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed"); + } + } + free(local_buf); + } + free(local_result); + return error; +} + +/* This routine is common to both set and Get Ioctls for the dongle case */ +static int +rwl_information_dongle(void *wl, int cmd, void* input_buf, unsigned long *input_len, + uint tx_len, uint flags) +{ + int error; + rem_ioctl_t *rem_ptr = NULL; + + if (remote_CDC_tx(wl, cmd, input_buf, *input_len, + tx_len, flags, 0) < 0) { + DPRINT_ERR(ERR, "query_info_fe: Send command failed\n"); + return FAIL; + } + + /* Get the header */ + if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) { + DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed\n"); + return BCME_SERIAL_PORT_ERR; + } + + /* Make sure there is enough room */ + if (rem_ptr->msg.len > *input_len) { + DPRINT_DBG(OUTPUT, "query_info_fe: needed size(%d) > actual" + "size(%ld)\n", rem_ptr->msg.len, *input_len); + return FAIL; + } + + /* We can grab short frames all at once. Longer frames (> 960 bytes) + * come in fragments. + */ + if (rem_ptr->data_len < DATA_FRAME_LEN) { + if (remote_CDC_rx(wl, rem_ptr, input_buf, *input_len, 0) == FAIL) { + DPRINT_ERR(ERR, "query_info_fe: No results!\n"); + return FAIL; + } + if (rem_ptr->msg.flags & REMOTE_REPLY) + error = rem_ptr->msg.cmd; + else + error = 0; + } else { + /* rwl_serial_fragmented_response_fe returns either valid number or FAIL. + * In any case return the same value to caller + */ + error = rwl_serial_fragmented_response_fe(wl, rem_ptr, input_buf, input_len); + } + return error; +} +/* Handler to signal the reader thread that ctrl-C is pressed */ +volatile sig_atomic_t g_sig_ctrlc = 1; +void ctrlc_handler(int num) +{ + UNUSED_PARAMETER(num); + g_sig_ctrlc = 0; +} + +/* Issue shell commands independent of transport type and return result */ +static int +rwl_shell_information_fe(void *wl, int cmd, uchar* input_buf, unsigned long *input_len) +{ + int error, remote_cmd; + uchar* resp_buf = NULL; + rem_ioctl_t *rem_ptr = NULL; + +#ifdef RWL_WIFI + char *cbuf, retry; + dot11_action_wifi_vendor_specific_t *list; +#endif + +#ifdef RWL_SOCKET + int Sockfd; +#endif + + remote_cmd = REMOTE_SHELL_CMD; + +#ifdef RWLASD + if (cmd == ASD_CMD) + remote_cmd = REMOTE_ASD_CMD; +#endif + if (cmd == VISTA_CMD) + remote_cmd = REMOTE_VISTA_CMD; + + switch (remote_type) { + case REMOTE_SOCKET: +#ifdef RWL_SOCKET + if ((Sockfd = rwl_connect_socket_server()) < 0) { + DPRINT_ERR(ERR, " Error in getting the SocDes\n"); + return BCME_ERROR; + } + + wl = (void *)(&Sockfd); + if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len, + remote_cmd, 0) < 0) { + DPRINT_ERR(ERR, "shell_info_fe: Send command failed\n"); + rwl_close_pipe(remote_type, wl); + return BCME_ERROR; + } + /* For backward compatibility for ASD, async and kill commands do the + * old way + */ + if (remote_cmd == REMOTE_SHELL_CMD && !strstr((char*)input_buf, "%") && + !strstr((char*)input_buf, "kill")) + error = rwl_socket_shellresp(wl, rem_ptr, input_buf); + else { + if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) { + DPRINT_ERR(ERR, "shell_info_fe: Receiving CDC" + "header failed\n"); + rwl_close_pipe(remote_type, wl); + return FAIL; + } + + if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) { + DPRINT_ERR(ERR, "Mem alloc fails\n"); + rwl_close_pipe(remote_type, wl); + return FAIL; + } + + if (remote_CDC_rx(wl, rem_ptr, resp_buf, + rem_ptr->msg.len, 0) == FAIL) { + DPRINT_ERR(ERR, "shell_info_fe: No results!\n"); + rwl_close_pipe(remote_type, wl); + free(resp_buf); + return FAIL; + } + + /* print the shell result */ + resp_buf[rem_ptr->msg.len] = '\0'; + /* The return value of the shell command + * will be stored in rem_ptr->msg.cmd + * Return that value to the client process + */ + if (rem_ptr->msg.flags & REMOTE_REPLY) + error = rem_ptr->msg.cmd; + fputs((char*)resp_buf, stdout); + } + rwl_close_pipe(remote_type, wl); +#endif /* RWL_SOCKET */ + break; + case REMOTE_DONGLE: + case REMOTE_SERIAL: + if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len, + remote_cmd, 0) < 0) { + DPRINT_ERR(ERR, "shell_info_fe: Send command failed\n"); + return FAIL; + } + + /* For backward compatibility for ASD, async and kill commands do the + * old way + */ + if (remote_cmd != REMOTE_ASD_CMD && !strstr((char*)input_buf, "%") && + !strstr((char*)input_buf, "kill")) + error = rwl_dongle_shellresp(wl, rem_ptr, input_buf, cmd); + else { + if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) { + DPRINT_ERR(ERR, "shell_info_fe:" + "Receiving CDC header failed\n"); + return BCME_SERIAL_PORT_ERR; + } + rwl_swap_header(rem_ptr, NETWORK_TO_HOST); + /* In case of shell or ASD commands the response + * size is not known in advance + * Hence based on response from the server memory is allocated + */ + if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) { + DPRINT_ERR(ERR, "Mem alloc fails for shell response buffer\n"); + return FAIL; + } + + if (rem_ptr->data_len < DATA_FRAME_LEN) { + /* Response comes in one shot not in fragments */ + if (remote_CDC_rx(wl, rem_ptr, resp_buf, + rem_ptr->msg.len, 0) == FAIL) { + DPRINT_ERR(ERR, "shell_info_fe: No results!\n"); + free(resp_buf); + return FAIL; + } + } else { + error = rwl_serial_fragmented_response_fe(wl, rem_ptr, + resp_buf, (unsigned long *)&(rem_ptr->msg.len)); + } + /* print the shell result */ + resp_buf[rem_ptr->msg.len] = '\0'; + /* The return value of the shell command will be stored in rem_ptr->msg.cmd + * Return that value to the client process + */ + if (rem_ptr->msg.flags & REMOTE_REPLY) + error = rem_ptr->msg.cmd; + fputs((char*)resp_buf, stdout); + } + break; + + case REMOTE_WIFI: +#ifdef RWL_WIFI + /* Unlike dongle or UART case the response for wi-fi comes in single frame. + * (CDC header + data). Hence the single read is called for header and data. + * If any error in reading then we sleep for some time before retrying. + */ + if ((list = (dot11_action_wifi_vendor_specific_t *) + malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) { + return FAIL; + } + if ((rem_ptr = (rem_ioctl_t *)malloc(REMOTE_SIZE)) == NULL) { + free(list); + return FAIL; + } + + if ((cbuf = (char*) malloc(*input_len)) == NULL) { + DPRINT_ERR(ERR, "Malloc failed for shell response\n"); + free(rem_ptr); + free(list); + return FAIL; + } + + /* copy of the original buf is required for retry */ + memcpy(cbuf, (char*)input_buf, *input_len); + for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { + + rwl_wifi_purge_actionframes(wl); + if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len, + remote_cmd, 0) < 0) { + DPRINT_DBG(OUTPUT, "rwl_shell_information_fe(wifi):" + "Send command failed\n"); + rwl_sleep(RWL_WIFI_RETRY_DELAY); + free(rem_ptr); + free(list); + return FAIL; + } + /* For backward compatibility for ASD, + * async and kill commands do the + * old way + */ + if (remote_cmd == REMOTE_SHELL_CMD && + !strstr((char*)input_buf, "%") && + !strstr((char*)input_buf, "kill")) { + error = rwl_wifi_shellresp(wl, rem_ptr, input_buf); + if (rem_ptr->msg.len == 0) + break; + } + else if (remote_cmd == REMOTE_VISTA_CMD) { + if ((error = remote_CDC_DATA_wifi_rx_frag(wl, rem_ptr, 0, + NULL, RWL_WIFI_SHELL_CMD)) < 0) { + DPRINT_DBG(OUTPUT, "rwl_shell_information_fe(wifi):" + "error in reading shell response\n"); + continue; + } + if (rem_ptr->msg.flags & REMOTE_REPLY) { + error = rem_ptr->msg.cmd; + break; + } else { + rwl_sleep(RWL_WIFI_RETRY_DELAY); + continue; + } + } + else { + /* ASD commands may take long time to give back + * the response (eg: file transfer) + */ + if (remote_cmd == REMOTE_ASD_CMD) { + for (;;) { + /* copy back the buffer to input buffer */ + memcpy((char*)input_buf, cbuf, *input_len); + + if ((error = remote_CDC_DATA_wifi_rx_frag( + wl, rem_ptr, 0, NULL, + RWL_WIFI_SHELL_CMD)) < 0) { + DPRINT_DBG(OUTPUT, + "rwl_shell_information_fe(wifi):" + "err in reading shell response\n"); + continue; + } + if (rem_ptr->msg.flags & REMOTE_REPLY) { + error = rem_ptr->msg.cmd; + retry = RWL_WIFI_RETRY; + break; + } else { + rwl_sleep(RWL_WIFI_RETRY_DELAY); + continue; + } + } + } + } + + } + free(rem_ptr); + free(list); + if (cbuf != NULL) + free(cbuf); +#endif /* RWL_WIFI */ + break; + + default: + break; + } /* End of switch (remote_type) */ + + if (resp_buf) + free(resp_buf); + + return error; +} + +/* Prepare to issue shell command */ +int +rwl_shell_cmd_proc(void *wl, char **argv, int cmd) +{ + uchar *buff; + unsigned long len = SHELL_CMD_LEN; + int err; + + if ((buff = malloc(SHELL_CMD_LEN)) == NULL) { + DPRINT_ERR(ERR, "\n Mem alloc fails for shell cmd buffer\n"); + return FAIL; + } + + memset(buff, 0, sizeof(SHELL_CMD_LEN)); + while (*argv) { + strcat((char*)buff, *argv); + argv++; + if (*argv) + strcat((char*)buff, " "); /* leave space between args */ + } + + err = rwl_shell_information_fe(wl, cmd, buff, &len); + free(buff); + return err; +} + +/* transport independent entry point for GET ioctls */ +int +rwl_queryinformation_fe(void *wl, int cmd, void* input_buf, + unsigned long *input_len, int debug, int rem_ioctl_select) { + int error = 0; + uint tx_len; +#if defined(RWL_SERIAL) || RWL_WIFI + rem_ioctl_t *rem_ptr = NULL; +#endif + +#ifdef RWL_WIFI + int retry; + char *cinput_buf; +#endif + + UNUSED_PARAMETER(debug); + + switch (remote_type) { + case REMOTE_SOCKET: +#ifdef RWL_SOCKET + /* We don't want the server to allocate bigger buffers + * for some of the commands + * like scanresults. Server can still allocate 8K memory + * and send the response + */ + if (*input_len > SERVER_RESPONSE_MAX_BUF_LEN) + *input_len = SERVER_RESPONSE_MAX_BUF_LEN; + error = rwl_information_socket(wl, cmd, input_buf, input_len, + input_len, rem_ioctl_select); +#endif /* RWL_SOCKET */ + break; + +#ifdef RWL_SERIAL + /* System serial transport is not supported in Linux. Only XP */ + case REMOTE_SERIAL: + tx_len = MIN(*input_len, 1024); + /* Time estimate assumes 115K baud */ + if (*input_len > (1024 *10)) + /* Multiply by 2. The buffer has to go there and back */ + DPRINT_DBG(OUTPUT, "Wait time: %lu seconds\n", + ((*input_len)+ tx_len) / (115200/8)); + + if (remote_CDC_tx(wl, cmd, input_buf, *input_len, + tx_len, rem_ioctl_select, debug) < 0) { + DPRINT_ERR(ERR, "query_info_fe: Send command failed\n"); + return FAIL; + } + + if ((rem_ptr = remote_CDC_rx_hdr(wl, debug)) == NULL) { + DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed\n"); + return FAIL; + } + + if (rem_ptr->msg.flags != REMOTE_REPLY) { + DPRINT_ERR(ERR, "query_info_fe: response format error.\n"); + return FAIL; + } + if (rem_ptr->msg.len > *input_len) { + DPRINT_ERR(ERR, "query_info_fe: needed size(%d) greater than " + "actual size(%lu)\n", rem_ptr->msg.len, *input_len); + return FAIL; + } + + if (error != 0) + DPRINT_ERR(ERR, "query_info_fe: remote cdc header return " + "error code %d\n", error); + if (remote_CDC_rx(wl, rem_ptr, input_buf, *input_len, debug) == -1) { + DPRINT_ERR(ERR, "query_info_fe: No results!\n"); + return FAIL; + } + if (rem_ptr->msg.flags & REMOTE_REPLY) + error = rem_ptr->msg.cmd; + break; + +#endif /* RWL_SERIAL */ + case REMOTE_DONGLE: + /* We don't want the server to allocate bigger buffers + * for some of the commands + * like scanresults. Server can still allocate 8K + *memory and send the response + * in fragments. + */ + if (*input_len > SERVER_RESPONSE_MAX_BUF_LEN) + *input_len = SERVER_RESPONSE_MAX_BUF_LEN; + + /* Actual buffer to be sent should be max 256 bytes as + *UART input buffer + * is 512 bytes + */ + tx_len = MIN(*input_len, 256); + error = rwl_information_dongle(wl, cmd, input_buf, input_len, + tx_len, rem_ioctl_select); + + break; + + case REMOTE_WIFI: +#ifdef RWL_WIFI + /* We don't want the server to allocate bigger buffers + * for some of the commands + * like scanresults. Server can still allocate 8K memory + * and send the response + * in fragments. + */ + if (*input_len > SERVER_RESPONSE_MAX_BUF_LEN) + *input_len = SERVER_RESPONSE_MAX_BUF_LEN; + + /* Actual buffer to be sent should be max 960 bytes + * as wifi max frame size if 960 + * and actual data for any command will not exceed 960 bytes + */ + tx_len = MIN(*input_len, RWL_WIFI_FRAG_DATA_SIZE); + + if ((rem_ptr = (rem_ioctl_t *)malloc(REMOTE_SIZE)) == NULL) { + return FAIL; + } + if ((cinput_buf = (char*)malloc(tx_len)) == NULL) { + DPRINT_ERR(ERR, "Malloc failed for query information fe" + "character buf \n"); + free(rem_ptr); + return FAIL; + } + + memcpy(cinput_buf, (char*)input_buf, tx_len); /* Keep a copy of input_buf */ + + for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { + + rwl_wifi_purge_actionframes(wl); + + if (retry > 3) + DPRINT_INFO(OUTPUT, "ir_queryinformation_fe : retry %d" + "cmd %d\n", retry, cmd); + + /* copy back the buffer to input buffer */ + memcpy((char*)input_buf, cinput_buf, tx_len); + + /* Issue the command */ + if ((error = remote_CDC_wifi_tx(wl, cmd, input_buf, + *input_len, tx_len, rem_ioctl_select)) < 0) { + DPRINT_DBG(OUTPUT, "query_info_fe: Send command failed\n"); + rwl_sleep(RWL_WIFI_RETRY_DELAY); + continue; + } + + if ((error = remote_CDC_DATA_wifi_rx_frag(wl, rem_ptr, + *input_len, input_buf, RWL_WIFI_WL_CMD) < 0)) { + DPRINT_DBG(OUTPUT, "ir_queryinformation_fe :" + "Error in reading the frag bytes\n"); + rwl_sleep(RWL_WIFI_RETRY_DELAY); + continue; + } + + if (rem_ptr->msg.flags & REMOTE_REPLY) { + error = rem_ptr->msg.cmd; + break; + } else { + rwl_sleep(RWL_WIFI_RETRY_DELAY); + } + } + + free(rem_ptr); + if (cinput_buf) + free(cinput_buf); + break; +#endif /* RWL_WIFI */ + default: + DPRINT_ERR(ERR, "rwl_queryinformation_fe: Unknown" + "remote_type %d\n", remote_type); + break; + } + return error; +} + +/* +* This is the front end query function for Set Ioctls. This is used by clients +for executing Set Ioctls. +*/ +int +rwl_setinformation_fe(void *wl, int cmd, void* buf, + unsigned long *len, int debug, int rem_ioctl_select) { + int error = 0; + uint tx_len; +#if defined(RWL_SERIAL) || RWL_WIFI + rem_ioctl_t *rem_ptr = NULL; +#endif + +#ifdef RWL_WIFI + dot11_action_wifi_vendor_specific_t *list = NULL; + char *cbuf, retry; +#endif + + UNUSED_PARAMETER(debug); + + switch (remote_type) { + case REMOTE_SOCKET: +#ifdef RWL_SOCKET + error = rwl_information_socket(wl, cmd, buf, len, len, rem_ioctl_select); +#endif + break; +#ifdef RWL_SERIAL + case REMOTE_SERIAL: + if (*len > (1024 *10)) + DPRINT_DBG(OUTPUT, "Wait time: %lu seconds\n", (*len)/(115200/8)); + + if (remote_CDC_tx(wl, cmd, buf, *len, *len, rem_ioctl_select, debug) < 0) { + DPRINT_ERR(ERR, "set_info_fe: Send command failed\n"); + return FAIL; + } + + if ((rem_ptr = remote_CDC_rx_hdr(wl, debug)) == NULL) { + DPRINT_ERR(ERR, "set_info_fe: Reading CDC header failed\n"); + return FAIL; + } + + if (rem_ptr->msg.flags != REMOTE_REPLY) { + DPRINT_ERR(ERR, "set_info_fe: response format error.\n"); + return FAIL; + } + + if (rem_ptr->msg.len > *len) { + DPRINT_ERR(ERR, "set_info_fe: needed size (%d) greater than " + "actual size (%lu)\n", rem_ptr->msg.len, *len); + return FAIL; + } + + if (error != 0) { + DPRINT_ERR(ERR, "set_info_fe: remote cdc header return " + "error code (%d)\n", error); + } + if (remote_CDC_rx(wl, rem_ptr, buf, rem_ptr->msg.len, debug) == -1) { + DPRINT_ERR(ERR, "set_info_fe: fetching results failed\n"); + return FAIL; + } + + if (rem_ptr->msg.flags & REMOTE_REPLY) + error = rem_ptr->msg.cmd; + break; +#endif /* RWL_SERIAL */ + case REMOTE_DONGLE: + if (*len > SERVER_RESPONSE_MAX_BUF_LEN) + *len = SERVER_RESPONSE_MAX_BUF_LEN; + + /* Actual buffer to be sent should be max 256 bytes as + *UART input buffer + * is 512 bytes + */ + tx_len = MIN(*len, 512); + error = rwl_information_dongle(wl, cmd, buf, len, tx_len, rem_ioctl_select); + break; + + case REMOTE_WIFI: +#ifdef RWL_WIFI + if (*len > SERVER_RESPONSE_MAX_BUF_LEN) + *len = SERVER_RESPONSE_MAX_BUF_LEN; + + /* Actual buffer to be sent should be max 960 bytes + * as wifi max frame size if 960 + * and actual data for any command will not exceed 960 bytes + */ + tx_len = MIN(*len, RWL_WIFI_FRAG_DATA_SIZE); + + if ((cbuf = (char*) malloc(tx_len)) == NULL) { + DPRINT_ERR(ERR, "Malloc failed for set_info_fe character buf\n"); + return FAIL; + } + if ((list = (dot11_action_wifi_vendor_specific_t *) + malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) { + free(cbuf); + return FAIL; + } + + if ((rem_ptr = (rem_ioctl_t *)malloc(sizeof(rem_ioctl_t))) == NULL) { + free(list); + free(cbuf); + return FAIL; + } + + memcpy(cbuf, (char*)buf, tx_len); + + for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { + + rwl_wifi_purge_actionframes(wl); + /* copy back the buffer to input buffer */ + memcpy((char*)buf, (char*)cbuf, tx_len); + + if (retry > 3) + DPRINT_INFO(OUTPUT, "retry %d cmd %d\n", retry, cmd); + + if ((error = remote_CDC_wifi_tx(wl, cmd, buf, *len, + tx_len, rem_ioctl_select) < 0)) { + DPRINT_ERR(ERR, "ir_setinformation_fe: Send" + "command failed\n"); + rwl_sleep(RWL_WIFI_RETRY_DELAY); + continue; + } + + if ((char*)buf != NULL) { + /* In case cmd is findserver, response is not + * required from the server + */ + if (!strcmp((char*)buf, RWL_WIFI_FIND_SER_CMD)) { + break; + } + } + + /* Read the CDC header and data of for the sent cmd + * resposne + */ + if ((error = remote_CDC_DATA_wifi_rx((void*)wl, list) < 0)) { + DPRINT_ERR(ERR, "ir_setinformation_fe: failed to read" + "the response\n"); + rwl_sleep(RWL_WIFI_RETRY_DELAY); + continue; + } + + memcpy((char*)rem_ptr, + (char*)&list->data[RWL_WIFI_CDC_HEADER_OFFSET], + REMOTE_SIZE); + rwl_swap_header(rem_ptr, NETWORK_TO_HOST); + + memcpy((char*)buf, (char*)&list->data[REMOTE_SIZE], + rem_ptr->msg.len); + + if (rem_ptr->msg.flags & REMOTE_REPLY) { + error = rem_ptr->msg.cmd; + break; + } else { + rwl_sleep(RWL_WIFI_RETRY_DELAY); + } + } + free(rem_ptr); + free(list); + if (cbuf != NULL) + free(cbuf); + break; +#endif /* RWL_WIFI */ + default: + DPRINT_ERR(ERR, "rwl_setinformation_fe: Unknown remote_type:%d\n", + remote_type); + break; + } + + return error; +} + +#ifdef RWL_WIFI +int +rwl_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr) +{ + int len, error; + + memset((char*)g_rwl_aligned_buf, 0, WLC_IOCTL_MAXLEN); + strcpy(g_rwl_aligned_buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&g_rwl_aligned_buf[len], param, param_len); + + *bufptr = g_rwl_aligned_buf; + /* When user wants to execute local CMD being in remote wifi mode, + * rwl_wifi_swap_remote_type fucntion is used to change the remote types. + */ + rwl_wifi_swap_remote_type(remote_type); + + error = wl_get(wl, WLC_GET_VAR, &g_rwl_aligned_buf[0], WLC_IOCTL_MAXLEN); + /* revert back to the old remote type */ + rwl_wifi_swap_remote_type(remote_type); + return error; +} + +int +rwl_var_setbuf(void *wl, const char *iovar, void *param, int param_len) +{ + int len, error; + + memset(g_rwl_aligned_buf, 0, WLC_IOCTL_MAXLEN); + strcpy(g_rwl_aligned_buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&g_rwl_aligned_buf[len], param, param_len); + + len += param_len; + /* When user wants to execute local CMD being in remote wifi mode, + * rwl_wifi_swap_remote_type fucntion is used to change the remote types. + */ + rwl_wifi_swap_remote_type(remote_type); + error = wl_set(wl, WLC_SET_VAR, &g_rwl_aligned_buf[0], len); + /* revert back to the old type */ + rwl_wifi_swap_remote_type(remote_type); + return error; +} + +/* This function will send the buffer to the dongle driver */ +int +rwl_var_send_vs_actionframe(void* wl, const char* iovar, void* param, int param_len) +{ + int len, error; + + memset(g_rwl_aligned_buf, 0, WLC_IOCTL_MAXLEN); + strcpy(g_rwl_aligned_buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy((void*)&g_rwl_aligned_buf[len+ OFFSETOF(wl_action_frame_t, data)], + param, + param_len); + + /* Set the PacketID (not used by remote WL */ + memset((void*)&g_rwl_aligned_buf[len + OFFSETOF(wl_action_frame_t, packetId)], 0, 4); + + /* Set the dest addr */ + memcpy((void*)&g_rwl_aligned_buf[len + OFFSETOF(wl_action_frame_t, da)], + (void*)g_rwl_buf_mac, + ETHER_ADDR_LEN); + + /* set the length */ + memcpy((void*)&g_rwl_aligned_buf[len + OFFSETOF(wl_action_frame_t, len)], + (void*) ¶m_len, + 2); + + len += param_len + ETHER_ADDR_LEN + 2 + 4; + + /* When user wants to execute local CMD being in remote wifi mode, + * rwl_wifi_swap_remote_type fucntion is used to change the remote types. + */ + rwl_wifi_swap_remote_type(remote_type); + + error = wl_set(wl, WLC_SET_VAR, &g_rwl_aligned_buf[0], len); + /* revert back to the old type */ + rwl_wifi_swap_remote_type(remote_type); + return error; +} +#endif /* RWL_WIFI */ +/* + * Function for printing the usage if user type invalid command line + * options(e.g wl --serial or --dongle or --socket or --wifi) + */ +void +rwl_usage(int remote_type) +{ + switch (remote_type) { + case REMOTE_SERIAL: + fprintf(stderr, " Usage: wl/dhd [--linuxdut/linux] [--debug]"); + fprintf(stderr, " [--serial port no]"); + fprintf(stderr, "[--ReadTimeout n] [--interactive] [--clientbatch] \n"); + fprintf(stderr, "\t--linuxdut/linux removes the WLC_OID_BASE"); + fprintf(stderr, "when sending the IOCTL command \n"); + fprintf(stderr, "\t--debug prints out tx packets sending down "); + fprintf(stderr, " the serial line, and other debug info \n"); + fprintf(stderr, "\t--serial enables the remoteWL serial port number\n"); + fprintf(stderr, "\t--interactive enables using WL in interactive mode\n"); + fprintf(stderr, "\t--clientbatch enables command batchinng on the client,"); + fprintf(stderr, " the default is batching on driver\n"); + break; + case REMOTE_DONGLE: + fprintf(stderr, " Usage: wl/dhd --dongle <Device Name> <command>\n"); + fprintf(stderr, "\t<Device Name> COM1/COM2 (WinXP) or /dev/ttyS0" + " or /dev/ttyS1 (Linux)\n"); + fprintf(stderr, "\t<command> - wl, shell or dhd command\n"); + fprintf(stderr, "\tDepending on the client you are using(wl or dhd)\n"); + fprintf(stderr, "\t\t shell command usage: sh <command>\n"); + break; + case REMOTE_SOCKET: + fprintf(stderr, " Usage: " + "wl/dhd --socket <IP ADDRESS> [<PORT>] <command>\n"); + fprintf(stderr, "\t<IPADDRESS> IP address of server machine\n"); + fprintf(stderr, "\t<PORT> Port no of server\n"); + fprintf(stderr, "\t<command> - wl, shell or dhd command\n"); + fprintf(stderr, "\tDepending on the client you are using(wl or dhd)\n"); + fprintf(stderr, "\t\t shell command usage: sh <command>\n"); + fprintf(stderr, "\t If <PORT> is omitted, use default port number 8000\n"); + break; + case REMOTE_WIFI: + fprintf(stderr, " Usage: wl/dhd --wifi <MAC Address> <command>\n"); + fprintf(stderr, "\t<MAC Address> MAC Address\n"); + fprintf(stderr, "\t<command> - wl, shell or dhd command\n"); + fprintf(stderr, "\tDepending on the client you are using(wl or dhd)\n"); + fprintf(stderr, "\t\t shell command usage: sh <command>\n"); + break; + default: + break; + } +} +#ifdef RWL_SOCKET +/* Note in case of error ( returned value == FAIL) it is assumed that wl is closed by caller, + * no treatment in this function + */ +static int +rwl_socket_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf) +{ + uchar* resp_buf = NULL; + int pid, msg_len, error; + g_sig_ctrlc = 1; + g_child_pid = pid = rwl_shell_createproc(wl); + if (pid == 0) { + while (g_sig_ctrlc); + remote_CDC_tx(wl, 0, input_buf, 0, 0, CTRLC_FLAG, 0); + exit(0); + } + + do { + if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) { + DPRINT_ERR(ERR, "rwl_socket_shellresp: Receiving CDC" + "header failed\n"); + return FAIL; + } + msg_len = rem_ptr->msg.len; + if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) { + DPRINT_ERR(ERR, "rwl_socket_shellresp: Mem alloc fails\n"); + return FAIL; + } + if (msg_len > 0) { + if (remote_CDC_rx(wl, rem_ptr, resp_buf, + rem_ptr->msg.len, 0) == FAIL) { + DPRINT_ERR(ERR, "rwl_socket_shellresp: No results!\n"); + free(resp_buf); + return FAIL; + } + } + /* print the shell result */ + resp_buf[rem_ptr->msg.len] = '\0'; + /* The return value of the shell command + * will be stored in rem_ptr->msg.cmd + * Return that value to the client process + */ + if (rem_ptr->msg.flags & REMOTE_REPLY) + error = rem_ptr->msg.cmd; + write(1, resp_buf, msg_len); + } while (msg_len); + rwl_shell_killproc(pid); + return error; +} +#endif /* RWL_SOCKET */ +/* For wifi shell responses read data until server stops sending */ +#ifdef RWL_WIFI +static int +rwl_wifi_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf) +{ + int pid, msg_len, error; + g_sig_ctrlc = 1; + g_child_pid = pid = rwl_shell_createproc(wl); + if (pid == 0) + { + while (g_sig_ctrlc); + remote_CDC_tx(wl, 0, input_buf, 0, 0, CTRLC_FLAG, 0); + exit(0); + } + + do { + if ((error = remote_CDC_DATA_wifi_rx_frag(wl, rem_ptr, 0, + NULL, RWL_WIFI_SHELL_CMD)) < 0) { + DPRINT_DBG(OUTPUT, "rwl_shell_information_fe(wifi):" + "error in reading shell response\n"); + continue; + } + msg_len = rem_ptr->msg.len; + error = rem_ptr->msg.cmd; + } while (msg_len); + + rwl_shell_killproc(pid); + return error; +} +#endif /* RWL_WIFI */ + +/* For dongle or system serial shell responses read data until server stops sending */ +static int +rwl_dongle_shellresp(void *wl, rem_ioctl_t *rem_ptr, uchar *input_buf, int cmd) +{ + int pid, msg_len, error; + uchar *resp_buf; + + g_sig_ctrlc = 1; + g_child_pid = pid = rwl_shell_createproc(wl); + if (pid == 0) { + while (g_sig_ctrlc); + remote_CDC_tx(wl, cmd, input_buf, 0, 0, CTRLC_FLAG, 0); + exit(0); + } + + do { + if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) { + DPRINT_ERR(ERR, "shell_info_fe: Receiving CDC header failed\n"); + return BCME_SERIAL_PORT_ERR; + } + /* In case of shell or ASD commands the response size is not known in advance + * Hence based on response from the server memory is allocated + */ + msg_len = rem_ptr->msg.len; + if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) { + DPRINT_ERR(ERR, "Mem alloc fails for shell response buffer\n"); + return FAIL; + } + /* Response comes in one shot not in fragments */ + if (remote_CDC_rx(wl, rem_ptr, resp_buf, + rem_ptr->msg.len, 0) == FAIL) { + DPRINT_ERR(ERR, "shell_info_fe: No results!\n"); + free(resp_buf); + return FAIL; + } + /* print the shell result */ + resp_buf[rem_ptr->msg.len] = '\0'; + /* The return value of the shell command will be stored in rem_ptr->msg.cmd + * Return that value to the client process + */ + if (rem_ptr->msg.flags & REMOTE_REPLY) + error = rem_ptr->msg.cmd; + write(1, resp_buf, msg_len); + } while (msg_len); + rwl_shell_killproc(pid); + return error; +} + +int rwl_detect(void *wl, bool debug, int* os_type_ptr) +{ + int error, buf = UNKNOWN_OS; + unsigned long len = sizeof(buf); + + error = rwl_queryinformation_fe(wl, + NEGOTIATE_GET_OS, &buf, &len, debug, REMOTE_NEGOTIATE_CMD); + if (!error) { + if (buf > UNKNOWN_OS && buf < INVALID_OS) { + *os_type_ptr = buf; + if (debug) + fprintf(stderr, "Autodetect: %d\n", *os_type_ptr); + return 0; + } + } + + fprintf(stderr, "Autodetect failed, rwl server is either " + "too old or unreachable. Use --nodetect to disable autodetect.\n"); + return FAIL; +} + +int rwl_check_port_number(char *s, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (!isdigit(s[i])) + return FAIL; + } + return SUCCESS; +}
diff --git a/src/wl/exe/wlu_client_shared.h b/src/wl/exe/wlu_client_shared.h new file mode 100644 index 0000000..ed8452d --- /dev/null +++ b/src/wl/exe/wlu_client_shared.h
@@ -0,0 +1,37 @@ +/* + * OS independent client specific declarations + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_client_shared.h 331785 2012-05-07 21:05:20Z $ + */ +#ifndef _wlu_client_shared_h +#define _wlu_client_shared_h + +/* Newly added wrappers from wlu_client_shared.c */ +extern int +rwl_shell_cmd_proc(void *wl, char **argv, int cmd); +extern int +rwl_queryinformation_fe(void *wl, int cmd, void* input_buf, unsigned long *input_len, +int debug, int rem_ioctl_select); +extern int +rwl_setinformation_fe(void *wl, int cmd, void* buf, unsigned long *len, int debug, +int rem_ioctl_select); +extern void +rwl_usage(int remote_type); +extern int +rwl_detect(void *wl, bool debug, int* os_type_ptr); + +extern int rwl_shell_createproc(void *wl); +extern void rwl_shell_killproc(int pid); +/* declaring these as extern to be used in wlu_ndis.c and wlu_linux.c */ +extern volatile sig_atomic_t g_sig_ctrlc; +extern void ctrlc_handler(int num); + +#endif /* _wlu_client_share_h */
diff --git a/src/wl/exe/wlu_cmd.c b/src/wl/exe/wlu_cmd.c new file mode 100644 index 0000000..f63d41d --- /dev/null +++ b/src/wl/exe/wlu_cmd.c
@@ -0,0 +1,21 @@ +/* + * $Id: wlu_cmd.c 428479 2013-10-08 23:08:49Z $ + * $Copyright: (c) 2006, Broadcom Corp. + * All Rights Reserved.$ + * + * File: wlu_cmd.c + * Purpose: Command and IO variable information commands + * Requires: + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include <typedefs.h> +#include <bcmutils.h> +#include <wlioctl.h> + +#include "wlu.h"
diff --git a/src/wl/exe/wlu_cmd.h b/src/wl/exe/wlu_cmd.h new file mode 100644 index 0000000..c98ced1 --- /dev/null +++ b/src/wl/exe/wlu_cmd.h
@@ -0,0 +1,141 @@ +/* + * Command structure for wl command line utility + * + * Copyright 2002, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied or + * duplicated in any form, in whole or in part, without the prior written + * permission of Broadcom Corporation. + * + * $Id: wlu_cmd.h 428479 2013-10-08 23:08:49Z $ + */ + +#ifndef _wlu_cmd_h_ +#define _wlu_cmd_h_ + +typedef struct cmd cmd_t; +typedef int (cmd_func_t)(void *wl, cmd_t *cmd, char **argv); + +/* generic command line argument handler */ +struct cmd { + const char *name; + cmd_func_t *func; + int get; + int set; + const char *help; +}; + +/* list of command line arguments */ +extern cmd_t wl_cmds[]; +extern cmd_t wl_varcmd; + +/* per-port ioctl handlers */ +extern int wl_get(void *wl, int cmd, void *buf, int len); +extern int wl_set(void *wl, int cmd, void *buf, int len); + +/* + * Flags for command categories. A command may belong to + * multiple categories. These are used in bitmaps, so be careful + * to keep the macro value (2 ^ n) and the array indexes (n) + * consistent. + */ + +#define CMD_PHY 0x1 +#define CMD_CHAN 0x2 +#define CMD_RATE 0x4 +#define CMD_POWER 0x8 +#define CMD_MAC 0x10 +#define CMD_MGMT 0x20 +#define CMD_SEC 0x40 +#define CMD_WME 0x80 +#define CMD_MON 0x100 +#define CMD_AP 0x200 +#define CMD_STA 0x400 +#define CMD_BOARD 0x800 +#define CMD_ADMIN 0x1000 +#define CMD_DEV 0x2000 +#define CMD_DEP 0x4000 +#define CMD_UNCAT 0x8000 + +#define CMD_ALL 0xffff + +/* Initializer for category string array */ + +#define CMD_CATEGORY_STRINGS_INIT { \ + "phy", \ + "chan", \ + "rate", \ + "power", \ + "mac", \ + "mgmt", \ + "sec", \ + "wme", \ + "mon", \ + "ap", \ + "sta", \ + "board", \ + "admin", \ + "dev", \ + "dep", \ + "uncat", \ + "" } + +extern const char *wl_cmd_category_strings[]; +extern const int wl_cmd_category_count; + +/* Initializer for category description strings array */ +#define CMD_CATEGORY_DESC_INIT { \ + "PHY and radio; speed, band, etc", \ + "Channel; subclass of phy", \ + "Rate; subclass of phy, a/b/g", \ + "Power; subclass of phy", \ + "MAC; Media access", \ + "Management, association, IE, etc", \ + "Security; subclass of mgmt", \ + "WME; media extensions", \ + "Monitoring device (counters, etc)", \ + "AP subclass of mgmt", \ + "STA subclass of mgmt", \ + "Board, hardware", \ + "Administration; software, UI, diags", \ + "Device; low level control", \ + "Deprecated", \ + "Uncategorized so far", \ + "" } + +extern const char *wl_cmd_category_desc[]; + +/* + * + * IO variable information + * + */ + +/* Supplemental IO variable info structure */ +typedef const struct wlu_iov_info_s { + const char *name; + uint32 cat; /* Category flags; same as command categories */ + uint32 flags; /* See below */ + int dflt; /* Only for integers; see flags */ + const char *desc; /* Description */ +} wlu_iov_info_t; + +/* Flags for wlu_iov_info_t */ +#define WLU_IOVI_READ_ONLY 0x1 /* Known to be read only */ +#define WLU_IOVI_WRITE_ONLY 0x2 /* Known to be write only */ +#define WLU_IOVI_BCM_INTERNAL 0x4 /* Known to be BCM internal */ +#define WLU_IOVI_DEFAULT_VALID 0x8 /* Default value in structure is valid */ + +extern wlu_iov_info_t wlu_iov_info[]; +extern int wlu_iov_info_count; + +#define WLU_IOV_BLOCK_LEN 10 + +#define WLU_MOD_NAME_MAX 64 /* Max num modules */ +#define WLU_MOD_NAME_BYTES 16 /* Size of modules name */ + +extern int wl_get_scan(void *wl, int opc, char *scan_buf, uint buf_len); + +#endif /* _wlu_cmd_h_ */
diff --git a/src/wl/exe/wlu_common.c b/src/wl/exe/wlu_common.c new file mode 100644 index 0000000..4207287 --- /dev/null +++ b/src/wl/exe/wlu_common.c
@@ -0,0 +1,385 @@ +/* + * Common code for wl routines + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_common.c 433133 2013-10-30 19:23:45Z $ + */ + +#ifdef WIN32 +#include <windows.h> +#endif + +#include "wlu_common.h" +#include "wlu.h" +#include <bcmendian.h> + +extern int wl_get(void *wl, int cmd, void *buf, int len); +extern int wl_set(void *wl, int cmd, void *buf, int len); + +wl_cmd_list_t cmd_list; +int cmd_pkt_list_num; +bool cmd_batching_mode; + +const char *wlu_av0; + +/* global wlc index indentifier for RSDB -W/--wlc option */ +int g_wlc_idx = -1; + + + +/* + * format an iovar buffer + * iovar name is converted to lower case + */ +static uint +wl_iovar_mkbuf(const char *name, char *data, uint datalen, char *iovar_buf, uint buflen, int *perr) +{ + uint iovar_len; + char *p; + + iovar_len = strlen(name) + 1; + + /* check for overflow */ + if ((iovar_len + datalen) > buflen) { + *perr = BCME_BUFTOOSHORT; + return 0; + } + + /* copy data to the buffer past the end of the iovar name string */ + if (datalen > 0) + memmove(&iovar_buf[iovar_len], data, datalen); + + /* copy the name to the beginning of the buffer */ + strcpy(iovar_buf, name); + + /* wl command line automatically converts iovar names to lower case for + * ease of use + */ + p = iovar_buf; + while (*p != '\0') { + *p = tolower((int)*p); + p++; + } + + *perr = 0; + return (iovar_len + datalen); +} + +void +init_cmd_batchingmode(void) +{ + cmd_pkt_list_num = 0; + cmd_batching_mode = FALSE; +} + +void +clean_up_cmd_list(void) +{ + wl_seq_cmd_pkt_t *this_cmd, *next_cmd; + + this_cmd = cmd_list.head; + while (this_cmd != NULL) { + next_cmd = this_cmd->next; + if (this_cmd->data != NULL) { + free(this_cmd->data); + } + free(this_cmd); + this_cmd = next_cmd; + } + cmd_list.head = NULL; + cmd_list.tail = NULL; + cmd_pkt_list_num = 0; +} + +int +add_one_batched_cmd(int cmd, void *cmdbuf, int len) +{ + wl_seq_cmd_pkt_t *new_cmd; + + new_cmd = malloc(sizeof(wl_seq_cmd_pkt_t)); + + if (new_cmd == NULL) { + printf("malloc(%d) failed, free %d batched commands and exit batching mode\n", + (int)sizeof(wl_seq_cmd_pkt_t), cmd_pkt_list_num); + goto free_and_exit; + } else { + printf("batching %dth command %d\n", cmd_pkt_list_num+1, cmd); + + } + + new_cmd->cmd_header.cmd = cmd; + new_cmd->cmd_header.len = len; + new_cmd->next = NULL; + + new_cmd->data = malloc(len); + + if (new_cmd->data == NULL) { + printf("malloc(%d) failed, free %d batched commands and exit batching mode\n", + len, cmd_pkt_list_num); + free(new_cmd); + goto free_and_exit; + } + + memcpy(new_cmd->data, cmdbuf, len); + + if (cmd_list.tail != NULL) + cmd_list.tail->next = new_cmd; + else + cmd_list.head = new_cmd; + + cmd_list.tail = new_cmd; + + cmd_pkt_list_num ++; + return 0; + +free_and_exit: + + clean_up_cmd_list(); + + if (cmd_batching_mode) { + cmd_batching_mode = FALSE; + } + else { + printf("calling add_one_batched_cmd() at non-command-batching mode, weird\n"); + } + + return -1; +} + +int +wlu_get_req_buflen(int cmd, void *cmdbuf, int len) +{ + int modified_len = len; + char *cmdstr = (char *)cmdbuf; + + if (len == WLC_IOCTL_MAXLEN) { + if ((strcmp(cmdstr, "dump") == 0) || + (cmd == WLC_SCAN_RESULTS)) + modified_len = WLC_IOCTL_MAXLEN; + else + modified_len = WLC_IOCTL_MEDLEN; + } + return modified_len; +} +/* Wrapper function that converts -W option in to "wlc:" prefix + * (1) It converts an existing iovar to the following format + * wlc:<iovar_name>\0<wlc_idx><param> + * (2) It converts an existing ioctl to the following format + * wlc:ioc\0<wlc_idx><ioct_cmd_id><param> + * NOTE: (2) requires new iovar named "ioc" in driver +*/ +static int +wlu_wlc_wrapper(void *wl, bool get, int* cmd, void *cmdbuf, int len, void **outbuf, int *outlen) +{ + void *param = cmdbuf; + int paramlen = len; + int wlc_idx = g_wlc_idx; + char *name = NULL; + BCM_REFERENCE(wl); + /* Wrap only if we find a valid WLC index and iovar name */ + if (wlc_idx >= 0) { + int cmdlen = 0; + int prefix_len = 0; + char *lbuf = NULL; + char *buf = NULL; + bool ioctl_wrap = FALSE; + if ((*cmd == WLC_GET_VAR) || (*cmd == WLC_SET_VAR)) { + /* incoming command is an iovar */ + /* pull out name\0param */ + name = cmdbuf; + cmdlen = strlen(name); + param = ((char*)cmdbuf) + cmdlen + 1; + paramlen = len - cmdlen - 1; + } else { + /* we are an ioctl, invoke the common "ioc" iovar and wrap the cmd */ + name = "ioc"; + cmdlen = strlen(name); + /* additional 4 bytes for storing IOCTL_CMD_ID */ + prefix_len = sizeof(int); + ioctl_wrap = TRUE; + } + prefix_len += strlen("wlc:") + 1 + cmdlen + sizeof(int); + /* now create wlc:<name>\0<wlc_idx><param> */ + buf = lbuf = malloc(prefix_len + paramlen); + if (buf == NULL) { + printf("%s:malloc(%d) failed\n", __FUNCTION__, prefix_len + paramlen); + return BCME_NOMEM; + } + memcpy(buf, "wlc:", 4); buf += 4; + strcpy(buf, name); buf += (cmdlen+1); + wlc_idx = htod32(wlc_idx); + memcpy(buf, &wlc_idx, sizeof(int32)); buf += sizeof(int32); + if (ioctl_wrap) { + /* For IOCTL wlc:ioc\0<wlc_idx><ioctl_id><param> */ + int32 ioctl_cmd = htod32(*cmd); + memcpy(buf, &ioctl_cmd, sizeof(int32)); buf += sizeof(int32); + } + memcpy(buf, param, paramlen); + *cmd = (get) ? WLC_GET_VAR : WLC_SET_VAR; + param = lbuf; + paramlen += prefix_len; + } + *outlen = paramlen; + *outbuf = param; + return BCME_OK; +} +/* now IOCTL GET commands shall call wlu_get() instead of wl_get() so that the commands + * can be batched when needed + */ +int +wlu_get(void *wl, int cmd, void *cmdbuf, int len) +{ + void *outbuf = NULL; + int outlen; + int err = 0; + if (cmd_batching_mode) { + if (!WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd)) { + printf("IOCTL GET command %d is not supported in batching mode\n", cmd); + return BCME_UNSUPPORTED; + } + } + + err = wlu_wlc_wrapper(wl, TRUE, &cmd, cmdbuf, len, &outbuf, &outlen); + if (err != BCME_OK) return err; + err = wl_get(wl, cmd, outbuf, outlen); + + if (outbuf != cmdbuf) { + memcpy(cmdbuf, outbuf, len); + free(outbuf); + } + return err; +} + +/* now IOCTL SET commands shall call wlu_set() instead of wl_set() so that the commands + * can be batched when needed + */ +int +wlu_set(void *wl, int cmd, void *cmdbuf, int len) +{ + int err = 0; + void *outbuf = NULL; + int outlen; + + err = wlu_wlc_wrapper(wl, FALSE, &cmd, cmdbuf, len, &outbuf, &outlen); + if (err != BCME_OK) return err; + + if (cmd_batching_mode) { + err = add_one_batched_cmd(cmd, outbuf, outlen); + } + else { + err = wl_set(wl, cmd, outbuf, outlen); + } + if (outbuf != cmdbuf) { + memcpy(cmdbuf, outbuf, len); + free(outbuf); + } + return err; + +} + +/* + * get named iovar providing both parameter and i/o buffers + * iovar name is converted to lower case + */ +int +wlu_iovar_getbuf(void* wl, const char *iovar, + void *param, int paramlen, void *bufptr, int buflen) +{ + int err; + + wl_iovar_mkbuf(iovar, param, paramlen, bufptr, buflen, &err); + if (err) + return err; + + return wlu_get(wl, WLC_GET_VAR, bufptr, buflen); +} + +/* + * set named iovar providing both parameter and i/o buffers + * iovar name is converted to lower case + */ +int +wlu_iovar_setbuf(void* wl, const char *iovar, + void *param, int paramlen, void *bufptr, int buflen) +{ + int err; + int iolen; + + iolen = wl_iovar_mkbuf(iovar, param, paramlen, bufptr, buflen, &err); + if (err) + return err; + + return wlu_set(wl, WLC_SET_VAR, bufptr, iolen); +} + +/* + * get named iovar without parameters into a given buffer + * iovar name is converted to lower case + */ +int +wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len) +{ + char smbuf[WLC_IOCTL_SMLEN]; + int err; + + /* use the return buffer if it is bigger than what we have on the stack */ + if (len > (int)sizeof(smbuf)) { + err = wlu_iovar_getbuf(wl, iovar, NULL, 0, outbuf, len); + } else { + memset(smbuf, 0, sizeof(smbuf)); + err = wlu_iovar_getbuf(wl, iovar, NULL, 0, smbuf, sizeof(smbuf)); + if (err == 0) + memcpy(outbuf, smbuf, len); + } + + return err; +} + +/* + * set named iovar given the parameter buffer + * iovar name is converted to lower case + */ +int +wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen) +{ + char smbuf[WLC_IOCTL_SMLEN*2]; + + memset(smbuf, 0, sizeof(smbuf)); + + return wlu_iovar_setbuf(wl, iovar, param, paramlen, smbuf, sizeof(smbuf)); +} + +/* + * get named iovar as an integer value + * iovar name is converted to lower case + */ +int +wlu_iovar_getint(void *wl, const char *iovar, int *pval) +{ + int ret; + + ret = wlu_iovar_get(wl, iovar, pval, sizeof(int)); + if (ret >= 0) + { + *pval = dtoh32(*pval); + } + return ret; +} + +/* + * set named iovar given an integer parameter + * iovar name is converted to lower case + */ +int +wlu_iovar_setint(void *wl, const char *iovar, int val) +{ + val = htod32(val); + return wlu_iovar_set(wl, iovar, &val, sizeof(int)); +}
diff --git a/src/wl/exe/wlu_common.h b/src/wl/exe/wlu_common.h new file mode 100644 index 0000000..2153c3d --- /dev/null +++ b/src/wl/exe/wlu_common.h
@@ -0,0 +1,72 @@ +/* + * Common code for wl routines + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_common.h 402715 2013-05-16 18:50:09Z $ + */ +#include <wlioctl.h> +#include <bcmutils.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#define stricmp strcasecmp +#define strnicmp strncasecmp + + +/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */ +/* The below macros handle endian mis-matches between wl utility and wl driver. */ +static bool g_swap = FALSE; +#define htod64(i) (g_swap?bcmswap64(i):(uint64)(i)) +#define htod32(i) (g_swap?bcmswap32(i):(uint32)(i)) +#define htod16(i) (g_swap?bcmswap16(i):(uint16)(i)) +#define dtoh64(i) (g_swap?bcmswap64(i):(uint64)(i)) +#define dtoh32(i) (g_swap?bcmswap32(i):(uint32)(i)) +#define dtoh16(i) (g_swap?bcmswap16(i):(uint16)(i)) +#define htodchanspec(i) (g_swap?htod16(i):i) +#define dtohchanspec(i) (g_swap?dtoh16(i):i) +#define htodenum(i) (g_swap?((sizeof(i) == 4) ? htod32(i) : ((sizeof(i) == 2) ? htod16(i) : i)):i) +#define dtohenum(i) (g_swap?((sizeof(i) == 4) ? dtoh32(i) : ((sizeof(i) == 2) ? htod16(i) : i)):i) + +/* command batching data structure */ +typedef struct wl_seq_cmd_pkt { + struct wl_seq_cmd_pkt *next; + wl_seq_cmd_ioctl_t cmd_header; + char * data; /* user buffer */ +} wl_seq_cmd_pkt_t; + +typedef struct wl_cmd_list { + wl_seq_cmd_pkt_t *head; + wl_seq_cmd_pkt_t *tail; +} wl_cmd_list_t; + +extern wl_cmd_list_t cmd_list; +extern int cmd_pkt_list_num; +extern bool cmd_batching_mode; + +extern int wlu_iovar_getbuf(void* wl, const char *iovar, + void *param, int paramlen, void *bufptr, int buflen); +extern int wlu_iovar_setbuf(void* wl, const char *iovar, + void *param, int paramlen, void *bufptr, int buflen); +extern int wlu_var_setbuf(void *wl, const char *iovar, void *param, int param_len); +extern int wlu_iovar_getint(void *wl, const char *iovar, int *pval); +extern void init_cmd_batchingmode(void); +extern void clean_up_cmd_list(void); +extern int wl_check(void *wl); + +extern int add_one_batched_cmd(int cmd, void *cmdbuf, int len); +extern int wlu_get_req_buflen(int cmd, void *cmdbuf, int len); +extern int wlu_get(void *wl, int cmd, void *cmdbuf, int len); +extern int wlu_set(void *wl, int cmd, void *cmdbuf, int len); +extern int wlu_iovar_get(void *wl, const char *iovar, void *outbuf, int len); +extern int wlu_iovar_set(void *wl, const char *iovar, void *param, int paramlen); +extern int wlu_iovar_getint(void *wl, const char *iovar, int *pval); +extern int wlu_iovar_setint(void *wl, const char *iovar, int val);
diff --git a/src/wl/exe/wlu_iov.c b/src/wl/exe/wlu_iov.c new file mode 100644 index 0000000..6f5633a --- /dev/null +++ b/src/wl/exe/wlu_iov.c
@@ -0,0 +1,22 @@ +/* + * Automatically generated IOVariable merge information + * $Copyright: (c) 2006, Broadcom Corp. + * All Rights Reserved.$ + * $Id: wlu_iov.c 341355 2012-06-27 13:08:42Z $ + * + * Contains user IO variable information + * Note that variable type information comes from the driver + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include <typedefs.h> +#include <bcmutils.h> +#include <wlioctl.h> + +#include "wlu.h"
diff --git a/src/wl/exe/wlu_linux.c b/src/wl/exe/wlu_linux.c new file mode 100644 index 0000000..5bd7523 --- /dev/null +++ b/src/wl/exe/wlu_linux.c
@@ -0,0 +1,1020 @@ +/* + * Linux port of wl command line utility + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_linux.c 454792 2014-02-11 20:40:19Z $ + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> +#ifndef TARGETENV_android +#include <error.h> +#endif /* TARGETENV_android */ +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <proto/ethernet.h> +#include <proto/bcmip.h> + +#ifndef TARGETENV_android +#include <linux/types.h> +#endif /* TARGETENV_android */ + +#include <linux/sockios.h> +#include <linux/ethtool.h> +#include <signal.h> +#include <typedefs.h> +#include <wlioctl.h> +#include <bcmutils.h> +#include <sys/wait.h> +#include <netdb.h> +#include <netinet/in.h> +#include "wlu.h" +#include <bcmcdc.h> +#include "wlu_remote.h" +#include "wlu_client_shared.h" +#include "wlu_pipe.h" +#ifdef NL80211 +#include "wlu_nl80211.h" +#endif /* NL80211 */ +#include <miniopt.h> + +#define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */ +#define INTERACTIVE_NUM_ARGS 15 +#define INTERACTIVE_MAX_INPUT_LENGTH 512 +#define NO_ERROR 0 +#define RWL_WIFI_JOIN_DELAY 5 + +/* Function prototypes */ +static cmd_t *wl_find_cmd(char* name); +static int do_interactive(struct ifreq *ifr); +static int wl_do_cmd(struct ifreq *ifr, char **argv); +int process_args(struct ifreq* ifr, char **argv); +extern int g_child_pid; +/* RemoteWL declarations */ +int remote_type = NO_REMOTE; +int rwl_os_type = LINUX_OS; +static bool rwl_dut_autodetect = TRUE; +static bool debug = FALSE; +extern char *g_rwl_buf_mac; +extern char* g_rwl_device_name_serial; +unsigned short g_rwl_servport; +char *g_rwl_servIP = NULL; +unsigned short defined_debug = DEBUG_ERR | DEBUG_INFO; +static uint interactive_flag = 0; +extern char *remote_vista_cmds[]; +extern char g_rem_ifname[IFNAMSIZ]; +extern int rwl_check_port_number(char *s, int len); + +#ifdef NL80211 +static void +syserr(char *s) +{ + UNUSED_PARAMETER(s); +} + +static int wl_driver_nl80211(void *wl, wl_ioctl_t *ioc) +{ + struct wl_netlink_info wl_nli; + struct ifreq *ifr = (struct ifreq *)wl; + int ret = 0; + + wl_nli.ifidx = if_nametoindex(ifr->ifr_name); + if (!wl_nli.ifidx) { + fprintf(stderr, "invalid device %s\n", ifr->ifr_name); + return BCME_IOCTL_ERROR; + } + + if (wlnl_sock_connect(&wl_nli) < 0) { + fprintf(stderr, "%s: ", wlu_av0); + perror("socket"); + exit(errno); + } + + ret = wlnl_do_testmode(&wl_nli, ioc); + wlnl_sock_disconnect(&wl_nli); + return ret; +} +#else +static void +syserr(char *s) +{ + fprintf(stderr, "%s: ", wlu_av0); + perror(s); + exit(errno); +} + +static int wl_driver_nl80211(void *wl, wl_ioctl_t *ioc) +{ + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(ioc); + return BCME_IOCTL_ERROR; +} +#endif /* NL80211 */ + +static int wl_driver_ioctl(void *wl, wl_ioctl_t *ioc) +{ + struct ifreq *ifr = (struct ifreq *) wl; + int ret; + int s; + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + syserr("socket"); + + /* do it */ + ifr->ifr_data = (caddr_t)ioc; + ret = ioctl(s, SIOCDEVPRIVATE, ifr); + + /* cleanup */ + close(s); + return ret; +} + +static int (*g_driver_io)(void *wl, wl_ioctl_t *ioc) = wl_driver_ioctl; + +int +wl_ioctl(void *wl, int cmd, void *buf, int len, bool set) +{ + wl_ioctl_t ioc; + int ret; + + /* do it */ + ioc.cmd = cmd; + ioc.buf = buf; + ioc.len = len; + ioc.set = set; + + ret = g_driver_io(wl, &ioc); + if (ret < 0) { + if (g_driver_io == wl_driver_ioctl) { + /* try using nl80211 testmode interface */ + ret = wl_driver_nl80211(wl, &ioc); + if (ret >= 0) { + g_driver_io = wl_driver_nl80211; + goto exit; + } + } + if (cmd != WLC_GET_MAGIC) + ret = BCME_IOCTL_ERROR; + } + +exit: + return ret; +} + +static int +wl_get_dev_type(char *name, void *buf, int len) +{ + int s; + int ret; + struct ifreq ifr; + struct ethtool_drvinfo info; + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + syserr("socket"); + + /* get device type */ + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GDRVINFO; + ifr.ifr_data = (caddr_t)&info; + strncpy(ifr.ifr_name, name, IFNAMSIZ); + if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) { + + /* print a good diagnostic if not superuser */ + if (errno == EPERM) + syserr("wl_get_dev_type"); + + *(char *)buf = '\0'; + } else { + strncpy(buf, info.driver, len); + } + + close(s); + return ret; +} + +static int +wl_find(struct ifreq *ifr) +{ + char proc_net_dev[] = "/proc/net/dev"; + FILE *fp; + char buf[1000], *c, *name; + char dev_type[DEV_TYPE_LEN]; + int status; + + ifr->ifr_name[0] = '\0'; + + if (!(fp = fopen(proc_net_dev, "r"))) + return BCME_ERROR; + + /* eat first two lines */ + if (!fgets(buf, sizeof(buf), fp) || + !fgets(buf, sizeof(buf), fp)) { + fclose(fp); + return BCME_ERROR; + } + + while (fgets(buf, sizeof(buf), fp)) { + c = buf; + while (isspace(*c)) + c++; + if (!(name = strsep(&c, ":"))) + continue; + strncpy(ifr->ifr_name, name, IFNAMSIZ-1); + ifr->ifr_name[IFNAMSIZ-1] = 0; + if (wl_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 && + (!strncmp(dev_type, "wl", 2) || + !strncmp(dev_type, "brc", 3))) + if (wl_check((void *) ifr) == 0) + break; + ifr->ifr_name[0] = '\0'; + } + if (ifr->ifr_name[0] == '\0') + status = BCME_ERROR; + else + status = BCME_OK; + + fclose(fp); + return status; +} + + +static int +ioctl_queryinformation_fe(void *wl, int cmd, void* input_buf, unsigned long *input_len) +{ + int error = NO_ERROR; + + if (remote_type == NO_REMOTE) { + error = wl_ioctl(wl, cmd, input_buf, *input_len, FALSE); + } else { + error = rwl_queryinformation_fe(wl, cmd, input_buf, + input_len, 0, REMOTE_GET_IOCTL); + + } + return error; +} + +static int +ioctl_setinformation_fe(void *wl, int cmd, void* buf, unsigned long *input_len) +{ + int error = 0; + + if (remote_type == NO_REMOTE) { + error = wl_ioctl(wl, cmd, buf, *input_len, TRUE); + } else { + error = rwl_setinformation_fe(wl, cmd, buf, + input_len, 0, REMOTE_SET_IOCTL); + } + + return error; +} + +int +wl_get(void *wl, int cmd, void *buf, int len) +{ + int error = 0; + unsigned long input_len = len; + + if ((rwl_os_type == WIN32_OS || rwl_os_type == WINVISTA_OS) && remote_type != NO_REMOTE) + cmd += WL_OID_BASE; + error = (int)ioctl_queryinformation_fe(wl, cmd, buf, &input_len); + + if (error == BCME_SERIAL_PORT_ERR) + return BCME_SERIAL_PORT_ERR; + else if (error == BCME_NODEVICE) + return BCME_NODEVICE; + else if (error != 0) + return BCME_IOCTL_ERROR; + + return 0; +} + +int +wl_set(void *wl, int cmd, void *buf, int len) +{ + int error = 0; + unsigned long input_len = len; + + if ((rwl_os_type == WIN32_OS || rwl_os_type == WINVISTA_OS) && remote_type != NO_REMOTE) + cmd += WL_OID_BASE; + error = (int)ioctl_setinformation_fe(wl, cmd, buf, &input_len); + + if (error == BCME_SERIAL_PORT_ERR) + return BCME_SERIAL_PORT_ERR; + else if (error == BCME_NODEVICE) + return BCME_NODEVICE; + else if (error != 0) + return BCME_IOCTL_ERROR; + + return 0; +} + +#if defined(WLMSO) +int wl_os_type_get_rwl() +{ + return rwl_os_type; +} + +void wl_os_type_set_rwl(int os_type) +{ + rwl_os_type = os_type; +} + +int wl_ir_init_rwl(void **irh) +{ + switch (rwl_get_remote_type()) { + case NO_REMOTE: + case REMOTE_WIFI: { + struct ifreq *ifr; + ifr = malloc(sizeof(struct ifreq)); + if (ifr) { + memset(ifr, 0, sizeof(ifr)); + wl_find(ifr); + } + *irh = ifr; + } + break; + default: + break; + } + + return 0; +} + +void wl_close_rwl(int remote_type, void *irh) +{ + switch (remote_type) { + case NO_REMOTE: + case REMOTE_WIFI: + free(irh); + break; + default: + break; + } +} + +#define LINUX_NUM_ARGS 16 + +static int +buf_to_args(char *tmp, char *new_args[]) +{ + char line[INTERACTIVE_MAX_INPUT_LENGTH]; + char *token; + int argc = 0; + + if (strlen(tmp) >= INTERACTIVE_MAX_INPUT_LENGTH) { + printf("wl:error: Input string too long; must be < %d bytes\n", + INTERACTIVE_MAX_INPUT_LENGTH); + return 0; + } + + strcpy(line, tmp); + while (argc < (LINUX_NUM_ARGS - 1) && + (token = strtok(argc ? NULL : line, " \t")) != NULL) { + new_args[argc] = malloc(strlen(token)+1); + strncpy(new_args[argc], token, strlen(token)+1); + argc++; + } + new_args[argc] = NULL; + if (argc == (LINUX_NUM_ARGS - 1) && (token = strtok(NULL, " \t")) != NULL) { + printf("wl:error: too many args; argc must be < %d\n", + (LINUX_NUM_ARGS - 1)); + argc = LINUX_NUM_ARGS; + } + return argc; +} + +int +wl_lib(char *input_str) +{ + struct ifreq ifr; + char *ifname = NULL; + int err = 0; + int help = 0; + int status = CMD_WL; + void* serialHandle = NULL; + char *tmp_argv[LINUX_NUM_ARGS]; + char **argv = tmp_argv; + int argc; + + /* buf_to_args return 0 if no args or string too long + * or return NDIS_NUM_ARGS if too many args + */ + if (((argc = buf_to_args(input_str, argv)) == 0) || (argc == LINUX_NUM_ARGS)) { + printf("wl:error: can't convert input string\n"); + return (-1); + } +#else +/* Main client function */ +int +main(int argc, char **argv) +{ + struct ifreq ifr; + char *ifname = NULL; + int err = 0; + int help = 0; + int status = CMD_WL; +#if defined(RWL_DONGLE) || RWL_SERIAL + void* serialHandle = NULL; +#endif + +#endif /* WLMSO */ + wlu_av0 = argv[0]; + + wlu_init(); + memset(&ifr, 0, sizeof(ifr)); + (void)*argv++; + + if ((status = wl_option(&argv, &ifname, &help)) == CMD_OPT) { + if (ifname) + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + /* Bug fix: If -h is used as an option, the above function call + * will notice it and raise the flag but it won't be processed + * in this function so we undo the argv increment so that the -h + * can be spotted by the next call of wl_option. This will ensure + * that wl -h [cmd] will function as desired. + */ + else if (help) + (void)*argv--; + } + + /* Linux client looking for a indongle reflector */ + if (*argv && strncmp (*argv, "--indongle", strlen(*argv)) == 0) { + rwl_dut_autodetect = FALSE; + (void)*argv++; + } + /* Linux client looking for a WinVista server */ + if (*argv && strncmp (*argv, "--vista", strlen(*argv)) == 0) { + rwl_os_type = WINVISTA_OS; + rwl_dut_autodetect = FALSE; + (void)*argv++; + } + + /* Provide option for disabling remote DUT autodetect */ + if (*argv && strncmp(*argv, "--nodetect", strlen(*argv)) == 0) { + rwl_dut_autodetect = FALSE; + argv++; + } + + if (*argv && strncmp (*argv, "--debug", strlen(*argv)) == 0) { + debug = TRUE; + argv++; + } + + /* RWL socket transport Usage: --socket ipaddr/hostname [port num] */ + if (*argv && strncmp (*argv, "--socket", strlen(*argv)) == 0) { + (void)*argv++; + + remote_type = REMOTE_SOCKET; + + if (!(*argv)) { + rwl_usage(remote_type); + return err; + } + /* IP address validation is done in client_shared file */ + g_rwl_servIP = *argv; + (void)*argv++; + + /* Port number validation is done in client_shared file */ + g_rwl_servport = DEFAULT_SERVER_PORT; + if ((*argv) && (rwl_check_port_number(*argv, strlen(*argv)) == SUCCESS)) { + g_rwl_servport = atoi(*argv); + (void)*argv++; + } + } + + /* RWL from system serial port on client to uart serial port on server */ + /* Usage: --serial /dev/ttyS0 */ + if (*argv && strncmp (*argv, "--serial", strlen(*argv)) == 0) { + (void)*argv++; + remote_type = REMOTE_SERIAL; + } + + /* RWL from system serial port on client to uart dongle port on server */ + /* Usage: --dongle /dev/ttyS0 */ + if (*argv && strncmp (*argv, "--dongle", strlen(*argv)) == 0) { + (void)*argv++; + remote_type = REMOTE_DONGLE; + } + +#if defined(RWL_SERIAL) || defined(RWL_DONGLE) + if (remote_type == REMOTE_SERIAL || remote_type == REMOTE_DONGLE) { + if (!(*argv)) { + rwl_usage(remote_type); + return err; + } + g_rwl_device_name_serial = *argv; + (void)*argv++; + if ((serialHandle = rwl_open_pipe(remote_type, g_rwl_device_name_serial, 0, 0)) + == NULL) { + DPRINT_ERR(ERR, "serial device open error\r\n"); + return -1; + } + ifr = (*(struct ifreq *)serialHandle); + } +#endif /* RWL_SERIAL */ + + /* RWL over wifi. Usage: --wifi mac_address */ + if (*argv && strncmp (*argv, "--wifi", strlen(*argv)) == 0) { + (void)*argv++; + /* use default interface */ + if (!*ifr.ifr_name) + wl_find(&ifr); + + /* validate the interface */ + if (!*ifr.ifr_name || (err = wl_check((void *)&ifr)) < 0) { + fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0); + exit(1); + } + + remote_type = REMOTE_WIFI; + + if (argc < 4) { + rwl_usage(remote_type); + return err; + } + /* copy server mac address to local buffer for later use by findserver cmd */ + if (!wl_ether_atoe(*argv, (struct ether_addr *)g_rwl_buf_mac)) { + fprintf(stderr, + "could not parse as an ethternet MAC address\n"); + return FAIL; + } + (void)*argv++; + } + + if ((*argv) && (strlen(*argv) > 2) && + (strncmp(*argv, "--interactive", strlen(*argv)) == 0)) { + interactive_flag = 1; + } + + /* Process for local wl */ + if (remote_type == NO_REMOTE) { + if (interactive_flag == 1) + (void)*argv--; + err = process_args(&ifr, argv); + return err; + } else { + /* Autodetect remote DUT */ + if (rwl_dut_autodetect == TRUE) + rwl_detect((void*)&ifr, debug, &rwl_os_type); + } + + /* RWL client needs to initialize ioctl_version */ + if (wl_check((void *)&ifr) != 0) { + fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0); + exit(1); + } + + if (interactive_flag == 1) { + err = do_interactive(&ifr); + return err; + } + + if ((*argv) && (interactive_flag == 0)) { + err = process_args(&ifr, argv); + if ((err == BCME_SERIAL_PORT_ERR) && (remote_type == REMOTE_DONGLE)) { + DPRINT_ERR(ERR, "\n Retry again\n"); + err = process_args((struct ifreq*)&ifr, argv); + } + return err; + } + rwl_usage(remote_type); +#if defined(RWL_DONGLE) || RWL_SERIAL + if (remote_type == REMOTE_DONGLE || remote_type == REMOTE_SERIAL) + rwl_close_pipe(remote_type, (void*)&ifr); +#endif /* RWL_DONGLE || RWL_SERIAL */ + return err; +} + +/* + * Function called for 'local' execution and for 'remote' non-interactive session + * (shell cmd, wl cmd) + */ +int +process_args(struct ifreq* ifr, char **argv) +{ + char *ifname = NULL; + int help = 0; + int status = 0; + int vista_cmd_index; + int err = 0; + cmd_t *cmd = NULL; +#ifdef RWL_WIFI + int retry; +#endif + + while (*argv) { + if ((strcmp (*argv, "sh") == 0) && (remote_type != NO_REMOTE)) { + (void)*argv++; /* Get the shell command */ + if (*argv) { + /* Register handler in case of shell command only */ + err = rwl_shell_cmd_proc((void*)ifr, argv, SHELL_CMD); + } else { + DPRINT_ERR(ERR, "Enter the shell " + "command, e.g. ls(Linux) or dir(Win CE)\n"); + err = -1; + } + return err; + } + +#ifdef RWLASD + if ((strcmp (*argv, "asd") == 0) && (remote_type != NO_REMOTE)) { + (void)*argv++; /* Get the asd command */ + if (*argv) { + err = rwl_shell_cmd_proc((void*)ifr, argv, ASD_CMD); + } else { + DPRINT_ERR(ERR, "Enter the ASD command, e.g. ca_get_version\n"); + err = -1; + } + return err; + } +#endif + if (rwl_os_type == WINVISTA_OS) { + for (vista_cmd_index = 0; remote_vista_cmds[vista_cmd_index] && + strcmp(remote_vista_cmds[vista_cmd_index], *argv); + vista_cmd_index++); + if (remote_vista_cmds[vista_cmd_index] != NULL) { + err = rwl_shell_cmd_proc((void *)ifr, argv, VISTA_CMD); + if ((remote_type == REMOTE_WIFI) && ((!strcmp(*argv, "join")))) { +#ifdef RWL_WIFI + DPRINT_INFO(OUTPUT, + "\nChannel will be synchronized by Findserver\n\n"); + sleep(RWL_WIFI_JOIN_DELAY); + for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { + if ((rwl_find_remote_wifi_server(ifr, + &g_rwl_buf_mac[0]) == 0)) { + break; + } + } +#endif /* RWL_WIFI */ + } + return err; + } + } + + if ((status = wl_option(&argv, &ifname, &help)) == CMD_OPT) { + if (help) + break; + if (ifname) { + if (remote_type == NO_REMOTE) { + strncpy((*ifr).ifr_name, ifname, IFNAMSIZ); + } + else { + strncpy(g_rem_ifname, ifname, IFNAMSIZ); + } + } + continue; + } + /* parse error */ + else if (status == CMD_ERR) + break; + + if (remote_type == NO_REMOTE) { + /* use default interface */ + if (!*(*ifr).ifr_name) + wl_find(ifr); + + /* validate the interface */ + if (!*(*ifr).ifr_name || (err = wl_check((void *)ifr)) < 0) { + fprintf(stderr, "%s: wl driver adapter not found\n", wlu_av0); + exit(1); + } + + if ((strcmp (*argv, "--interactive") == 0) || (interactive_flag == 1)) { + err = do_interactive(ifr); + return err; + } + } + /* search for command */ + cmd = wl_find_cmd(*argv); + /* if not found, use default set_var and get_var commands */ + if (!cmd) { + cmd = &wl_varcmd; + } +#ifdef RWL_WIFI + if (!strcmp(cmd->name, "findserver")) { + remote_wifi_ser_init_cmds((void *) ifr); + } +#endif /* RWL_WIFI */ + + /* RWL over Wifi supports 'lchannel' command which lets client + * (ie *this* machine) change channels since normal 'channel' command + * applies to the server (ie target machine) + */ + if (remote_type == REMOTE_WIFI) { +#ifdef RWL_WIFI + if (!strcmp(argv[0], "lchannel")) { + strcpy(argv[0], "channel"); + rwl_wifi_swap_remote_type(remote_type); + err = (*cmd->func)((void *) ifr, cmd, argv); + rwl_wifi_swap_remote_type(remote_type); + } else { + err = (*cmd->func)((void *) ifr, cmd, argv); + } + /* After join cmd's gets exeuted on the server side , client needs to know + * the channel on which the server is associated with AP , after delay of + * few seconds client will intiate the scan on diffrent channels by calling + * rwl_find_remote_wifi_server fucntion + */ + if ((!strcmp(cmd->name, "join") || ((!strcmp(cmd->name, "ssid") && + (*(++argv) != NULL))))) { + DPRINT_INFO(OUTPUT, "\n Findserver is called to synchronize the" + "channel\n\n"); + sleep(RWL_WIFI_JOIN_DELAY); + for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { + if ((rwl_find_remote_wifi_server(ifr, + &g_rwl_buf_mac[0]) == 0)) { + break; + } + } + } +#endif /* RWL_WIFI */ + } else { + /* do command */ + err = (*cmd->func)((void *) ifr, cmd, argv); + } + break; + } /* while loop end */ + +/* provide for help on a particular command */ + if (help && *argv) { + cmd = wl_find_cmd(*argv); + if (cmd) { + wl_cmd_usage(stdout, cmd); + } else { + DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n", + wlu_av0, *argv); + } + } else if (!cmd) + wl_usage(stdout, NULL); + else if (err == BCME_USAGE_ERROR) + wl_cmd_usage(stderr, cmd); + else if (err == BCME_IOCTL_ERROR) + wl_printlasterror((void *) ifr); + else if (err == BCME_NODEVICE) + DPRINT_ERR(ERR, "%s : wl driver adapter not found\n", g_rem_ifname); + + return err; +} + +/* Function called for 'local' interactive session and for 'remote' interactive session */ +static int +do_interactive(struct ifreq *ifr) +{ + int err = 0; + +#ifdef RWL_WIFI + int retry; +#endif + + while (1) { + char *fgsret; + char line[INTERACTIVE_MAX_INPUT_LENGTH]; + fprintf(stdout, "> "); + fgsret = fgets(line, sizeof(line), stdin); + + /* end of file */ + if (fgsret == NULL) + break; + if (line[0] == '\n') + continue; + + if (strlen (line) > 0) { + /* skip past first arg if it's "wl" and parse up arguments */ + char *argv[INTERACTIVE_NUM_ARGS]; + int argc; + char *token; + argc = 0; + + while (argc < (INTERACTIVE_NUM_ARGS - 1) && + (token = strtok(argc ? NULL : line, " \t\n")) != NULL) { + + /* Specifically make sure empty arguments (like SSID) are empty */ + if (token[0] == '"' && token[1] == '"') { + token[0] = '\0'; + } + + argv[argc++] = token; + } + argv[argc] = NULL; + if (argc == (INTERACTIVE_NUM_ARGS - 1) && + (token = strtok(NULL, " \t")) != NULL) { + printf("wl:error: too many args; argc must be < %d\n", + (INTERACTIVE_NUM_ARGS - 1)); + continue; + } +#ifdef RWL_WIFI + if (!strcmp(argv[0], "findserver")) { + remote_wifi_ser_init_cmds((void *) ifr); + } +#endif /* RWL_WIFI */ + + if (strcmp(argv[0], "q") == 0 || strcmp(argv[0], "exit") == 0) { + break; + } + + if ((strcmp(argv[0], "sh") == 0) && (remote_type != NO_REMOTE)) { + if (argv[1]) { + process_args(ifr, argv); + } else { + DPRINT_ERR(ERR, "Give shell command"); + continue; + } + } else { /* end shell */ + /* check for lchannel support,applicable only for wifi transport. + * when lchannel is called remote type is swapped by calling swap_ + * remote_type.This is done to change, the remote type to local, + * so that local machine's channel can be executed and + * returned to the user. + * To get back the original remote type, swap is recalled. + */ + if (remote_type == REMOTE_WIFI) { +#ifdef RWL_WIFI + if (!strcmp(argv[0], "lchannel")) { + strcpy(argv[0], "channel"); + rwl_wifi_swap_remote_type(remote_type); + err = wl_do_cmd(ifr, argv); + rwl_wifi_swap_remote_type(remote_type); + } else { + err = wl_do_cmd(ifr, argv); + } + /* After join cmd's gets exeuted on the server side, client + * needs to know the channel on which the server is associated + * with AP , after delay of few seconds client will intiate the + * scan on diffrent channels by calling + * rwl_find_remote_wifi_server function + */ + if ((!strcmp(argv[0], "join")) || + (!strcmp(argv[0], "ssid"))) { + DPRINT_INFO(OUTPUT, "\n Findserver is called" + "after the join issued to remote \n \n"); + sleep(RWL_WIFI_JOIN_DELAY); + for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { + if ((rwl_find_remote_wifi_server(ifr, + &g_rwl_buf_mac[0]) == 0)) { + break; + } + } + } +#endif /* RWL_WIFI */ + } else { + err = wl_do_cmd(ifr, argv); + } + } /* end of wl */ + } /* end of strlen (line) > 0 */ + } /* while (1) */ + + return err; +} + +/* + * find command in argv and execute it + * Won't handle changing ifname yet, expects that to happen with the --interactive + * Return an error if unable to find/execute command + */ +static int +wl_do_cmd(struct ifreq *ifr, char **argv) +{ + cmd_t *cmd = NULL; + int err = 0; + int help = 0; + char *ifname = NULL; + int status = CMD_WL; + + /* skip over 'wl' if it's there */ + if (*argv && strcmp (*argv, "wl") == 0) { + argv++; + } + + /* handle help or interface name changes */ + if (*argv && (status = wl_option (&argv, &ifname, &help)) == CMD_OPT) { + if (ifname) { + fprintf(stderr, + "Interface name change not allowed within --interactive\n"); + } + } + + /* in case wl_option eats all the args */ + if (!*argv) { + return err; + } + + if (status != CMD_ERR) { + /* search for command */ + cmd = wl_find_cmd(*argv); + + /* defaults to using the set_var and get_var commands */ + if (!cmd) { + cmd = &wl_varcmd; + } + /* do command */ + err = (*cmd->func)((void *)ifr, cmd, argv); + } + /* provide for help on a particular command */ + if (help && *argv) { + cmd = wl_find_cmd(*argv); + if (cmd) { + wl_cmd_usage(stdout, cmd); + } else { + DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n", + wlu_av0, *argv); + } + } else if (!cmd) + wl_usage(stdout, NULL); + else if (err == BCME_USAGE_ERROR) + wl_cmd_usage(stderr, cmd); + else if (err == BCME_IOCTL_ERROR) + wl_printlasterror((void *)ifr); + else if (err == BCME_NODEVICE) + DPRINT_ERR(ERR, "%s : wl driver adapter not found\n", g_rem_ifname); + + return err; +} + +/* Search the wl_cmds table for a matching command name. + * Return the matching command or NULL if no match found. + */ +static cmd_t * +wl_find_cmd(char* name) +{ + cmd_t *cmd = NULL; + + /* search the wl_cmds for a matching name */ + for (cmd = wl_cmds; cmd->name && strcmp(cmd->name, name); cmd++); + + if (cmd->name == NULL) + cmd = NULL; + + return cmd; +} + +void def_handler(int signum) +{ + UNUSED_PARAMETER(signum); + kill(g_child_pid, SIGINT); + kill(getpid(), SIGINT); + exit(0); +} +/* Create a child that waits for Ctrl-C at the client side + */ +int rwl_shell_createproc(void *wl) +{ + UNUSED_PARAMETER(wl); + signal(SIGINT, ctrlc_handler); + signal(SIGTERM, def_handler); + signal(SIGABRT, def_handler); + return fork(); +} + +/* In case if the server shell command exits normally + * then kill the thread that was waiting for Ctr-C to happen + * at the client side + */ +void rwl_shell_killproc(int pid) +{ + kill(pid, SIGKILL); + signal(SIGINT, SIG_DFL); + wait(NULL); +} +#ifdef RWL_SOCKET +/* to validate hostname/ip given by the client */ +int validate_server_address() +{ + struct hostent *he; + struct ipv4_addr temp; + if (!wl_atoip(g_rwl_servIP, &temp)) { + /* Wrong IP address format check for hostname */ + if ((he = gethostbyname(g_rwl_servIP)) != NULL) { + if (!wl_atoip(*he->h_addr_list, &temp)) { + g_rwl_servIP = + inet_ntoa(*(struct in_addr *)*he->h_addr_list); + if (g_rwl_servIP == NULL) { + DPRINT_ERR(ERR, "Error at inet_ntoa \n"); + return FAIL; + } + } else { + DPRINT_ERR(ERR, "Error in IP address \n"); + return FAIL; + } + } else { + DPRINT_ERR(ERR, "Enter correct IP address/hostname format\n"); + return FAIL; + } + } + return SUCCESS; +} +#endif /* RWL_SOCKET */
diff --git a/src/wl/exe/wlu_pipe.c b/src/wl/exe/wlu_pipe.c new file mode 100644 index 0000000..a8d5580 --- /dev/null +++ b/src/wl/exe/wlu_pipe.c
@@ -0,0 +1,1068 @@ +/* + * Common Functionality for pipe + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_pipe.c 363727 2012-10-19 02:21:29Z $ + */ +#ifdef WIN32 +#define NEED_IR_TYPES + +#include <windows.h> +#include <epictrl.h> +#include <irelay.h> +#endif /* WIN32 */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <netdb.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <wlioctl.h> +#include <net/if.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#ifdef TARGETOS_symbian +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#else +#include <malloc.h> +#endif /* TARGETOS_symbian */ +#include <typedefs.h> +#include <wlioctl.h> + +#include <proto/ethernet.h> +#include <bcmendian.h> +#include <bcmutils.h> +#include <bcmcdc.h> +#include <proto/802.11.h> +#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR) +#include <rwl_wifi.h> +#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */ +#include "wlu.h" +#include "wlu_remote.h" + +static rem_ioctl_t rem_cdc; +char *g_rwl_device_name_serial = ""; +bool g_rwl_swap = FALSE; +char g_rem_ifname[IFNAMSIZ] = "\0"; +int need_speedy_response; /* Indicate findserver is checking channels */ + + /* Linux 100 usec */ +#define SYNC_TIME 100 + +#define UART_FIFO_LEN 64 +#define END_OF_PACK_SEP_LEN 2 +#define INIT_CMD_SLEEP 500 +#define dtoh32(i) i + +/* dword align allocation */ +union { + uchar bufdata[ETHER_ADDR_LEN]; + uint32 alignme; +} bufmac_wlu; +char *g_rwl_buf_mac = (char*) &bufmac_wlu.bufdata; + +#ifdef RWL_WIFI +/* dword align allocation */ +union { + uchar shelldata[WL_MAX_BUF_LEN]; + uint32 alignme; +} shell_wlu; +char *g_rwl_buf_shell = (char*) &shell_wlu.shelldata; +int rwl_find_remote_wifi_server(void *wl, char *id); +int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set); + +/* + * This function runs a set of commands before running the wi-fi server + * This is avoids packet drops and improves performance. + * We run the following wl commands + * up, mpc 0, wsec 0, slow_timer 999999, fast_timer 999999, glacial_timer 999999 + * legacylink 1, monitor 1. + */ +void remote_wifi_ser_init_cmds(void *wl) +{ + int err; + char bigbuf[RWL_WIFI_BUF_LEN]; + uint len = 0, count; + /* The array stores command, length and then data format */ + remote_wifi_cmds_t wifi_cmds[] = { + {WLC_UP, NULL, 0x0}, + {WLC_SET_VAR, "mpc", 0}, + {WLC_SET_WSEC, NULL, 0x0}, + {WLC_SET_VAR, "slow_timer", 999999}, + {WLC_SET_VAR, "fast_timer", 999999}, + {WLC_SET_VAR, "glacial_timer", 999999}, + {WLC_SET_MONITOR, NULL, 0x1}, + {WLC_SET_PM, NULL, 0x0} + }; + + for (count = 0; count < ARRAYSIZE(wifi_cmds); count++) { + + if (wifi_cmds[count].data == NULL) + len = sizeof(int); + else + len = strlen(wifi_cmds[count].data) + 1 + sizeof(int); + + /* If the command length exceeds the buffer length continue + * executing the next command + */ + if (len > sizeof(bigbuf)) { + DPRINT_ERR(ERR, "Err: command len exceeds buf len. Check" + "initialization cmds\n"); + continue; + } + + if (wifi_cmds[count].data != NULL) { + strcpy(bigbuf, wifi_cmds[count].data); + memcpy(&bigbuf[strlen(wifi_cmds[count].data)+1], + (char*)&wifi_cmds[count].value, sizeof(int)); + } else { + memcpy(&bigbuf[0], (char*)&wifi_cmds[count].value, sizeof(int)); + } +#ifdef WIN32 + /* Add OID base for NDIS commands */ + + err = (int)ir_setinformation(wl, wifi_cmds[count].cmd + WL_OID_BASE, + bigbuf, &len); +#endif + + if (wifi_cmds[count].cmd == WLC_UP) + /* NULL needs to be passed to the driver if WL UP command needs to + * be executed Otherwise driver hangs + */ + err = wl_ioctl(wl, wifi_cmds[count].cmd, + NULL, 0, TRUE); + else + err = wl_ioctl(wl, wifi_cmds[count].cmd, + (void*)&bigbuf, len, TRUE); + rwl_sleep(INIT_CMD_SLEEP); + } + BCM_REFERENCE(err); +} + +/* When user wants to execute local CMD being in remote wifi mode, this fucntion is used + * to change the remote types. + * This fucntion is called to swap the remote type to execute the cmd using the local + * driver interface. + * This is required for to call proper front end fucntions to achive the local set/get ioctl. + */ +void +rwl_wifi_swap_remote_type(int flag) +{ + static int remote_flag; + if (flag == REMOTE_WIFI) { + remote_type = NO_REMOTE; + remote_flag = flag; + } else if (remote_flag == REMOTE_WIFI) { + remote_type = remote_flag; + remote_flag = flag; + } + return; +} + +void +rwl_wifi_free_list(dot11_action_wifi_vendor_specific_t *list[]) +{ + int i; + for (i = 0; i < RWL_DEFAULT_WIFI_FRAG_COUNT; i++) { + if (list[i]) + free(list[i]); + } +} + +/* + * Configures local channel for finding server. + * Server call this fucntion for getting its current channel, + * client uses this fucntion for setting its channel to new channel. + */ +static int +rwl_wifi_config_channel(void *wl, int cmd, int *channel) +{ + int error; + channel_info_t ci; + error = -1; + /* Get functionality is used only by server */ + if (cmd == WLC_GET_CHANNEL) { + memset((char*)&ci, 0, sizeof(ci)); + if ((error = wl_get(wl, cmd, &ci, sizeof(channel_info_t))) < 0) + return error; + ci.hw_channel = dtoh32(ci.hw_channel); + ci.scan_channel = dtoh32(ci.scan_channel); + ci.target_channel = dtoh32(ci.target_channel); + if (ci.scan_channel) { + printf("Scan in progress.\n"); + } + *channel = ci.hw_channel; + } + + if (cmd == WLC_SET_CHANNEL) { + /* Set functionality is used by the client */ + ci.target_channel = *channel; + /* When user wants to execute local CMD being in remote wifi mode, + * rwl_wifi_swap_remote_type fucntion is used to change the remote types. + */ + rwl_wifi_swap_remote_type(remote_type); + error = wl_set(wl, cmd, &ci.target_channel, sizeof(int)); + /* rever it back to same old remote type */ + rwl_wifi_swap_remote_type(remote_type); + } + return error; +} +/* +allocate the memory for action frame and update with wifi tranport header. +*/ +dot11_action_wifi_vendor_specific_t * +rwl_wifi_allocate_actionframe() +{ + dot11_action_wifi_vendor_specific_t *action_frame; + + if ((action_frame = (dot11_action_wifi_vendor_specific_t *) + malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) { + DPRINT_ERR(ERR, "rwl_wifi_allocate_actionframe: unable to allocate frame \n"); + return action_frame; + } + action_frame->category = RWL_ACTION_WIFI_CATEGORY; + action_frame->OUI[0] = RWL_WIFI_OUI_BYTE0; + action_frame->OUI[1] = RWL_WIFI_OUI_BYTE1; + action_frame->OUI[2] = RWL_WIFI_OUI_BYTE2; + action_frame->type = RWL_WIFI_DEFAULT_TYPE; + action_frame->subtype = RWL_WIFI_DEFAULT_SUBTYPE; + + return action_frame; +} +/* + * Send the valid action frame (CDC+DATA) through the REF driver interface. + * if the CMD is "findserver" then "findmypeer" frames are sent on the diffrent + * channels to reconnect + * to with server. Other wl cmd takes the normal path. + * parameter 3 , i.e. buf contains the cmd line arguments and buf_len is the actual + * length of the buf. data_len is the length of the actual data to be sent to remote server. + */ +int +remote_CDC_wifi_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags) +{ + rem_ioctl_t *rem_ptr = &rem_cdc; + int error, read_try; + dot11_action_wifi_vendor_specific_t *rem_wifi_send; + + /* prepare CDC header */ + rem_ptr->msg.cmd = cmd; + rem_ptr->msg.len = buf_len; + rem_ptr->msg.flags = flags; + rem_ptr->data_len = data_len; + if (strlen(g_rem_ifname) != 0) + strncpy(rem_ptr->intf_name, g_rem_ifname, (int)IFNAMSIZ); + rwl_swap_header(rem_ptr, HOST_TO_NETWORK); + + if ((data_len > buf_len)) { + DPRINT_ERR(ERR, "remote_CDC_wifi_tx: data_len (%d) > buf_len (%d)\n", + data_len, buf_len); + return (FAIL); + } + /* client will not send data greater than RWL_WIFI_FRAG_DATA_SIZE to server, + * this condition should not be hit on client side, when sending the cmd + * to remote server + */ + if (data_len > RWL_WIFI_FRAG_DATA_SIZE) + DPRINT_DBG(OUTPUT, "data size exceeds data_len %d\n", rem_ptr->msg.len); + + if ((buf != NULL) && (strlen((char*)buf) >= (sizeof(RWL_WIFI_FIND_SER_CMD)-1)) && + (!strcmp((char*)buf, RWL_WIFI_FIND_SER_CMD))) { + /* This is special case for wifi, when user wants to findserver, + * client has to execute it locally.Find the channel on the on + * which DUT is operating and sync up with specified MAC address, + * retry if fails to find the server + */ + for (read_try = 0; read_try < RWL_WIFI_RETRY; read_try++) { + if (((error = rwl_find_remote_wifi_server(wl, + &g_rwl_buf_mac[0])) == 0)) { + break; + } + } + return error; + } + + if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) { + DPRINT_ERR(ERR, "remote_CDC_wifi_tx: Failed to allocate memory\n"); + return (FAIL); + } + /* only data length needs to be sent to remote server using this function + * This function is only meant for client to send data to server + * Copy the CDC header and data to action frame data feild + * Now we have encapsulated the CDC header and data completely to in the + * action frame. + */ + memcpy((void*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET], + (char*)rem_ptr, REMOTE_SIZE); + if (buf != NULL) { + memcpy((void*)&rem_wifi_send->data[REMOTE_SIZE], buf, data_len); + } + + /* Send the action frame to remote server using the rwl_var_setbuf fucntion, + * which will use the local driver interface to send this frame on the air + */ + if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send, + RWL_WIFI_ACTION_FRAME_SIZE)) < 0) { + DPRINT_ERR(ERR, "Unable to read the action frame %d error\n", error); + } + free(rem_wifi_send); + return error; +} + +/* + * Read the valid action frame through the REF/DUT driver interface. + * Retry for no of times, wait for action frame for the specified time. + */ +int +remote_CDC_DATA_wifi_rx(void *wl, dot11_action_wifi_vendor_specific_t * rec_frame) +{ + int error, read_try; + void *ptr = NULL; + + + /* retry is to ensure to read late arrival action frame */ + for (read_try = 0; read_try < RWL_WIFI_RX_RETRY; read_try++) { + /* read the action frame queued in the local driver wifi queue */ + if ((error = rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, rec_frame, + RWL_WIFI_ACTION_FRAME_SIZE, &ptr)) < 0) { + DPRINT_ERR(ERR, "remote_CDC_DATA_wifi_rx: Error in reading the frame %d\n", + error); + return error; + } + /* copy the read action frame to the user frame and cjheck for the action category. + * If the action category matches with RWL_ACTION_WIFI_CATEGORY , + * then its the valid frame, otherwise ignore it. + */ + memcpy((char*)rec_frame, ptr, RWL_WIFI_ACTION_FRAME_SIZE); + + if (rec_frame->category == RWL_ACTION_WIFI_CATEGORY) { + break; + } else { + /* If we are executing findserver then sleep less */ + if (!need_speedy_response) + rwl_sleep(RWL_WIFI_RX_DELAY); + else + rwl_sleep(RWL_CHANNEL_RX_SCAN_DELAY); + } + } + /* If failed to get the valid frame , indicate the error */ + if (!(rec_frame->category == RWL_ACTION_WIFI_CATEGORY)) { + return (FAIL); + } + return error; +} +/* + * read data that has reached client in fragments. If the functtion is + * called from rwl_shell_information_fe then the flag will be set to 1. + * For shell response this function will output the response on the standard interface. + * Response will be coming in out of order , this fucntion will make it inorder. + * Duplicate action frames are ignored. + */ +int +remote_CDC_DATA_wifi_rx_frag(void *wl, rem_ioctl_t *rem_ptr, uint input_len, +void *input, bool shell) +{ + int error, totalfrag, seq_num, num_frags, remainingbytes; + dot11_action_wifi_vendor_specific_t *rec_frame; + uchar *input_buf = (uchar*)input; + /* An array of pointers to each recieved frag */ + dot11_action_wifi_vendor_specific_t *master_list[RWL_DEFAULT_WIFI_FRAG_COUNT]; + + UNUSED_PARAMETER(input_len); + remainingbytes = 0; + + memset(master_list, 0, sizeof(master_list)); + /* in case of shell cmd's receive size is unknown */ + if (shell) { + input_buf = (uchar*)g_rwl_buf_shell; + memset(input_buf, 0, WL_MAX_BUF_LEN); + } + + /* We don't yet know how many fragments we will need to read since the + length is contained in the first frgment of the message itself. Set + totalfrag to an arbitry large number and we will readjust it after we + successfully recieve the first frag. + */ + totalfrag = RWL_DEFAULT_WIFI_FRAG_COUNT; + + for (num_frags = 0; num_frags <= totalfrag; num_frags++) { + if ((rec_frame = rwl_wifi_allocate_actionframe()) == NULL) { + DPRINT_DBG(OUTPUT, "malloc failure\n"); + rwl_wifi_free_list(master_list); + return (FAIL); + } + if ((error = remote_CDC_DATA_wifi_rx((void*)wl, rec_frame)) < 0) { + free(rec_frame); + rwl_wifi_free_list(master_list); + return FAIL; + } + + if (rec_frame->subtype >= RWL_DEFAULT_WIFI_FRAG_COUNT) { + DPRINT_DBG(OUTPUT, " Read bogus subtype %d\n", rec_frame->subtype); + free(rec_frame); + continue; + } + /* Keep only originals and discard any dup frags */ + if (!master_list[rec_frame->subtype]) { + master_list[rec_frame->subtype] = rec_frame; + } else { + num_frags--; + free(rec_frame); + } + + /* Look for first frag so we can accurately calculate totalfrag */ + if (rec_frame->subtype == RWL_WIFI_DEFAULT_SUBTYPE) { + memcpy((char*)rem_ptr, + (char*)&master_list[rec_frame->subtype]-> + data[RWL_WIFI_CDC_HEADER_OFFSET], REMOTE_SIZE); + rwl_swap_header(rem_ptr, NETWORK_TO_HOST); + totalfrag = rem_ptr->msg.len / RWL_WIFI_FRAG_DATA_SIZE; + remainingbytes = rem_ptr->msg.len % RWL_WIFI_FRAG_DATA_SIZE; + } + } + + /* All frags are now read and there are no dups. Check for missing frags */ + for (seq_num = 0; seq_num < totalfrag; seq_num++) { + if (!master_list[seq_num]) { + DPRINT_DBG(OUTPUT, "Missing frag number %d\n", seq_num); + rwl_wifi_free_list(master_list); + return (FAIL); + } + } + /* + case 1: response in one frame i.e if (totalfrag==0) + case 2: response in multiple frame ( multiple of RWL_WIFI_FRAG_DATA_SIZE) + case 3: response in multiple frame and not in multiple of RWL_WIFI_FRAG_DATA_SIZE + */ + + /* case 1: Check for the response in single frame */ + if (totalfrag == 0) + memcpy((char*)&input_buf[0], + (char*)&master_list[0]->data[REMOTE_SIZE], rem_ptr->msg.len); + else /* case 2: Copy fragments into contiguous frame */ + memcpy((char*)&input_buf[0], + (char*)&master_list[0]->data[REMOTE_SIZE], RWL_WIFI_FRAG_DATA_SIZE); + + /* + * If all the frames are recieved , copy them to a contigues buffer + */ + for (seq_num = 1; seq_num < totalfrag; seq_num++) { + memcpy((char*)&input_buf[seq_num*RWL_WIFI_FRAG_DATA_SIZE], + (char*)&master_list[seq_num]->data, RWL_WIFI_FRAG_DATA_SIZE); + } + + /* case 3 : if response is in fragments and valid data in the last frame is less + * than RWL_WIFI_FRAG_DATA_SIZE + */ + if (remainingbytes && (totalfrag > 0)) + memcpy((char*)&input_buf[seq_num*RWL_WIFI_FRAG_DATA_SIZE], + (char*)&master_list[seq_num]->data, remainingbytes); + + if (shell) { + write(1, (char*)input_buf, strlen((char*)input_buf)); + } + + rwl_wifi_free_list(master_list); + return error; +} +/* + * read out all the action frame which are queued in the driver even + * before issuing any wl cmd. This is essential because due to late arrival of frame it can + * get queued after the read expires. + */ +void +rwl_wifi_purge_actionframes(void *wl) +{ + dot11_action_wifi_vendor_specific_t *rec_frame; + void *ptr = NULL; + + if ((rec_frame = (dot11_action_wifi_vendor_specific_t *) + malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) { + DPRINT_DBG(OUTPUT, "Purge Error in reading the frame \n"); + return; + } + + for (;;) { + if (rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, rec_frame, + RWL_WIFI_ACTION_FRAME_SIZE, &ptr) < 0) { + DPRINT_DBG(OUTPUT, "rwl_wifi_purge_actionframes:" + "Purge Error in reading the frame \n"); + break; + } + memcpy((char*)rec_frame, ptr, RWL_WIFI_ACTION_FRAME_SIZE); + + if ((rec_frame->category != RWL_ACTION_WIFI_CATEGORY)) + break; + } + + free(rec_frame); + + return; +} +/* + * check for the channel of remote and respond if it matches with its current + * channel. Once the server gets the handshake cmd, it will check the channel + * number of the remote with its channel and if it matches , then it send out the + * ack to the remote client. This fucntion is used only by the server. + */ +void +rwl_wifi_find_server_response(void *wl, dot11_action_wifi_vendor_specific_t *rec_frame) +{ + int error, send, server_channel; + + if (rec_frame->type == RWL_WIFI_FIND_MY_PEER) { + + rec_frame->type = RWL_WIFI_FOUND_PEER; + /* read channel on of the SERVER */ + rwl_wifi_config_channel(wl, WLC_GET_CHANNEL, &server_channel); + /* overlapping channel not supported, + so server will only respond to client on the channel of the client + */ + if (rec_frame->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET] == server_channel) { + /* send the response by updating server channel in the frame */ + rec_frame->data[RWL_WIFI_SERVER_CHANNEL_OFFSET] = server_channel; + /* change the TYPE feild for giving the ACK */ + for (send = 0; send < RWL_WIFI_SEND; send++) { + if ((error = rwl_var_send_vs_actionframe(wl, + RWL_WIFI_ACTION_CMD, + rec_frame, + RWL_WIFI_ACTION_FRAME_SIZE)) < 0) { + DPRINT_ERR(ERR, "rwl_wifi_find_server_response: Failed" + "to Send the Frame %d\n", error); + break; + } + rwl_sleep(RWL_WIFI_SEND_DELAY); + } + } + } + return; +} +/* + * This function is used by client only. Sends the finmypeer sync frame to remote + * server on diffrent channels and waits for the response. + */ +int +rwl_find_remote_wifi_server(void *wl, char *id) +{ + dot11_action_wifi_vendor_specific_t *rem_wifi_send, *rem_wifi_recv; + rem_ioctl_t *rem_ptr = &rem_cdc; + /* This list is generated considering valid channel and if this + * may requires updation or deletion. This needs to be identified. + * we have assumed that server band is not known and considered all band channels. + */ + int wifichannel[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 36, 40, 44, 48, 149, 153, 157, 161, 165}; + int i, error, schannel, channel_count; + struct ether_addr * curr_macaddr; + int ret; + need_speedy_response = TRUE; + + if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) { + DPRINT_ERR(ERR, " rwl_find_remote_wifi_server : Failed to allocate \n"); + return FAIL; + } + if ((rem_wifi_recv = rwl_wifi_allocate_actionframe()) == NULL) { + DPRINT_ERR(ERR, " rwl_find_remote_wifi_server : Failed to allocate\n"); + free(rem_wifi_send); + return FAIL; + } + + channel_count = sizeof(wifichannel) / sizeof(int); + + /* make dummy read to make sure we don't read the already queued + * actionframes against the cmd we issue + */ + rwl_wifi_purge_actionframes(wl); + + /* update the client sync specifier */ + rem_wifi_send->type = RWL_WIFI_FIND_MY_PEER; + /* update the CDC flag to indicate it is handshake frame */ + rem_ptr->msg.cmd = 0; + /* cmd =0 ,this will be ignored when server receive frame + * with REMOTE_FINDSERVER_IOCTL flag + */ + rem_ptr->msg.len = RWL_WIFI_FRAG_DATA_SIZE; + rem_ptr->msg.flags = REMOTE_FINDSERVER_IOCTL; + rem_ptr->data_len = RWL_WIFI_FRAG_DATA_SIZE; + rwl_swap_header(rem_ptr, HOST_TO_NETWORK); + + memcpy((char*)&rem_wifi_send->data, (char*)rem_ptr, REMOTE_SIZE); + /* copy server mac to which ref driver needs to send unicast action frame */ + memcpy((char*)&rem_wifi_send->data[RWL_REF_MAC_ADDRESS_OFFSET], &id[0], ETHER_ADDR_LEN); + + if ((ret = rwl_var_getbuf(wl, "cur_etheraddr", NULL, 0, (void**) &curr_macaddr)) < 0) { + DPRINT_ERR(ERR, "Error getting current Mac addr \n"); + return FAIL; + } + + memcpy((char*)&rem_wifi_send->data[RWL_DUT_MAC_ADDRESS_OFFSET], (char*)curr_macaddr->octet, + ETHER_ADDR_LEN); + /* Start with the channel in the list and keep changing till the server + * responds or channels list ends + */ + for (i = 0; i < channel_count; i++) { + DPRINT_INFO(OUTPUT, "Scanning Channel: %d ...\n", wifichannel[i]); + if ((error = rwl_wifi_config_channel(wl, WLC_SET_CHANNEL, + &wifichannel[i])) < 0) { + DPRINT_ERR(ERR, " Failed to set the specified channel %d\n", + wifichannel[i]); + break; + } + /* send channel detail of client to server */ + rem_wifi_send->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET] = wifichannel[i]; + + if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send, + RWL_WIFI_ACTION_FRAME_SIZE)) < 0) { + DPRINT_DBG(OUTPUT, "Failed to Send the Frame %d\n", error); + break; + } + /* read the server response on the same channel */ + if ((error = remote_CDC_DATA_wifi_rx(wl, rem_wifi_recv)) < 0) { + rwl_sleep(RWL_CHANNEL_SCAN_WAIT); + continue; + } + /* Verify for the Type RWL_WIFI_FOUND_PEER */ + if (rem_wifi_recv->type == RWL_WIFI_FOUND_PEER) { + if (rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET] == + rem_wifi_recv->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET]) { + + DPRINT_INFO(OUTPUT, "Server is on channel # %d\n", + rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET]); + + schannel = rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET]; + /* Set the back to the channel on which REF was originally */ + if ((error = rwl_wifi_config_channel(wl, + WLC_SET_CHANNEL, &schannel) < 0)) { + DPRINT_ERR(ERR, "Failed to set the specified" + "channel %d\n", schannel); + } else { + DPRINT_ERR(ERR, "REF now moved to the" + "channel of server # %d\n", schannel); + } + need_speedy_response = FALSE; + /* we are done here, end the loop */ + break; + } else { + DPRINT_INFO(OUTPUT, "Server is operating on diffrent channel." + "continue scanning\n"); + } + } + /* before chaning the channel of client and sending sync frame + * wait for while and send + */ + rwl_sleep(RWL_CHANNEL_SCAN_WAIT); + } + need_speedy_response = FALSE; + + free(rem_wifi_send); + free(rem_wifi_recv); + return error; +} +#endif /* RWL_WIFI */ +#ifdef RWL_DONGLE +static int +remote_CDC_tx_dongle(void *wl, rem_ioctl_t *rem_ptr, uchar *buf) +{ + unsigned long numwritten; + char end_of_packet[END_OF_PACK_SEP_LEN] = "\n\n"; + uchar loc_buf[UART_FIFO_LEN]; + uint len = END_OF_PACK_SEP_LEN; + uint noframes, frame_count, rem_bytes; + uint n_bytes; + uint data_len; + + /* Converting the CDC header with keyword 'rwl ' in ascii format + * as dongle UART understands only ascii format. + * In dongle UART driver CDC structure is made from the ascii data + * it received. + */ + sprintf((char*)loc_buf, "rwl %d %d %d %d ", rem_ptr->msg.cmd, rem_ptr->msg.len, + rem_ptr->msg.flags, rem_ptr->data_len); + n_bytes = strlen((char*)loc_buf); + + data_len = ltoh32(rem_ptr->data_len); + DPRINT_DBG(OUTPUT, "rwl %x %d %d %d ", ltoh32(rem_ptr->msg.cmd), ltoh32(rem_ptr->msg.len), + ltoh32(rem_ptr->msg.flags), data_len); + DPRINT_DBG(OUTPUT, "CDC Header:No of bytes to be sent=%d\n", n_bytes); + DPRINT_DBG(OUTPUT, "Data:No of bytes to be sent=%d\n", data_len); + + /* Send the CDC Header */ + if (rwl_write_serial_port(wl, (char*)loc_buf, n_bytes, &numwritten) < 0) { + DPRINT_ERR(ERR, "CDC_Tx: Header: Write failed\n"); + DPRINT_ERR(ERR, "CDC_Tx: Header: numwritten %ld != n_bytes %d\n", + numwritten, n_bytes); + return (FAIL); + } + + /* Dongle UART FIFO len is 64 bytes and flow control is absent. + * While transmitting large chunk of data the data was getting lost + * at UART driver so for large chunk of data 64 bytes are sent at a time + * folowed by delay and then next set of 64 bytes and so on. + * For data which is less than 64 bytes it is sent in one shot + */ + + noframes = rem_ptr->data_len/UART_FIFO_LEN; + if (noframes == 0) { + /* Send the data now */ + if (rwl_write_serial_port(wl, (char*)buf, rem_ptr->data_len, &numwritten) < 0) { + DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n"); + DPRINT_ERR(ERR, "Data_Tx: Header: numwritten %ld != len %d\n", + numwritten, rem_ptr->data_len); + return (FAIL); + } + + } else { + if (rem_ptr->data_len % UART_FIFO_LEN == 0) { + rem_bytes = UART_FIFO_LEN; + } else { + rem_bytes = rem_ptr->data_len % UART_FIFO_LEN; + noframes += 1; + } + + for (frame_count = 0; frame_count < noframes; frame_count++) { + if (frame_count != noframes-1) { + memcpy(loc_buf, (char*)(&buf[frame_count*UART_FIFO_LEN]), + UART_FIFO_LEN); + /* Send the data now */ + if (rwl_write_serial_port(wl, (char*)loc_buf, UART_FIFO_LEN, + &numwritten) == -1) { + DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n"); + return (-1); + } + + } else { + memcpy(loc_buf, (char*)(&buf[frame_count*UART_FIFO_LEN]), + rem_bytes); + + if (rwl_write_serial_port(wl, (char*)loc_buf, rem_bytes, + &numwritten) == -1) { + DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n"); + return (-1); + } + + } + rwl_sleep(SYNC_TIME); + } + } + + /* Send end of packet now */ + if (rwl_write_serial_port(wl, end_of_packet, len, &numwritten) == -1) { + DPRINT_ERR(ERR, "CDC_Tx: Header: Write failed\n"); + DPRINT_ERR(ERR, "CDC_Tx: Header: numwritten %ld != len %d\n", + numwritten, len); + return (FAIL); + } + + DPRINT_DBG(OUTPUT, "Packet sent!\n"); + + /* Return size of actual buffer to satisfy accounting going on above this level */ + return (ltoh32(rem_ptr->msg.len)); +} +#endif /* RWL_DONGLE */ + +#if defined(RWL_SERIAL) || defined(RWL_DONGLE)|| defined(RWL_SOCKET) +void * +rwl_open_pipe(int remote_type, char *port, int ReadTotalTimeout, int debug) +{ + return rwl_open_transport(remote_type, port, ReadTotalTimeout, debug); +} + +int +rwl_close_pipe(int remote_type, void* handle) +{ + return rwl_close_transport(remote_type, handle); +} +#endif + +int +remote_CDC_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags, int debug) +{ +#ifdef RWL_SERIAL + unsigned long numwritten = 0; +#endif + rem_ioctl_t *rem_ptr = &rem_cdc; +#ifdef RWL_WIFI + int error; + uint totalframes, tx_count; + dot11_action_wifi_vendor_specific_t *rem_wifi_send; +#endif + UNUSED_PARAMETER(debug); + UNUSED_PARAMETER(buf); + UNUSED_PARAMETER(wl); + + memset(rem_ptr, 0, sizeof(rem_ioctl_t)); + rem_ptr->msg.cmd = cmd; + rem_ptr->msg.len = buf_len; + rem_ptr->msg.flags = flags; + rem_ptr->data_len = data_len; + if (strlen(g_rem_ifname) != 0) + strncpy(rem_ptr->intf_name, g_rem_ifname, (int)IFNAMSIZ); + rwl_swap_header(rem_ptr, HOST_TO_NETWORK); + if (data_len > buf_len) { + DPRINT_ERR(ERR, "remote_CDC_tx: data_len (%d) > buf_len (%d)\n", data_len, buf_len); + return (FAIL); + } +#ifdef RWL_SERIAL + if (remote_type == REMOTE_SERIAL) { + int ret; + /* Send CDC header first */ + if ((ret = rwl_write_serial_port(wl, (char *)rem_ptr, + REMOTE_SIZE, &numwritten)) == -1) { + DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n"); + return (FAIL); + } + numwritten = ret; + + /* Send data second */ + if ((ret = rwl_write_serial_port(wl, (char*)buf, + data_len, &numwritten)) == -1) { + DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n"); + return (FAIL); + } + numwritten = ret; + + return (buf_len); + } +#endif /* RWL_SERIAL */ +#ifdef RWL_DONGLE + if (remote_type == REMOTE_DONGLE) { + return (remote_CDC_tx_dongle(wl, rem_ptr, buf)); + } +#endif /* RWL_DONGLE */ +#ifdef RWL_SOCKET + if (remote_type == REMOTE_SOCKET) { + int ret; + + /* Send CDC header first */ + if ((ret = rwl_send_to_streamsocket(*(int*)wl, (char *)rem_ptr, + REMOTE_SIZE, 0)) == -1) { + DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n"); + return (FAIL); + } + + /* Send data second */ + if ((ret = rwl_send_to_streamsocket(*(int*)wl, (const char*)buf, + data_len, 0)) == -1) { + DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n"); + return (FAIL); + } + + return (buf_len); + } +#endif /* RWL_SOCKET */ + +#ifdef RWL_WIFI + /* + * wifi action frame is formed based on the CDC header and data. + * If the data is bigger than RWL_WIFI_FRAG_DATA_SIZE size, number of fragments are + * calculated and sent + * similar number of action frames with subtype incremented with sequence. + * Frames are sent with delay to avoid the outof order at receving end + */ + if (remote_type == REMOTE_WIFI) { + if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) { + DPRINT_ERR(ERR, "remote_CDC_tx: Failed to get allocated buffer\n"); + return (FAIL); + } + + if (buf_len > RWL_WIFI_FRAG_DATA_SIZE) { + /* response needs to be sent in fragments */ + totalframes = buf_len / RWL_WIFI_FRAG_DATA_SIZE; + memcpy((char*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET], + (char*)rem_ptr, REMOTE_SIZE); + memcpy((char*)&rem_wifi_send->data[REMOTE_SIZE], &buf[0], + RWL_WIFI_FRAG_DATA_SIZE); + /* update type feild to inform receiver it's frammeted response frame + */ + rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE; + rem_wifi_send->subtype = RWL_WIFI_DEFAULT_SUBTYPE; + + if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, + rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) { + DPRINT_DBG(OUTPUT, "Failed to Send the Frame %d\n", error); + free(rem_wifi_send); + return error; + } + /* Send remaining bytes in fragments */ + for (tx_count = 1; tx_count < totalframes; tx_count++) { + rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE; + rem_wifi_send->subtype = tx_count; + /* First frame onwards , buf contains only data */ + memcpy((char*)&rem_wifi_send->data, + &buf[tx_count*RWL_WIFI_FRAG_DATA_SIZE], RWL_WIFI_FRAG_DATA_SIZE); + if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, + rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) { + free(rem_wifi_send); + return error; + } + rwl_sleep(RWL_WIFI_SEND_DELAY); + } + + /* Check for remaing bytes to send */ + if ((totalframes*RWL_WIFI_FRAG_DATA_SIZE) != buf_len) { + rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE; + rem_wifi_send->subtype = tx_count; + memcpy((char*)&rem_wifi_send->data, + &buf[tx_count*RWL_WIFI_FRAG_DATA_SIZE], + (buf_len - (tx_count*RWL_WIFI_FRAG_DATA_SIZE))); + if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, + rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) { + free(rem_wifi_send); + return error; + } + } + } else { + /* response fits to single frame */ + memcpy((char*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET], + (char*)rem_ptr, REMOTE_SIZE); + /* when data_len is 0 , buf will be NULL */ + if (buf != NULL) { + memcpy((char*)&rem_wifi_send->data[REMOTE_SIZE], + &buf[0], data_len); + } + error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send, + RWL_WIFI_ACTION_FRAME_SIZE); + free(rem_wifi_send); + return error; + } + } +#endif /* RWL_WIFI */ + return (0); +} + + +rem_ioctl_t * +remote_CDC_rx_hdr(void *remote, int debug) +{ +#ifdef RWL_SOCKET + int ret; +#endif /* RWL_SOCKET */ + +#if defined(RWL_SERIAL) || defined(RWL_DONGLE) || defined(RWL_SOCKET) + uint numread = 0; +#endif + rem_ioctl_t *rem_ptr = &rem_cdc; + memset(rem_ptr, 0, sizeof(rem_ioctl_t)); + + UNUSED_PARAMETER(remote); + UNUSED_PARAMETER(debug); + + switch (remote_type) { +#if defined(RWL_SERIAL) || defined(RWL_DONGLE) + case REMOTE_SERIAL: + case REMOTE_DONGLE: + if (rwl_read_serial_port(remote, (char *)rem_ptr, sizeof(rem_ioctl_t), + &numread) < 0) { + DPRINT_ERR(ERR, "remote_CDC_rx_hdr: Header Read failed \n"); + return (NULL); + } + break; +#endif /* RWL_SERIAL | RWL_DONGLE */ + + +#ifdef RWL_SOCKET + case REMOTE_SOCKET: + ret = rwl_receive_from_streamsocket(*(int*)remote, (char *)rem_ptr, + sizeof(rem_ioctl_t), 0); + numread = ret; + if (ret == -1) { + DPRINT_ERR(ERR, "remote_CDC_rx_hdr: numread:%d", numread); + return (NULL); + } + if (numread == 0) { + DPRINT_DBG(OUTPUT, "\n remote_CDC_rx_hdr:No data to receive\n"); + return NULL; + } + break; +#endif + default: + DPRINT_ERR(ERR, "\n Unknown Transport Type\n"); + break; + } + + return (rem_ptr); +} + +/* Return a CDC type buffer */ +int +remote_CDC_rx(void *wl, rem_ioctl_t *rem_ptr, uchar *readbuf, uint buflen, int debug) +{ + uint numread = 0; + +#ifdef RWL_SOCKET + int ret; +#endif + +#ifdef RWL_WIFI + UNUSED_PARAMETER(numread); +#endif /* RWL_WIFI */ + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(readbuf); + UNUSED_PARAMETER(buflen); + UNUSED_PARAMETER(debug); + UNUSED_PARAMETER(numread); + + if (rem_ptr->data_len > rem_ptr->msg.len) { + DPRINT_ERR(ERR, "remote_CDC_rx: remote data len (%d) > msg len (%d)\n", + rem_ptr->data_len, rem_ptr->msg.len); + return (FAIL); + } + + +#if defined(RWL_DONGLE) || defined(RWL_SERIAL) + if ((remote_type == REMOTE_DONGLE) || (remote_type == REMOTE_SERIAL)) { + if (rwl_read_serial_port(wl, (char*)readbuf, rem_ptr->data_len, + &numread) < 0) { + DPRINT_ERR(ERR, "remote_CDC_rx_hdr: Data Receivefailed \n"); + return (FAIL); + } + } +#endif /* RWL_DONGLE || RWL_SERIAL */ + +#ifdef RWL_SOCKET + if (remote_type == REMOTE_SOCKET) { + if (((ret = rwl_receive_from_streamsocket(*(int*)wl, (char*)readbuf, + rem_ptr->data_len, 0)) == -1)) { + DPRINT_ERR(ERR, "remote_CDC_rx:Data Receive failed\n"); + return (FAIL); + } + } +#endif /* RWL_SOCKET */ + return (SUCCESS); +} +#ifdef RWL_SOCKET +int +rwl_sockconnect(int SockDes, struct sockaddr *servAddr, int size) +{ + DPRINT_DBG(OUTPUT, "sockconnet SockDes=%d\n", SockDes); + if (rwl_connectsocket(SockDes, servAddr, size) < 0) { + DPRINT_ERR(ERR, "\n Server is not running\n"); + return FAIL; + } + return SUCCESS; +} +#endif /* RWL_SOCKET */ +void +rwl_swap_header(rem_ioctl_t *rem_ptr, bool host_to_network) +{ + rem_ptr->msg.cmd = host_to_network?(htol32(rem_ptr->msg.cmd)):(ltoh32(rem_ptr->msg.cmd)); + rem_ptr->msg.len = host_to_network?(htol32(rem_ptr->msg.len)):(ltoh32(rem_ptr->msg.len)); + rem_ptr->msg.flags = host_to_network?(htol32(rem_ptr->msg.flags)): + (ltoh32(rem_ptr->msg.flags)); + rem_ptr->msg.status = host_to_network?(htol32(rem_ptr->msg.status)): + (ltoh32(rem_ptr->msg.status)); + rem_ptr->data_len = host_to_network?(htol32(rem_ptr->data_len)):(ltoh32(rem_ptr->data_len)); +}
diff --git a/src/wl/exe/wlu_pipe.h b/src/wl/exe/wlu_pipe.h new file mode 100644 index 0000000..752b84c --- /dev/null +++ b/src/wl/exe/wlu_pipe.h
@@ -0,0 +1,48 @@ +/* + * OS independent declarations + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_pipe.h 287128 2011-09-30 04:27:53Z $ + */ +#ifndef _wlu_pipe_h +#define _wlu_pipe_h + +/* Function prototypes defined in wlu_pipe.c */ + +/* Macros to access globals */ +extern char *g_rwl_device_name_serial; +#define rwl_get_serial_port_name() (g_rwl_device_name_serial) +#define rwl_set_serial_port_name(name) (g_rwl_device_name_serial = name) +extern char *g_rwl_buf_mac; +#define rwl_get_wifi_mac() (g_rwl_buf_mac) + +extern int remote_CDC_tx(void *wl, uint cmd, uchar *buf, uint buf_len, +uint data_len, uint flags, int debug); +extern rem_ioctl_t *remote_CDC_rx_hdr(void *remote, int debug); +extern int remote_CDC_rx(void *wl, rem_ioctl_t *rem_ptr, uchar *readbuf, uint buflen, int debug); + +extern void* rwl_open_pipe(int remote_type, char *port, int ReadTotalTimeout, int debug); +extern int rwl_close_pipe(int remote_type, void* hndle); + +#ifdef RWL_SOCKET +extern int rwl_sockconnect(int SockDes, struct sockaddr *servAddr, int size); +#endif /* RWL_SOCKET */ + +extern int remote_CDC_DATA_wifi_rx_frag(void *wl, rem_ioctl_t *rem_ptr, uint input_len, +void *input, bool shell); +extern int remote_CDC_DATA_wifi_rx(void *wl, struct dot11_action_wifi_vendor_specific *rec_frame); +extern int +remote_CDC_wifi_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags); +extern void rwl_wifi_server_response(void *wl, struct dot11_action_wifi_vendor_specific *rec_frame); +extern int rwl_find_remote_wifi_server(void *wl, char *id); +extern void rwl_wifi_purge_actionframes(void *wl); +extern void rwl_wifi_swap_remote_type(int flag); +extern void remote_wifi_ser_init_cmds(void *wl); +#endif /* _wlu_pipe_h */
diff --git a/src/wl/exe/wlu_pipe_linux.c b/src/wl/exe/wlu_pipe_linux.c new file mode 100644 index 0000000..26a6659 --- /dev/null +++ b/src/wl/exe/wlu_pipe_linux.c
@@ -0,0 +1,569 @@ +/* + * linux version of remote Wl transport mechanisms (pipes). + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_pipe_linux.c 386901 2013-02-22 08:46:40Z $ + */ + +/* Revision History: Linux version of remote Wl transport mechanisms (pipes). + * + * Date Author Description + * + * 27-Dec-2007 Suganthi Version 0.0 + * +*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <netdb.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <termios.h> +#include <fcntl.h> +#include <proto/802.11.h> +#include <bcmendian.h> +#include <bcmcdc.h> +#include <proto/802.11.h> +#include <wlioctl.h> +#include <typedefs.h> +#include "wlu_remote.h" +#include <miniopt.h> +#if defined(RWL_DONGLE) || defined(RWL_SERIAL) +#define READ_DELAY 500000 +#define BAUD_RATE_115200 115200 +#define VMIN_VAL 16 +#define VTIME_VAL 50 +#define LINUX_SYNC_DELAY 200 +extern char *g_rwl_device_name_serial; +#endif + +#define MICRO_SEC_CONVERTER_VAL 1000 +int g_irh; +int g_shellsync_pid; + +#ifdef RWL_SOCKET +#define MAX_INTERFACE_NAME 32 + +static int +rwl_opensocket(int AddrFamily, int Type, int Protocol) +{ + int SockDes; + + if ((SockDes = socket(AddrFamily, Type, Protocol)) == -1) { + perror("rwl_opensocket Fails:"); + DPRINT_ERR(ERR, "\nerrno:%d\n", errno); + return FAIL; + } + return SockDes; +} + +static int +rwl_set_socket_option(int SocketDes, int Level, int OptName, int Val) +{ + if (setsockopt(SocketDes, Level, OptName, &Val, sizeof(int)) == -1) { + perror("Error at SetTCPSocketOpt()"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + return FAIL; + } + return SUCCESS; +} + +/* Function to connect with the server waiting in the same port */ +int +rwl_connectsocket(int SocketDes, struct sockaddr* SerAddr, int SizeOfAddr) +{ + if (connect(SocketDes, SerAddr, SizeOfAddr) == -1) { + perror("Failed to connect() to server"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + return FAIL; + } + return SUCCESS; +} + +/* + * Function for associating a local address with a socket. + */ +int +rwl_bindsocket(int SocketDes, struct sockaddr * MyAddr, int SizeOfAddr) +{ + if (bind(SocketDes, MyAddr, SizeOfAddr) == -1) { + perror("Error at rwl_bindSocket()"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + return FAIL; + } + return SUCCESS; +} + +/* + * Function for making the socket to listen for incoming connection. + */ +int +rwl_listensocket(int SocketDes, int BackLog) +{ + if (listen(SocketDes, BackLog) == -1) { + perror("Error at rwl_listensocket()"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + return FAIL; + } + return SUCCESS; +} + +/* + * Function for permitting an incoming connection attempt on a socket + * Function called by server + */ +int +rwl_acceptconnection(int SocketDes, struct sockaddr* ClientAddr, int *SizeOfAddr) +{ + int NewSockDes; + + if ((NewSockDes = accept(SocketDes, ClientAddr, (socklen_t*)SizeOfAddr)) == -1) { + perror("Error at rwl_acceptConnection()"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + return FAIL; + } + return NewSockDes; +} + +static int +rwl_closesocket(int SocketDes) +{ + if (close(SocketDes) == -1) { + perror("Error at rwl_closeSocket()"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + return FAIL; + } + return SUCCESS; +} + +/* Transmit the response in the opened TCP stream socket */ +int +rwl_send_to_streamsocket(int SocketDes, const char* SendBuff, int data_size, int Flag) +{ + int total_numwritten = 0, numwritten = 0; + while (total_numwritten < data_size) { + if ((numwritten = send(SocketDes, SendBuff, + data_size - total_numwritten, Flag)) == -1) { + perror("Failed to send()"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + return (FAIL); + } + + /* Sent successfully at first attempt no more retries */ + if (numwritten == data_size) { + total_numwritten = numwritten; + break; + } + + /* If socket is busy we may hit this condition */ + if (numwritten != data_size - total_numwritten) { + DPRINT_DBG(OUTPUT, "wanted to send %d bytes sent only %d bytes\n", + data_size - total_numwritten, numwritten); + } + + /* Now send the remaining buffer */ + total_numwritten += numwritten; + SendBuff += numwritten; + } + + return total_numwritten; +} + +/* Receive the response from the opened TCP stream socket */ +int +rwl_receive_from_streamsocket(int SocketDes, char* RecvBuff, int data_size, int Flag) +{ + int numread; + int total_numread = 0; + + while (total_numread < data_size) { + if ((numread = recv(SocketDes, RecvBuff, data_size - total_numread, Flag)) == -1) { + perror("Failed to Receive()"); + DPRINT_ERR(ERR, "\n errno:%d\n", errno); + return FAIL; + } + + if (numread != data_size - total_numread) { + DPRINT_DBG(OUTPUT, "asked %d bytes got %d bytes\n", + data_size - total_numread, numread); + } + + if (numread == 0) + break; + + total_numread += numread; + RecvBuff += numread; + } + + return numread; +} + + +int +rwl_init_server_socket_setup(int argc, char** argv, uint remote_type) +{ + char netif[MAX_INTERFACE_NAME]; + unsigned short servPort; + struct sockaddr_in ServerAddress; + int err, SockDes, val; + + /* Default option */ + servPort = DEFAULT_SERVER_PORT; + + strcpy(netif, "eth0"); + + /* User option can override default arguments */ + if (argc == 3) { + argv++; + + if (isalpha(**argv) == FALSE) { + DPRINT_ERR(ERR, "USAGE ERROR:Incorrect network interface\n"); + return FAIL; + } + strcpy(netif, *argv); + argv++; + + if (isdigit(**argv) == FALSE) { + DPRINT_ERR(ERR, "USAGE ERROR:Incorrect port\n"); + return FAIL; + } + servPort = atoi(*argv); + } + + if (argc == 2) { + argv++; + + if (isalpha(**argv) == FALSE) { + if (isdigit(**argv) == FALSE) { + DPRINT_ERR(ERR, "USAGE ERROR\n"); + return FAIL; + } + else + servPort = atoi(*argv); + } + else + strcpy(netif, *argv); + } + + DPRINT_INFO(OUTPUT, "INFO: Network Interface:%s, Port:%d\n", + netif, servPort); + + if ((SockDes = (*(int *)rwl_open_transport(remote_type, NULL, 0, 0))) == FAIL) + return FAIL; + + val = 1; + if ((rwl_set_socket_option(SockDes, SOL_SOCKET, SO_REUSEADDR, val)) == FAIL) + return FAIL; + + memset(&ServerAddress, 0, sizeof(ServerAddress)); + + rwl_GetifAddr(netif, &ServerAddress); + ServerAddress.sin_family = AF_INET; /* host byte order */ + ServerAddress.sin_port = hton16(servPort); /* short, network byte order */ + + if (((err = rwl_bindsocket(SockDes, (struct sockaddr *)&ServerAddress, + sizeof(ServerAddress))) == FAIL)) + return err; + if ((err = rwl_listensocket(SockDes, BACKLOG)) == FAIL) + return err; + + DPRINT_DBG(OUTPUT, "Waiting for client to connect...\n"); + + return SockDes; +} + +int rwl_GetifAddr(char *ifname, struct sockaddr_in *sa) +{ + struct ifreq ifr; + int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + + if (fd < 0) + { + DPRINT_ERR(ERR, "socket open error\n"); + return FAIL; + } + + strcpy(ifr.ifr_name, ifname); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) + { + memcpy(sa, (struct sockaddr_in *)&ifr.ifr_addr, sizeof(struct sockaddr_in)); + close(fd); + return SUCCESS; + } + close(fd); + return FAIL; +} +#endif /* RWL_SOCKET */ + +#if defined(RWL_SERIAL) || defined(RWL_DONGLE) +static int +rwl_open_serial(int remote_type, char *port) +{ + struct termios tio; + int fCom; + int speed; + long BAUD, DATABITS, STOPBITS, PARITYON; + speed_t baud_rate; + + DPRINT_DBG(OUTPUT, "\n rwl_open_serial:%s\n", port); + if (remote_type == REMOTE_DONGLE) + fCom = open(port, O_RDWR | O_NOCTTY | O_NDELAY); + else + fCom = open(port, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC); + if (fCom < 0) { + DPRINT_ERR(ERR, "open COM failed with error %d.\n", errno); + return fCom; + } else { + /* To make the read as a blocking operation */ + fcntl(fCom, F_SETFL, 0); + } + + bzero(&tio, sizeof(tio)); + /* Get the current option for the port... */ + tcgetattr(fCom, &tio); + /* Set the baud rate */ + cfsetispeed(&tio, B115200); + cfsetospeed(&tio, B115200); + if (remote_type == REMOTE_DONGLE) { + if (tcsetattr(fCom, TCSANOW, &tio) < 0) { + perror("tcsetattr:setspeed"); + return FAIL; + } + + baud_rate = cfgetospeed(&tio); + if (baud_rate == B115200) + speed = BAUD_RATE_115200; + DPRINT_DBG(OUTPUT, "Baud_rate set is:%d\n", speed); + + BAUD = B115200; + DATABITS = CS8; + STOPBITS = 1; + PARITYON = 0; + + tio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | CLOCAL | CREAD; + tio.c_iflag = IGNPAR; + tio.c_oflag = 0; + tio.c_lflag = 0; + tio.c_cc[VMIN] = VMIN_VAL; + tio.c_cc[VTIME] = VTIME_VAL; + + tcflush(fCom, TCIOFLUSH); + if (tcsetattr(fCom, TCSANOW, &tio) < 0) { + perror("tcsetattr:"); + return FAIL; + } + + if (tcgetattr(fCom, &tio) < 0) { + perror("tcgetattr:"); + return FAIL; + } + + DPRINT_DBG(OUTPUT, "tcgetattr:VMIN is:%d\n", tio.c_cc[VMIN]); + DPRINT_DBG(OUTPUT, "tcgetattr:VTIME is:%d\n", tio.c_cc[VTIME]); + tcflush(fCom, TCIOFLUSH); + } + else { + UNUSED_PARAMETER(PARITYON); + UNUSED_PARAMETER(STOPBITS); + UNUSED_PARAMETER(DATABITS); + UNUSED_PARAMETER(BAUD); + UNUSED_PARAMETER(baud_rate); + UNUSED_PARAMETER(speed); + + /* Enable the receiver and set local mode */ + tio.c_cflag |= (CLOCAL | CREAD); + + tio.c_cflag &= ~PARENB; + tio.c_cflag &= ~CSTOPB; + tio.c_cflag &= ~CSIZE; + tio.c_cflag |= CS8; + tio.c_cc[VTIME] = 255; + tio.c_cc[VMIN] = 1; + + tio.c_iflag = 0; + tio.c_iflag |= IGNBRK; + + tio.c_oflag &= ~OPOST; + tio.c_oflag &= ~OLCUC; + tio.c_oflag &= ~ONLCR; + tio.c_oflag &= ~OCRNL; + tio.c_oflag &= ~ONOCR; + tio.c_oflag &= ~ONLRET; + tio.c_oflag &= ~OFILL; + + tio.c_lflag &= ~ICANON; + tio.c_lflag &= ~ISIG; + tio.c_lflag &= ~XCASE; + tio.c_lflag &= ~ECHO; + tio.c_lflag &= ~FLUSHO; + tio.c_lflag &= ~IEXTEN; + tio.c_lflag |= NOFLSH; + /* Set the new tio for the port... */ + tcsetattr(fCom, TCSANOW, &tio); + tcflush(fCom, TCIOFLUSH); + } + return (fCom); +} +int +rwl_write_serial_port(void* hndle, char* write_buf, unsigned long size, unsigned long *numwritten) +{ + int ret; + + ret = write((*(int *)hndle), (const void*)write_buf, size); + *numwritten = ret; + if (ret == -1) { + perror("WriteToPort Failed"); + DPRINT_ERR(ERR, "Errno:%d\n", errno); + return FAIL; + } + if (*numwritten != size) { + DPRINT_ERR(ERR, "rwl_write_serial_port failed numwritten %ld != len %ld\n", + *numwritten, size); + return FAIL; + } + return SUCCESS; +} + +int +rwl_read_serial_port(void* hndle, char* read_buf, uint data_size, uint *numread) +{ + int ret; + uint total_numread = 0; + while (total_numread < data_size) { + ret = read(*(int *)hndle, read_buf, data_size - total_numread); + *numread = ret; + if (ret == -1) { + + perror("ReadFromPort Failed"); + DPRINT_ERR(ERR, "Errno:%d\n", errno); + return FAIL; + } + if (*numread != data_size - total_numread) { + DPRINT_DBG(OUTPUT, "asked for %d bytes got %d bytes\n", + data_size - total_numread, *numread); + } + if (*numread == 0) + break; + + total_numread += *numread; + read_buf += *numread; + } + return SUCCESS; +} + +void +rwl_sync_delay(uint noframes) +{ + if (noframes > 1) { + rwl_sleep(LINUX_SYNC_DELAY); + } +} + +#endif /* RWL_DONGLE ||RWL_SERIAL */ + +#if defined(RWL_DONGLE) || defined(RWL_SOCKET) || defined(RWL_SERIAL) +void* +rwl_open_transport(int remote_type, char *port, int ReadTotalTimeout, int debug) +{ + void* hndle; + + UNUSED_PARAMETER(port); + UNUSED_PARAMETER(ReadTotalTimeout); + UNUSED_PARAMETER(debug); + + switch (remote_type) { +#if defined(RWL_DONGLE) || defined(RWL_SERIAL) + case REMOTE_SERIAL: +#ifdef RWL_SERIAL + g_rwl_device_name_serial = port; +#endif + case REMOTE_DONGLE: + if ((g_irh = rwl_open_serial(remote_type, g_rwl_device_name_serial)) + == FAIL) { + /* Initial port opening settings failed in reboot. + * So retry opening the serial port + */ + if ((g_irh = rwl_open_serial(remote_type, g_rwl_device_name_serial)) + == FAIL) { + DPRINT_ERR(ERR, "Can't open serial port\n"); + return NULL; + } + } + break; +#endif /* RWL_DONGLE || RWL_SERIAL */ + +#ifdef RWL_SOCKET + case REMOTE_SOCKET: + if ((g_irh = rwl_opensocket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == FAIL) { + DPRINT_ERR(ERR, "\nCan't open socket \n"); + return NULL; + } + + break; +#endif /* RWL_SOCKET */ + + default: + DPRINT_ERR(ERR, "rwl_open_transport: Unknown remote_type %d\n", remote_type); + return NULL; + break; + } /* end - switch case */ + + hndle = (void*) &g_irh; + return hndle; +} + +int +rwl_close_transport(int remote_type, void* Des) +{ + switch (remote_type) { +#ifdef RWL_SOCKET + case REMOTE_SOCKET: + if (rwl_closesocket(*(int *)Des) == FAIL) + return FAIL; + break; +#endif /* RWL_SOCKET */ + +#if defined(RWL_DONGLE) || defined(RWL_SERIAL) + case REMOTE_DONGLE: + case REMOTE_SERIAL: + if (close(*(int *)Des) == -1) + return FAIL; + break; +#endif /* RWL_DONGLE || RWL_SERIAL */ + + default: + DPRINT_ERR(ERR, "close_pipe: Unknown remote_type %d\n", remote_type); + break; + } + return SUCCESS; +} +#endif /* #if defined (RWL_DONGLE) || defined (RWL_SOCKET) */ + +void +rwl_sleep(int delay) +{ + usleep(delay * MICRO_SEC_CONVERTER_VAL); +} + +#if defined(WLMSO) +int +rwl_init_socket(void) +{ + return 0; +} +#endif
diff --git a/src/wl/exe/wlu_rates_matrix.c b/src/wl/exe/wlu_rates_matrix.c new file mode 100644 index 0000000..a44f5d1 --- /dev/null +++ b/src/wl/exe/wlu_rates_matrix.c
@@ -0,0 +1,740 @@ +/* + * This module does provides various mappings to or from the CLM rate indexes. + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + */ +/*FILE-CSTYLED*/ + +#include <stdio.h> +#include <typedefs.h> + +#include "wlu_rates_matrix.h" + +#define CLM_NO_RATE_STRING "NO_RATE" +#define EXP_MODE_UNKNOWN "Unknown expansion mode" +#define AUTO_RATESPEC 0x0 +#define MHZ_TO_HALF_MHZ 2 + +typedef enum exp_mode { + EXP_MODE_ID_DEF = 0, + EXP_MODE_ID_STBC, + EXP_MODE_ID_TXBF, + EXP_MODE_ID_MAX +} exp_mode_t; + +static reg_rate_index_t get_legacy_reg_rate_index(int rate_hmhz, int tx_expansion, exp_mode_t mode); +static reg_rate_index_t get_ht_reg_rate_index(int mcs, int tx_expansion, exp_mode_t mode); +static reg_rate_index_t get_vht_reg_rate_index(int mcs, int nss, int tx_expansion, exp_mode_t mode); +static int get_legacy_rate_identifier(int rate_hmhz); +static int get_legacy_mode_identifier(int tx_expansion, exp_mode_t mode); +static int get_vht_rate_identifier(int vht_mcs_index); +static int get_vht_ss1_mode_identifier(int tx_expansion, exp_mode_t mode); +static int get_vht_ss2_mode_identifier(int tx_expansion, exp_mode_t mode); +static int get_vht_ss3_mode_identifier(int tx_expansion, exp_mode_t mode); +static const char *get_mode_name(exp_mode_t mode); + +enum { + LEGACY_RATE_ID_NO_RATE = -1, + LEGACY_RATE_ID_1MHZ = 0, + LEGACY_RATE_ID_2MHZ, + LEGACY_RATE_ID_5_5MHZ, + LEGACY_RATE_ID_11MHZ, + LEGACY_RATE_ID_6MHZ, + LEGACY_RATE_ID_9MHZ, + LEGACY_RATE_ID_12MHZ, + LEGACY_RATE_ID_18MHZ, + LEGACY_RATE_ID_24MHZ, + LEGACY_RATE_ID_36MHZ, + LEGACY_RATE_ID_48MHZ, + LEGACY_RATE_ID_54MHZ, + LEGACY_RATE_ID_MAX +}; + +enum { + LEGACY_MODE_ID_NONE = 0, + LEGACY_MODE_ID_TXEXP1, + LEGACY_MODE_ID_TXEXP2, + LEGACY_MODE_ID_TXBF1, + LEGACY_MODE_ID_TXBF2, + LEGACY_MODE_ID_MAX +}; + +enum { + VHT_RATE_INDEX_0 = 0, + VHT_RATE_INDEX_1, + VHT_RATE_INDEX_2, + VHT_RATE_INDEX_3, + VHT_RATE_INDEX_4, + VHT_RATE_INDEX_5, + VHT_RATE_INDEX_6, + VHT_RATE_INDEX_7, + VHT_RATE_INDEX_8, + VHT_RATE_INDEX_9, + VHT_RATE_INDEX_MAX +}; + +enum { + VHT_SS1_MODE_ID_NONE = 0, + VHT_SS1_MODE_ID_CDD1, + VHT_SS1_MODE_ID_STBC, + VHT_SS1_MODE_ID_CDD2, + VHT_SS1_MODE_ID_STBC_SPEXP1, + VHT_SS1_MODE_ID_TXBF1, + VHT_SS1_MODE_ID_TXBF2, + VHT_SS1_MODE_ID_MAX +}; + +enum { + VHT_SS2_MODE_ID_NONE = 0, + VHT_SS2_MODE_ID_SPEXP1, + VHT_SS2_MODE_ID_TXBF0, + VHT_SS2_MODE_ID_TXBF1, + VHT_SS2_MODE_ID_MAX +}; + +enum { + VHT_SS3_MODE_ID_NONE = 0, + VHT_SS3_MODE_ID_TXBF0, + VHT_SS3_MODE_ID_MAX +}; + +const char *clm_rate_group_labels[] = { + "DSSS", + "OFDM", + "MCS0_7", + "VHT8_9SS1", + "DSSS_MULTI1", + "OFDM_CDD1", + "MCS0_7_CDD1", + "VHT8_9SS1_CDD1", + "MCS0_7_STBC", + "VHT8_9SS1_STBC", + "MCS8_15", + "VHT8_9SS2", + "DSSS_MULTI2", + "OFDM_CDD2", + "MCS0_7_CDD2", + "VHT8_9SS1_CDD2", + "MCS0_7_STBC_SPEXP1", + "VHT8_9SS1_STBC_SPEXP1", + "MCS8_15_SPEXP1", + "VHT8_9SS2_SPEXP1", + "MCS16_23", + "VHT8_9SS3", + "OFDM_TXBF1", + "MCS0_7_TXBF1", + "VHT8_9SS1_TXBF1", + "MCS8_15_TXBF0", + "OFDM_TXBF2", + "MCS0_7_TXBF2", + "VHT8_9SS1_TXBF2", + "MCS8_15_TXBF1", + "VHT8_9SS2_TXBF1", + "MCS16_23_TXBF0", +}; + + +const char *clm_rate_labels[] = { + "DSSS1", + "DSSS2", + "DSSS5", + "DSSS11", + "OFDM6", + "OFDM9", + "OFDM12", + "OFDM18", + "OFDM24", + "OFDM36", + "OFDM48", + "OFDM54", + "MCS0", + "MCS1", + "MCS2", + "MCS3", + "MCS4", + "MCS5", + "MCS6", + "MCS7", + "VHT8SS1", + "VHT9SS1", + "DSSS1_MULTI1", + "DSSS2_MULTI1", + "DSSS5_MULTI1", + "DSSS11_MULTI1", + "OFDM6_CDD1", + "OFDM9_CDD1", + "OFDM12_CDD1", + "OFDM18_CDD1", + "OFDM24_CDD1", + "OFDM36_CDD1", + "OFDM48_CDD1", + "OFDM54_CDD1", + "MCS0_CDD1", + "MCS1_CDD1", + "MCS2_CDD1", + "MCS3_CDD1", + "MCS4_CDD1", + "MCS5_CDD1", + "MCS6_CDD1", + "MCS7_CDD1", + "VHT8SS1_CDD1", + "VHT9SS1_CDD1", + "MCS0_STBC", + "MCS1_STBC", + "MCS2_STBC", + "MCS3_STBC", + "MCS4_STBC", + "MCS5_STBC", + "MCS6_STBC", + "MCS7_STBC", + "VHT8SS1_STBC", + "VHT9SS1_STBC", + "MCS8", + "MCS9", + "MCS10", + "MCS11", + "MCS12", + "MCS13", + "MCS14", + "MCS15", + "VHT8SS2", + "VHT9SS2", + "DSSS1_MULTI2", + "DSSS2_MULTI2", + "DSSS5_MULTI2", + "DSSS11_MULTI2", + "OFDM6_CDD2", + "OFDM9_CDD2", + "OFDM12_CDD2", + "OFDM18_CDD2", + "OFDM24_CDD2", + "OFDM36_CDD2", + "OFDM48_CDD2", + "OFDM54_CDD2", + "MCS0_CDD2", + "MCS1_CDD2", + "MCS2_CDD2", + "MCS3_CDD2", + "MCS4_CDD2", + "MCS5_CDD2", + "MCS6_CDD2", + "MCS7_CDD2", + "VHT8SS1_CDD2", + "VHT9SS1_CDD2", + "MCS0_STBC_SPEXP1", + "MCS1_STBC_SPEXP1", + "MCS2_STBC_SPEXP1", + "MCS3_STBC_SPEXP1", + "MCS4_STBC_SPEXP1", + "MCS5_STBC_SPEXP1", + "MCS6_STBC_SPEXP1", + "MCS7_STBC_SPEXP1", + "VHT8SS1_STBC_SPEXP1", + "VHT9SS1_STBC_SPEXP1", + "MCS8_SPEXP1", + "MCS9_SPEXP1", + "MCS10_SPEXP1", + "MCS11_SPEXP1", + "MCS12_SPEXP1", + "MCS13_SPEXP1", + "MCS14_SPEXP1", + "MCS15_SPEXP1", + "VHT8SS2_SPEXP1", + "VHT9SS2_SPEXP1", + "MCS16", + "MCS17", + "MCS18", + "MCS19", + "MCS20", + "MCS21", + "MCS22", + "MCS23", + "VHT8SS3", + "VHT9SS3", + "OFDM6_TXBF1", + "OFDM9_TXBF1", + "OFDM12_TXBF1", + "OFDM18_TXBF1", + "OFDM24_TXBF1", + "OFDM36_TXBF1", + "OFDM48_TXBF1", + "OFDM54_TXBF1", + "MCS0_TXBF1", + "MCS1_TXBF1", + "MCS2_TXBF1", + "MCS3_TXBF1", + "MCS4_TXBF1", + "MCS5_TXBF1", + "MCS6_TXBF1", + "MCS7_TXBF1", + "VHT8SS1_TXBF1", + "VHT9SS1_TXBF1", + "MCS8_TXBF0", + "MCS9_TXBF0", + "MCS10_TXBF0", + "MCS11_TXBF0", + "MCS12_TXBF0", + "MCS13_TXBF0", + "MCS14_TXBF0", + "MCS15_TXBF0", + "OFDM6_TXBF2", + "OFDM9_TXBF2", + "OFDM12_TXBF2", + "OFDM18_TXBF2", + "OFDM24_TXBF2", + "OFDM36_TXBF2", + "OFDM48_TXBF2", + "OFDM54_TXBF2", + "MCS0_TXBF2", + "MCS1_TXBF2", + "MCS2_TXBF2", + "MCS3_TXBF2", + "MCS4_TXBF2", + "MCS5_TXBF2", + "MCS6_TXBF2", + "MCS7_TXBF2", + "VHT8SS1_TXBF2", + "VHT9SS1_TXBF2", + "MCS8_TXBF1", + "MCS9_TXBF1", + "MCS10_TXBF1", + "MCS11_TXBF1", + "MCS12_TXBF1", + "MCS13_TXBF1", + "MCS14_TXBF1", + "MCS15_TXBF1", + "VHT8SS2_TXBF1", + "VHT9SS2_TXBF1", + "MCS16_TXBF0", + "MCS17_TXBF0", + "MCS18_TXBF0", + "MCS19_TXBF0", + "MCS20_TXBF0", + "MCS21_TXBF0", + "MCS22_TXBF0", + "MCS23_TXBF0", +}; + +int legacy_reg_rate_map[LEGACY_RATE_ID_MAX][LEGACY_MODE_ID_MAX] = { + {DSSS1, DSSS1_MULTI1, DSSS1_MULTI2, NO_RATE, NO_RATE}, + {DSSS2, DSSS2_MULTI1, DSSS2_MULTI2, NO_RATE, NO_RATE}, + {DSSS5, DSSS5_MULTI1, DSSS5_MULTI2, NO_RATE, NO_RATE}, + {DSSS11, DSSS11_MULTI1, DSSS11_MULTI2,NO_RATE, NO_RATE}, + {OFDM6, OFDM6_CDD1, OFDM6_CDD2, OFDM6_TXBF1, OFDM6_TXBF2}, + {OFDM9, OFDM9_CDD1, OFDM9_CDD2, OFDM9_TXBF1, OFDM9_TXBF2}, + {OFDM12, OFDM12_CDD1, OFDM12_CDD2, OFDM12_TXBF1, OFDM12_TXBF2}, + {OFDM18, OFDM18_CDD1, OFDM18_CDD2, OFDM18_TXBF1, OFDM18_TXBF2}, + {OFDM24, OFDM24_CDD1, OFDM24_CDD2, OFDM24_TXBF1, OFDM24_TXBF2}, + {OFDM36, OFDM36_CDD1, OFDM36_CDD2, OFDM36_TXBF1, OFDM36_TXBF2}, + {OFDM48, OFDM48_CDD1, OFDM48_CDD2, OFDM48_TXBF1, OFDM48_TXBF2}, + {OFDM54, OFDM54_CDD1, OFDM54_CDD2, OFDM54_TXBF1, OFDM54_TXBF2} +}; + +int vht_ss1_reg_rate_map[VHT_RATE_INDEX_MAX][VHT_SS1_MODE_ID_MAX] = { + {MCS0, MCS0_CDD1, MCS0_STBC, MCS0_CDD2, MCS0_STBC_SPEXP1, MCS0_TXBF1, MCS0_TXBF2}, + {MCS1, MCS1_CDD1, MCS1_STBC, MCS1_CDD2, MCS1_STBC_SPEXP1, MCS1_TXBF1, MCS1_TXBF2}, + {MCS2, MCS2_CDD1, MCS2_STBC, MCS2_CDD2, MCS2_STBC_SPEXP1, MCS2_TXBF1, MCS2_TXBF2}, + {MCS3, MCS3_CDD1, MCS3_STBC, MCS3_CDD2, MCS3_STBC_SPEXP1, MCS3_TXBF1, MCS3_TXBF2}, + {MCS4, MCS4_CDD1, MCS4_STBC, MCS4_CDD2, MCS4_STBC_SPEXP1, MCS4_TXBF1, MCS4_TXBF2}, + {MCS5, MCS5_CDD1, MCS5_STBC, MCS5_CDD2, MCS5_STBC_SPEXP1, MCS5_TXBF1, MCS5_TXBF2}, + {MCS6, MCS6_CDD1, MCS6_STBC, MCS6_CDD2, MCS6_STBC_SPEXP1, MCS6_TXBF1, MCS6_TXBF2}, + {MCS7, MCS7_CDD1, MCS7_STBC, MCS7_CDD2, MCS7_STBC_SPEXP1, MCS7_TXBF1, MCS7_TXBF2}, + {VHT8SS1, VHT8SS1_CDD1, VHT8SS1_STBC, VHT8SS1_CDD2, VHT8SS1_STBC_SPEXP1,VHT8SS1_TXBF1, VHT8SS1_TXBF2}, + {VHT9SS1, VHT9SS1_CDD1, VHT9SS1_STBC, VHT9SS1_CDD2, VHT9SS1_STBC_SPEXP1,VHT9SS1_TXBF1, VHT9SS1_TXBF2} +}; + +int vht_ss2_reg_rate_map[VHT_RATE_INDEX_MAX][VHT_SS2_MODE_ID_MAX] = { + {MCS8, MCS8_SPEXP1, MCS8_TXBF0, MCS8_TXBF1}, + {MCS9, MCS9_SPEXP1, MCS9_TXBF0, MCS9_TXBF1}, + {MCS10, MCS10_SPEXP1, MCS10_TXBF0, MCS10_TXBF1}, + {MCS11, MCS11_SPEXP1, MCS11_TXBF0, MCS11_TXBF1}, + {MCS12, MCS12_SPEXP1, MCS12_TXBF0, MCS12_TXBF1}, + {MCS13, MCS13_SPEXP1, MCS13_TXBF0, MCS13_TXBF1}, + {MCS14, MCS14_SPEXP1, MCS14_TXBF0, MCS14_TXBF1}, + {MCS15, MCS15_SPEXP1, MCS15_TXBF0, MCS15_TXBF1}, + {VHT8SS2, VHT8SS2_SPEXP1,NO_RATE, VHT8SS2_TXBF1}, + {VHT9SS2, VHT9SS2_SPEXP1,NO_RATE, VHT8SS2_TXBF1} +}; + +int vht_ss3_reg_rate_map[VHT_RATE_INDEX_MAX][VHT_SS3_MODE_ID_MAX] = { + {MCS16, MCS16_TXBF0}, + {MCS17, MCS17_TXBF0}, + {MCS18, MCS18_TXBF0}, + {MCS19, MCS19_TXBF0}, + {MCS20, MCS20_TXBF0}, + {MCS21, MCS21_TXBF0}, + {MCS22, MCS22_TXBF0}, + {MCS23, MCS23_TXBF0}, + {VHT8SS3, NO_RATE}, + {VHT9SS3, NO_RATE} +}; + +const char *exp_mode_name[EXP_MODE_ID_MAX] = { + "CDD", + "STBC", + "TXBF" +}; + +const char * +get_clm_rate_group_label(int rategroup) +{ + return clm_rate_group_labels[rategroup]; +} + +const char * +get_reg_rate_string_from_ratespec(int ratespec) +{ + reg_rate_index_t index = get_reg_rate_index_from_ratespec(ratespec); + + if (index >= 0) + { + return clm_rate_labels[index]; + } + return CLM_NO_RATE_STRING; +} + +reg_rate_index_t +get_reg_rate_index_from_ratespec(int ratespec) +{ + uint encode, rate, txexp; + bool stbc,txbf; + int rate_index = NO_RATE; + exp_mode_t expmode = EXP_MODE_ID_DEF; + + /* If auto is set, we don't get a ratespec that can be decoded */ + if (ratespec == AUTO_RATESPEC) + return rate_index; + + encode = (ratespec & WL_RSPEC_ENCODING_MASK); + rate = (ratespec & WL_RSPEC_RATE_MASK); + txexp = (ratespec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT; + stbc = (ratespec & WL_RSPEC_STBC) != 0; + txbf = (ratespec & WL_RSPEC_TXBF) != 0; + + if (stbc && txbf) { + return rate_index; + } else if (txbf) { + expmode = EXP_MODE_ID_TXBF; + } else if (stbc) { + expmode = EXP_MODE_ID_STBC; + } + + if (encode == WL_RSPEC_ENCODE_RATE) { + rate_index = get_legacy_reg_rate_index(rate, txexp, expmode); + } else if (encode == WL_RSPEC_ENCODE_HT) { + rate_index = get_ht_reg_rate_index(rate, txexp, expmode); + } else if (encode == WL_RSPEC_ENCODE_VHT) { + uint mcs = (ratespec & WL_RSPEC_VHT_MCS_MASK); + uint nss = (ratespec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; + rate_index = get_vht_reg_rate_index(mcs, nss, txexp, expmode); + } + + return rate_index; +} + +reg_rate_index_t +get_legacy_reg_rate_index(int rate_hmhz, int tx_expansion, exp_mode_t expmode) +{ + reg_rate_index_t index = NO_RATE; + int rate_id; + rate_id = get_legacy_rate_identifier(rate_hmhz); + if (rate_id == LEGACY_RATE_ID_NO_RATE || (expmode == EXP_MODE_ID_TXBF && rate_id < LEGACY_RATE_ID_6MHZ)) + { + fprintf(stderr, "ERROR: Bad legacy rate spec: %d\n", rate_hmhz); + } + else + { + index = legacy_reg_rate_map[rate_id][get_legacy_mode_identifier(tx_expansion, expmode)]; + } + return index; +} + +static int get_legacy_rate_identifier(int rate_hmhz) +{ + int rate_lut[LEGACY_RATE_ID_MAX]; + int rate_index = LEGACY_RATE_ID_NO_RATE; + int i; + + rate_lut[LEGACY_RATE_ID_1MHZ] = 1 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_2MHZ] = 2 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_5_5MHZ] = 11; /* 5.5 * MHZ_TO_HALF_MHZ */ + rate_lut[LEGACY_RATE_ID_11MHZ] = 11 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_6MHZ] = 6 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_9MHZ] = 9 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_12MHZ] = 12 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_18MHZ] = 18 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_24MHZ] = 24 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_36MHZ] = 36 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_48MHZ] = 48 * MHZ_TO_HALF_MHZ; + rate_lut[LEGACY_RATE_ID_54MHZ] = 54 * MHZ_TO_HALF_MHZ; + + for (i = 0; i < LEGACY_RATE_ID_MAX; i++) + { + if (rate_lut[i] == rate_hmhz) + { + rate_index = i; + break; + } + } + + return rate_index; +} + +static int get_legacy_mode_identifier(int tx_expansion, exp_mode_t expmode) +{ + int mode_identifier = 0; + + if (tx_expansion == 0) + { + mode_identifier = LEGACY_MODE_ID_NONE; + } + else if (tx_expansion == 1) + { + switch (expmode) + { + case EXP_MODE_ID_DEF: + mode_identifier = LEGACY_MODE_ID_TXEXP1; + break; + case EXP_MODE_ID_TXBF: + mode_identifier = LEGACY_MODE_ID_TXBF1; + break; + default: + fprintf(stderr, "ERROR: Bad legacy tx_expansion spec: %d expansion mode %s\n", + tx_expansion, get_mode_name(expmode)); + break; + } + } + else if (tx_expansion == 2) + { + switch (expmode) + { + case EXP_MODE_ID_DEF: + mode_identifier = LEGACY_MODE_ID_TXEXP2; + break; + case EXP_MODE_ID_TXBF: + mode_identifier = LEGACY_MODE_ID_TXBF2; + break; + default: + fprintf(stderr, "ERROR: Bad legacy tx_expansion spec: %d expansion mode %s\n", + tx_expansion, get_mode_name(expmode)); + break; + } + } + else + { + fprintf(stderr, "ERROR: Bad legacy tx_expansion spec: %d expansion mode %s\n", tx_expansion, + get_mode_name(expmode)); + } + + return mode_identifier; +} + +reg_rate_index_t +get_ht_reg_rate_index(int mcs, int tx_expansion, exp_mode_t expmode) +{ + reg_rate_index_t rate_index = NO_RATE; + int vht_mcs, nss; + + if (mcs > 23) + { + fprintf(stderr, "ERROR: Bad ht mcs spec: %d\n", mcs); + } + else + { + vht_mcs = mcs % 8; + nss = (mcs / 8) + 1; + + rate_index = get_vht_reg_rate_index(vht_mcs, nss, tx_expansion, expmode); + } + + return rate_index; +} + +reg_rate_index_t +get_vht_reg_rate_index(int mcs, int nss, int tx_expansion, exp_mode_t expmode) +{ + reg_rate_index_t rate_index = NO_RATE; + int rate_id = get_vht_rate_identifier(mcs); + + if (nss == 1) + { + rate_index = vht_ss1_reg_rate_map[rate_id][get_vht_ss1_mode_identifier(tx_expansion, expmode)]; + } + else if (nss == 2) + { + rate_index = vht_ss2_reg_rate_map[rate_id][get_vht_ss2_mode_identifier(tx_expansion, expmode)]; + } + else if (nss == 3) + { + rate_index = vht_ss3_reg_rate_map[rate_id][get_vht_ss3_mode_identifier(tx_expansion, expmode)]; + } + + return rate_index; +} + +static int get_vht_rate_identifier(int vht_mcs_index) +{ + int rate_index = 0; + + if (vht_mcs_index >= VHT_RATE_INDEX_0 && vht_mcs_index < VHT_RATE_INDEX_MAX) + { + rate_index = vht_mcs_index; + } + else + { + fprintf(stderr, "ERROR: Bad vht mcs spec: %d\n", vht_mcs_index); + } + return rate_index; +} + +static int get_vht_ss1_mode_identifier(int tx_expansion, exp_mode_t expmode) +{ + int mode_identifier = 0; + + if (tx_expansion == 0) + { + switch (expmode) + { + case EXP_MODE_ID_DEF: + mode_identifier = VHT_SS1_MODE_ID_NONE; + break; + case EXP_MODE_ID_STBC: + mode_identifier = VHT_SS1_MODE_ID_STBC; + break; + default: + fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode %s\n", tx_expansion, + get_mode_name(expmode)); + break; + } + } + else if (tx_expansion == 1) + { + switch (expmode) + { + case EXP_MODE_ID_DEF: + mode_identifier = VHT_SS1_MODE_ID_CDD1; + break; + case EXP_MODE_ID_STBC: + mode_identifier = VHT_SS1_MODE_ID_STBC_SPEXP1; + break; + case EXP_MODE_ID_TXBF: + mode_identifier = VHT_SS1_MODE_ID_TXBF1; + break; + default: + fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode %s\n", tx_expansion, + get_mode_name(expmode)); + break; + } + } + else if (tx_expansion == 2) + { + switch (expmode) + { + case EXP_MODE_ID_DEF: + mode_identifier = VHT_SS1_MODE_ID_CDD2; + break; + case EXP_MODE_ID_TXBF: + mode_identifier = VHT_SS1_MODE_ID_TXBF2; + break; + default: + fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode %s\n", tx_expansion, + get_mode_name(expmode)); + break; + } + } + else + { + fprintf(stderr, "ERROR: Bad vht ss1 mode: %d, expansion mode: %s\n", tx_expansion, + get_mode_name(expmode)); + } + + return mode_identifier; +} + +static int get_vht_ss2_mode_identifier(int tx_expansion, exp_mode_t expmode) +{ + int mode_identifier = 0; + + if (tx_expansion == 0) + { + switch (expmode) + { + case EXP_MODE_ID_DEF: + mode_identifier = VHT_SS2_MODE_ID_NONE; + break; + case EXP_MODE_ID_TXBF: + mode_identifier = VHT_SS2_MODE_ID_TXBF0; + break; + default: + fprintf(stderr, "ERROR: Bad vht ss2 mode: %d, expansion mode %s\n", tx_expansion, + get_mode_name(expmode)); + break; + } + } + else if (tx_expansion == 1) + { + switch (expmode) + { + case EXP_MODE_ID_DEF: + mode_identifier = VHT_SS2_MODE_ID_SPEXP1; + break; + case EXP_MODE_ID_TXBF: + mode_identifier = VHT_SS2_MODE_ID_TXBF1; + break; + default: + fprintf(stderr, "ERROR: Bad vht ss2 mode: %d, expansion mode %s\n", tx_expansion, + get_mode_name(expmode)); + break; + } + } + else + { + fprintf(stderr, "ERROR: Bad vht ss2 mode: %d expansion mode: %s\n", tx_expansion, + get_mode_name(expmode)); + } + + return mode_identifier; +} + +static int get_vht_ss3_mode_identifier(int tx_expansion, exp_mode_t expmode) +{ + int mode_identifier = 0; + + if (tx_expansion == 0) + { + switch (expmode) + { + case EXP_MODE_ID_DEF: + mode_identifier = VHT_SS3_MODE_ID_NONE; + break; + case EXP_MODE_ID_TXBF: + mode_identifier = VHT_SS3_MODE_ID_TXBF0; + break; + default: + fprintf(stderr, "ERROR: Bad vht ss3 mode: %d, expansion mode: %s\n", tx_expansion + , get_mode_name(expmode)); + break; + } + } + else + { + fprintf(stderr, "ERROR: Bad vht ss3 mode: %d, expansion: %s\n", tx_expansion, + get_mode_name(expmode)); + } + + return mode_identifier; +} + +static const char *get_mode_name(exp_mode_t mode) +{ + if (mode >= EXP_MODE_ID_MAX) + return EXP_MODE_UNKNOWN; + + return exp_mode_name[mode]; +}
diff --git a/src/wl/exe/wlu_rates_matrix.h b/src/wl/exe/wlu_rates_matrix.h new file mode 100644 index 0000000..d9fe645 --- /dev/null +++ b/src/wl/exe/wlu_rates_matrix.h
@@ -0,0 +1,401 @@ +/* + * This module does provides various mappings to or from the CLM rate indexes. + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + */ +/*FILE-CSTYLED*/ + +#ifndef _WLU_RATES_MATRIX_H_ +#define _WLU_RATES_MATRIX_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <bcmwifi_rates.h> +#include <wlioctl.h> +#include <typedefs.h> +#include <epivers.h> +#include <bcmutils.h> +#include <bcmendian.h> +#include <bcmwifi_channels.h> +#include <wlc_ppr.h> + +#include <inttypes.h> +#include <miniopt.h> + +#define WL_UNSUPPORTED_IDX 0xFFF + +typedef enum clm_rate_group_id { + RATE_GROUP_ID_DSSS = 0, + RATE_GROUP_ID_OFDM, + RATE_GROUP_ID_MCS0_7, + RATE_GROUP_ID_VHT8_9SS1, + RATE_GROUP_ID_DSSS_MULTI1, + RATE_GROUP_ID_OFDM_CDD1, + RATE_GROUP_ID_MCS0_7_CDD1, + RATE_GROUP_ID_VHT8_9SS1_CDD1, + RATE_GROUP_ID_MCS0_7_STBC, + RATE_GROUP_ID_VHT8_9SS1_STBC, + RATE_GROUP_ID_MCS8_15, + RATE_GROUP_ID_VHT8_9SS2, + RATE_GROUP_ID_DSSS_MULTI2, + RATE_GROUP_ID_OFDM_CDD2, + RATE_GROUP_ID_MCS0_7_CDD2, + RATE_GROUP_ID_VHT8_9SS1_CDD2, + RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, + RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP1, + RATE_GROUP_ID_MCS8_15_SPEXP1, + RATE_GROUP_ID_VHT8_9SS2_SPEXP1, + RATE_GROUP_ID_MCS16_23, + RATE_GROUP_ID_VHT8_9SS3, + RATE_GROUP_ID_OFDM_TXBF1, + RATE_GROUP_ID_MCS0_7_TXBF1, + RATE_GROUP_ID_VHT8_9SS1_TXBF1, + RATE_GROUP_ID_MCS8_15_TXBF0, + RATE_GROUP_ID_OFDM_TXBF2, + RATE_GROUP_ID_MCS0_7_TXBF2, + RATE_GROUP_ID_VHT8_9SS1_TXBF2, + RATE_GROUP_ID_MCS8_15_TXBF1, + RATE_GROUP_ID_VHT8_9SS2_TXBF1, + RATE_GROUP_ID_MCS16_23_TXBF0, + RATE_GROUP_ID_COUNT +} clm_rate_group_id_t; + + +typedef struct { + char label[23]; + uint8 chains; + clm_rate_group_id_t id; + clm_rates_t rate; + uint bw20ssl; + uint bw20n; + uint bw20ht; + uint bw40ssl; + uint bw40n; + uint bw40ht; + uint bw20in40ssl; + uint bw20in40n; + uint bw20in40ht; + uint bw80ssl; + uint bw80n; + uint bw80ht; + uint bw20in80ssl; + uint bw20in80n; + uint bw20in80ht; + uint bw40in80ssl; + uint bw40in80n; + uint bw40in80ht; +} clm_rate_matrix_t; + +typedef enum reg_rate_index { + NO_RATE = -1, + DSSS1, DSSS2, DSSS5, DSSS11, + OFDM6, OFDM9, OFDM12, OFDM18, + OFDM24, OFDM36, OFDM48, OFDM54, + MCS0, MCS1, MCS2, MCS3, + MCS4, MCS5, MCS6, MCS7, + VHT8SS1, VHT9SS1, + DSSS1_MULTI1, DSSS2_MULTI1, DSSS5_MULTI1, DSSS11_MULTI1, + OFDM6_CDD1, OFDM9_CDD1, OFDM12_CDD1, OFDM18_CDD1, + OFDM24_CDD1, OFDM36_CDD1, OFDM48_CDD1, OFDM54_CDD1, + MCS0_CDD1, MCS1_CDD1, MCS2_CDD1, MCS3_CDD1, + MCS4_CDD1, MCS5_CDD1, MCS6_CDD1, MCS7_CDD1, + VHT8SS1_CDD1, VHT9SS1_CDD1, + MCS0_STBC, MCS1_STBC, MCS2_STBC, MCS3_STBC, + MCS4_STBC, MCS5_STBC, MCS6_STBC, MCS7_STBC, + VHT8SS1_STBC, VHT9SS1_STBC, + MCS8, MCS9, MCS10, MCS11, + MCS12, MCS13, MCS14, MCS15, + VHT8SS2, VHT9SS2, + DSSS1_MULTI2, DSSS2_MULTI2, DSSS5_MULTI2, DSSS11_MULTI2, + OFDM6_CDD2, OFDM9_CDD2, OFDM12_CDD2, OFDM18_CDD2, + OFDM24_CDD2, OFDM36_CDD2, OFDM48_CDD2, OFDM54_CDD2, + MCS0_CDD2, MCS1_CDD2, MCS2_CDD2, MCS3_CDD2, + MCS4_CDD2, MCS5_CDD2, MCS6_CDD2, MCS7_CDD2, + VHT8SS1_CDD2, VHT9SS1_CDD2, + MCS0_STBC_SPEXP1, MCS1_STBC_SPEXP1, MCS2_STBC_SPEXP1, MCS3_STBC_SPEXP1, + MCS4_STBC_SPEXP1, MCS5_STBC_SPEXP1, MCS6_STBC_SPEXP1, MCS7_STBC_SPEXP1, + VHT8SS1_STBC_SPEXP1, VHT9SS1_STBC_SPEXP1, + MCS8_SPEXP1, MCS9_SPEXP1, MCS10_SPEXP1, MCS11_SPEXP1, + MCS12_SPEXP1, MCS13_SPEXP1, MCS14_SPEXP1, MCS15_SPEXP1, + VHT8SS2_SPEXP1, VHT9SS2_SPEXP1, + MCS16, MCS17, MCS18, MCS19, + MCS20, MCS21, MCS22, MCS23, + VHT8SS3, VHT9SS3, + OFDM6_TXBF1, OFDM9_TXBF1, OFDM12_TXBF1, OFDM18_TXBF1, + OFDM24_TXBF1, OFDM36_TXBF1, OFDM48_TXBF1, OFDM54_TXBF1, + MCS0_TXBF1, MCS1_TXBF1, MCS2_TXBF1, MCS3_TXBF1, + MCS4_TXBF1, MCS5_TXBF1, MCS6_TXBF1, MCS7_TXBF1, + VHT8SS1_TXBF1, VHT9SS1_TXBF1, + MCS8_TXBF0, MCS9_TXBF0, MCS10_TXBF0, MCS11_TXBF0, + MCS12_TXBF0, MCS13_TXBF0, MCS14_TXBF0, MCS15_TXBF0, + OFDM6_TXBF2, OFDM9_TXBF2, OFDM12_TXBF2, OFDM18_TXBF2, + OFDM24_TXBF2, OFDM36_TXBF2, OFDM48_TXBF2, OFDM54_TXBF2, + MCS0_TXBF2, MCS1_TXBF2, MCS2_TXBF2, MCS3_TXBF2, + MCS4_TXBF2, MCS5_TXBF2, MCS6_TXBF2, MCS7_TXBF2, + VHT8SS1_TXBF2, VHT9SS1_TXBF2, + MCS8_TXBF1, MCS9_TXBF1, MCS10_TXBF1, MCS11_TXBF1, + MCS12_TXBF1, MCS13_TXBF1, MCS14_TXBF1, MCS15_TXBF1, + VHT8SS2_TXBF1, VHT9SS2_TXBF1, + MCS16_TXBF0, MCS17_TXBF0, MCS18_TXBF0, MCS19_TXBF0, + MCS20_TXBF0, MCS21_TXBF0, MCS22_TXBF0, MCS23_TXBF0, +} reg_rate_index_t; + +typedef enum ppr_rate_type { + PPR_RATE_DSSS, + PPR_RATE_OFDM, + PPR_RATE_HT, + PPR_RATE_VHT, +} ppr_rate_type_t; + +typedef struct ppr_tbl { + char label[23]; + clm_rate_group_id_t id; + clm_rates_t rate; +} ppr_tbl_t; + +typedef struct ppr_group { + clm_rate_group_id_t id; + wl_tx_chains_t chain; + wl_tx_mode_t mode; + wl_tx_nss_t nss; + ppr_rate_type_t rate_type; + reg_rate_index_t first_rate; +} ppr_group_t; + +static const ppr_group_t ppr_group_table[] = { + /*group id chains mode nss rate type offset-first*/ + {RATE_GROUP_ID_DSSS, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_DSSS, DSSS1}, + {RATE_GROUP_ID_OFDM, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6}, + {RATE_GROUP_ID_MCS0_7, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_VHT, MCS0}, + {RATE_GROUP_ID_VHT8_9SS1, WL_TX_CHAINS_1, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_VHT, MCS0}, + {RATE_GROUP_ID_DSSS_MULTI1, WL_TX_CHAINS_2, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_DSSS, DSSS1_MULTI1}, + {RATE_GROUP_ID_OFDM_CDD1, WL_TX_CHAINS_2, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_CDD1}, + {RATE_GROUP_ID_MCS0_7_CDD1, WL_TX_CHAINS_2, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD1}, + {RATE_GROUP_ID_VHT8_9SS1_CDD1, WL_TX_CHAINS_2, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD1}, + {RATE_GROUP_ID_MCS0_7_STBC, WL_TX_CHAINS_2, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC}, + {RATE_GROUP_ID_VHT8_9SS1_STBC, WL_TX_CHAINS_2, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC}, + {RATE_GROUP_ID_MCS8_15, WL_TX_CHAINS_2, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8}, + {RATE_GROUP_ID_VHT8_9SS2, WL_TX_CHAINS_2, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8}, + {RATE_GROUP_ID_DSSS_MULTI2, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_1, PPR_RATE_DSSS, DSSS1_MULTI2}, + {RATE_GROUP_ID_OFDM_CDD2, WL_TX_CHAINS_3, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_CDD2}, + {RATE_GROUP_ID_MCS0_7_CDD2, WL_TX_CHAINS_3, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD2}, + {RATE_GROUP_ID_VHT8_9SS1_CDD2, WL_TX_CHAINS_3, WL_TX_MODE_CDD, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_CDD2}, + {RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC_SPEXP1}, + {RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_STBC, WL_TX_NSS_2, PPR_RATE_VHT, MCS0_STBC_SPEXP1}, + {RATE_GROUP_ID_MCS8_15_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_SPEXP1}, + {RATE_GROUP_ID_VHT8_9SS2_SPEXP1, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_SPEXP1}, + {RATE_GROUP_ID_MCS16_23, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_3, PPR_RATE_VHT, MCS16}, + {RATE_GROUP_ID_VHT8_9SS3, WL_TX_CHAINS_3, WL_TX_MODE_NONE, WL_TX_NSS_3, PPR_RATE_VHT, MCS16}, + {RATE_GROUP_ID_OFDM_TXBF1, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_TXBF1}, + {RATE_GROUP_ID_MCS0_7_TXBF1, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF1}, + {RATE_GROUP_ID_VHT8_9SS1_TXBF1, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF1}, + {RATE_GROUP_ID_MCS8_15_TXBF0, WL_TX_CHAINS_2, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_HT, MCS8_TXBF0}, + {RATE_GROUP_ID_OFDM_TXBF2, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_OFDM, OFDM6_TXBF2}, + {RATE_GROUP_ID_MCS0_7_TXBF2, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF2}, + {RATE_GROUP_ID_VHT8_9SS1_TXBF2, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_1, PPR_RATE_VHT, MCS0_TXBF2}, + {RATE_GROUP_ID_MCS8_15_TXBF1, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF1}, + {RATE_GROUP_ID_VHT8_9SS2_TXBF1, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_2, PPR_RATE_VHT, MCS8_TXBF1}, + {RATE_GROUP_ID_MCS16_23_TXBF0, WL_TX_CHAINS_3, WL_TX_MODE_TXBF, WL_TX_NSS_3, PPR_RATE_HT, MCS16_TXBF0}, +}; + +static const ppr_tbl_t ppr_table[] = { + /* Label Rate Group ID CLM index*/ + {"DSSS1", RATE_GROUP_ID_DSSS, WL_RATE_1X1_DSSS_1}, + {"DSSS2", RATE_GROUP_ID_DSSS, WL_RATE_1X1_DSSS_2}, + {"DSSS5", RATE_GROUP_ID_DSSS, WL_RATE_1X1_DSSS_5_5}, + {"DSSS11", RATE_GROUP_ID_DSSS, WL_RATE_1X1_DSSS_11}, + {"OFDM6", RATE_GROUP_ID_OFDM, WL_RATE_1X1_OFDM_6}, + {"OFDM9", RATE_GROUP_ID_OFDM, WL_RATE_1X1_OFDM_9}, + {"OFDM12", RATE_GROUP_ID_OFDM, WL_RATE_1X1_OFDM_12}, + {"OFDM18", RATE_GROUP_ID_OFDM, WL_RATE_1X1_OFDM_18}, + {"OFDM24", RATE_GROUP_ID_OFDM, WL_RATE_1X1_OFDM_24}, + {"OFDM36", RATE_GROUP_ID_OFDM, WL_RATE_1X1_OFDM_36}, + {"OFDM48", RATE_GROUP_ID_OFDM, WL_RATE_1X1_OFDM_48}, + {"OFDM54", RATE_GROUP_ID_OFDM, WL_RATE_1X1_OFDM_54}, + {"MCS0", RATE_GROUP_ID_MCS0_7, WL_RATE_1X1_MCS0}, + {"MCS1", RATE_GROUP_ID_MCS0_7, WL_RATE_1X1_MCS1}, + {"MCS2", RATE_GROUP_ID_MCS0_7, WL_RATE_1X1_MCS2}, + {"MCS3", RATE_GROUP_ID_MCS0_7, WL_RATE_1X1_MCS3}, + {"MCS4", RATE_GROUP_ID_MCS0_7, WL_RATE_1X1_MCS4}, + {"MCS5", RATE_GROUP_ID_MCS0_7, WL_RATE_1X1_MCS5}, + {"MCS6", RATE_GROUP_ID_MCS0_7, WL_RATE_1X1_MCS6}, + {"MCS7", RATE_GROUP_ID_MCS0_7, WL_RATE_1X1_MCS7}, + {"VHT8SS1", RATE_GROUP_ID_VHT8_9SS1, WL_RATE_1X1_VHT8SS1}, + {"VHT9SS1", RATE_GROUP_ID_VHT8_9SS1, WL_RATE_1X1_VHT9SS1}, + {"DSSS1_MULTI1", RATE_GROUP_ID_DSSS_MULTI1, WL_RATE_1X2_DSSS_1}, + {"DSSS2_MULTI1", RATE_GROUP_ID_DSSS_MULTI1, WL_RATE_1X2_DSSS_2}, + {"DSSS5_MULTI1", RATE_GROUP_ID_DSSS_MULTI1, WL_RATE_1X2_DSSS_5_5}, + {"DSSS11_MULTI1", RATE_GROUP_ID_DSSS_MULTI1, WL_RATE_1X2_DSSS_11}, + {"OFDM6_CDD1", RATE_GROUP_ID_OFDM_CDD1, WL_RATE_1X2_CDD_OFDM_6}, + {"OFDM9_CDD1", RATE_GROUP_ID_OFDM_CDD1, WL_RATE_1X2_CDD_OFDM_9}, + {"OFDM12_CDD1", RATE_GROUP_ID_OFDM_CDD1, WL_RATE_1X2_CDD_OFDM_12,}, + {"OFDM18_CDD1", RATE_GROUP_ID_OFDM_CDD1, WL_RATE_1X2_CDD_OFDM_18,}, + {"OFDM24_CDD1", RATE_GROUP_ID_OFDM_CDD1, WL_RATE_1X2_CDD_OFDM_24,}, + {"OFDM36_CDD1", RATE_GROUP_ID_OFDM_CDD1, WL_RATE_1X2_CDD_OFDM_36,}, + {"OFDM48_CDD1", RATE_GROUP_ID_OFDM_CDD1, WL_RATE_1X2_CDD_OFDM_48,}, + {"OFDM54_CDD1", RATE_GROUP_ID_OFDM_CDD1, WL_RATE_1X2_CDD_OFDM_54,}, + {"MCS0_CDD1", RATE_GROUP_ID_MCS0_7_CDD1, WL_RATE_1X2_CDD_MCS0}, + {"MCS1_CDD1", RATE_GROUP_ID_MCS0_7_CDD1, WL_RATE_1X2_CDD_MCS1}, + {"MCS2_CDD1", RATE_GROUP_ID_MCS0_7_CDD1, WL_RATE_1X2_CDD_MCS2}, + {"MCS3_CDD1", RATE_GROUP_ID_MCS0_7_CDD1, WL_RATE_1X2_CDD_MCS3}, + {"MCS4_CDD1", RATE_GROUP_ID_MCS0_7_CDD1, WL_RATE_1X2_CDD_MCS4}, + {"MCS5_CDD1", RATE_GROUP_ID_MCS0_7_CDD1, WL_RATE_1X2_CDD_MCS5}, + {"MCS6_CDD1", RATE_GROUP_ID_MCS0_7_CDD1, WL_RATE_1X2_CDD_MCS6}, + {"MCS7_CDD1", RATE_GROUP_ID_MCS0_7_CDD1, WL_RATE_1X2_CDD_MCS7}, + {"VHT8SS1_CDD1", RATE_GROUP_ID_VHT8_9SS1_CDD1, WL_RATE_1X2_VHT8SS1}, + {"VHT9SS1_CDD1", RATE_GROUP_ID_VHT8_9SS1_CDD1, WL_RATE_1X2_VHT9SS1}, + {"MCS0_STBC", RATE_GROUP_ID_MCS0_7_STBC, WL_RATE_2X2_STBC_MCS0}, + {"MCS1_STBC", RATE_GROUP_ID_MCS0_7_STBC, WL_RATE_2X2_STBC_MCS1}, + {"MCS2_STBC", RATE_GROUP_ID_MCS0_7_STBC, WL_RATE_2X2_STBC_MCS2}, + {"MCS3_STBC", RATE_GROUP_ID_MCS0_7_STBC, WL_RATE_2X2_STBC_MCS3}, + {"MCS4_STBC", RATE_GROUP_ID_MCS0_7_STBC, WL_RATE_2X2_STBC_MCS4}, + {"MCS5_STBC", RATE_GROUP_ID_MCS0_7_STBC, WL_RATE_2X2_STBC_MCS5}, + {"MCS6_STBC", RATE_GROUP_ID_MCS0_7_STBC, WL_RATE_2X2_STBC_MCS6}, + {"MCS7_STBC", RATE_GROUP_ID_MCS0_7_STBC, WL_RATE_2X2_STBC_MCS7}, + {"VHT8SS1_STBC", RATE_GROUP_ID_VHT8_9SS1_STBC, WL_RATE_2X2_STBC_VHT8SS1}, + {"VHT9SS1_STBC", RATE_GROUP_ID_VHT8_9SS1_STBC, WL_RATE_2X2_STBC_VHT9SS1}, + {"MCS8", RATE_GROUP_ID_MCS8_15, WL_RATE_2X2_SDM_MCS8}, + {"MCS9", RATE_GROUP_ID_MCS8_15, WL_RATE_2X2_SDM_MCS9}, + {"MCS10", RATE_GROUP_ID_MCS8_15, WL_RATE_2X2_SDM_MCS10}, + {"MCS11", RATE_GROUP_ID_MCS8_15, WL_RATE_2X2_SDM_MCS11}, + {"MCS12", RATE_GROUP_ID_MCS8_15, WL_RATE_2X2_SDM_MCS12}, + {"MCS13", RATE_GROUP_ID_MCS8_15, WL_RATE_2X2_SDM_MCS13}, + {"MCS14", RATE_GROUP_ID_MCS8_15, WL_RATE_2X2_SDM_MCS14}, + {"MCS15", RATE_GROUP_ID_MCS8_15, WL_RATE_2X2_SDM_MCS15}, + {"VHT8SS2", RATE_GROUP_ID_VHT8_9SS2, WL_RATE_2X2_VHT8SS2}, + {"VHT9SS2", RATE_GROUP_ID_VHT8_9SS2, WL_RATE_2X2_VHT9SS2}, + {"DSSS1_MULTI2", RATE_GROUP_ID_DSSS_MULTI2, WL_RATE_1X3_DSSS_1}, + {"DSSS2_MULTI2", RATE_GROUP_ID_DSSS_MULTI2, WL_RATE_1X3_DSSS_2}, + {"DSSS5_MULTI2", RATE_GROUP_ID_DSSS_MULTI2, WL_RATE_1X3_DSSS_5_5}, + {"DSSS11_MULTI2", RATE_GROUP_ID_DSSS_MULTI2, WL_RATE_1X3_DSSS_11}, + {"OFDM6_CDD2", RATE_GROUP_ID_OFDM_CDD2, WL_RATE_1X3_CDD_OFDM_6}, + {"OFDM9_CDD2", RATE_GROUP_ID_OFDM_CDD2, WL_RATE_1X3_CDD_OFDM_9}, + {"OFDM12_CDD2", RATE_GROUP_ID_OFDM_CDD2, WL_RATE_1X3_CDD_OFDM_12}, + {"OFDM18_CDD2", RATE_GROUP_ID_OFDM_CDD2, WL_RATE_1X3_CDD_OFDM_18}, + {"OFDM24_CDD2", RATE_GROUP_ID_OFDM_CDD2, WL_RATE_1X3_CDD_OFDM_24}, + {"OFDM36_CDD2", RATE_GROUP_ID_OFDM_CDD2, WL_RATE_1X3_CDD_OFDM_36}, + {"OFDM48_CDD2", RATE_GROUP_ID_OFDM_CDD2, WL_RATE_1X3_CDD_OFDM_48}, + {"OFDM54_CDD2", RATE_GROUP_ID_OFDM_CDD2, WL_RATE_1X3_CDD_OFDM_54}, + {"MCS0_CDD2", RATE_GROUP_ID_MCS0_7_CDD2, WL_RATE_1X3_CDD_MCS0}, + {"MCS1_CDD2", RATE_GROUP_ID_MCS0_7_CDD2, WL_RATE_1X3_CDD_MCS1}, + {"MCS2_CDD2", RATE_GROUP_ID_MCS0_7_CDD2, WL_RATE_1X3_CDD_MCS2}, + {"MCS3_CDD2", RATE_GROUP_ID_MCS0_7_CDD2, WL_RATE_1X3_CDD_MCS3}, + {"MCS4_CDD2", RATE_GROUP_ID_MCS0_7_CDD2, WL_RATE_1X3_CDD_MCS4}, + {"MCS5_CDD2", RATE_GROUP_ID_MCS0_7_CDD2, WL_RATE_1X3_CDD_MCS5}, + {"MCS6_CDD2", RATE_GROUP_ID_MCS0_7_CDD2, WL_RATE_1X3_CDD_MCS6}, + {"MCS7_CDD2", RATE_GROUP_ID_MCS0_7_CDD2, WL_RATE_1X3_CDD_MCS7}, + {"VHT8SS1_CDD2", RATE_GROUP_ID_VHT8_9SS1_CDD2, WL_RATE_1X3_VHT8SS1}, + {"VHT9SS1_CDD2", RATE_GROUP_ID_VHT8_9SS1_CDD2, WL_RATE_1X3_VHT9SS1}, + {"MCS0_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_RATE_2X3_STBC_MCS0}, + {"MCS1_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_RATE_2X3_STBC_MCS1}, + {"MCS2_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_RATE_2X3_STBC_MCS2}, + {"MCS3_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_RATE_2X3_STBC_MCS3}, + {"MCS4_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_RATE_2X3_STBC_MCS4}, + {"MCS5_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_RATE_2X3_STBC_MCS5}, + {"MCS6_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_RATE_2X3_STBC_MCS6}, + {"MCS7_STBC_SPEXP1", RATE_GROUP_ID_MCS0_7_STBC_SPEXP1, WL_RATE_2X3_STBC_MCS7}, + {"VHT8SS1_STBC_SPEXP1", RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP1, WL_RATE_2X3_STBC_VHT8SS1}, + {"VHT9SS1_STBC_SPEXP1", RATE_GROUP_ID_VHT8_9SS1_STBC_SPEXP1, WL_RATE_2X3_STBC_VHT9SS1}, + {"MCS8_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1, WL_RATE_2X3_SDM_MCS8}, + {"MCS9_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1, WL_RATE_2X3_SDM_MCS9}, + {"MCS10_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1, WL_RATE_2X3_SDM_MCS10}, + {"MCS11_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1, WL_RATE_2X3_SDM_MCS11}, + {"MCS12_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1, WL_RATE_2X3_SDM_MCS12}, + {"MCS13_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1, WL_RATE_2X3_SDM_MCS13}, + {"MCS14_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1, WL_RATE_2X3_SDM_MCS14}, + {"MCS15_SPEXP1", RATE_GROUP_ID_MCS8_15_SPEXP1, WL_RATE_2X3_SDM_MCS15}, + {"VHT8SS2_SPEXP1", RATE_GROUP_ID_VHT8_9SS2_SPEXP1, WL_RATE_2X3_VHT8SS2}, + {"VHT9SS2_SPEXP1", RATE_GROUP_ID_VHT8_9SS2_SPEXP1, WL_RATE_2X3_VHT9SS2}, + {"MCS16", RATE_GROUP_ID_MCS16_23, WL_RATE_3X3_SDM_MCS16}, + {"MCS17", RATE_GROUP_ID_MCS16_23, WL_RATE_3X3_SDM_MCS17}, + {"MCS18", RATE_GROUP_ID_MCS16_23, WL_RATE_3X3_SDM_MCS18}, + {"MCS19", RATE_GROUP_ID_MCS16_23, WL_RATE_3X3_SDM_MCS19}, + {"MCS20", RATE_GROUP_ID_MCS16_23, WL_RATE_3X3_SDM_MCS20}, + {"MCS21", RATE_GROUP_ID_MCS16_23, WL_RATE_3X3_SDM_MCS21}, + {"MCS22", RATE_GROUP_ID_MCS16_23, WL_RATE_3X3_SDM_MCS22}, + {"MCS23", RATE_GROUP_ID_MCS16_23, WL_RATE_3X3_SDM_MCS23}, + {"VHT8SS3", RATE_GROUP_ID_VHT8_9SS3, WL_RATE_3X3_VHT8SS3}, + {"VHT9SS3", RATE_GROUP_ID_VHT8_9SS3, WL_RATE_3X3_VHT9SS3}, + {"OFDM6_TXBF1", RATE_GROUP_ID_OFDM_TXBF1, WL_RATE_1X2_TXBF_OFDM_6}, + {"OFDM9_TXBF1", RATE_GROUP_ID_OFDM_TXBF1, WL_RATE_1X2_TXBF_OFDM_9}, + {"OFDM12_TXBF1", RATE_GROUP_ID_OFDM_TXBF1, WL_RATE_1X2_TXBF_OFDM_12}, + {"OFDM18_TXBF1", RATE_GROUP_ID_OFDM_TXBF1, WL_RATE_1X2_TXBF_OFDM_18}, + {"OFDM24_TXBF1", RATE_GROUP_ID_OFDM_TXBF1, WL_RATE_1X2_TXBF_OFDM_24}, + {"OFDM36_TXBF1", RATE_GROUP_ID_OFDM_TXBF1, WL_RATE_1X2_TXBF_OFDM_36}, + {"OFDM48_TXBF1", RATE_GROUP_ID_OFDM_TXBF1, WL_RATE_1X2_TXBF_OFDM_48}, + {"OFDM54_TXBF1", RATE_GROUP_ID_OFDM_TXBF1, WL_RATE_1X2_TXBF_OFDM_54}, + {"MCS0_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1, WL_RATE_1X2_TXBF_MCS0}, + {"MCS1_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1, WL_RATE_1X2_TXBF_MCS1}, + {"MCS2_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1, WL_RATE_1X2_TXBF_MCS1}, + {"MCS3_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1, WL_RATE_1X2_TXBF_MCS3}, + {"MCS4_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1, WL_RATE_1X2_TXBF_MCS4}, + {"MCS5_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1, WL_RATE_1X2_TXBF_MCS5}, + {"MCS6_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1, WL_RATE_1X2_TXBF_MCS6}, + {"MCS7_TXBF1", RATE_GROUP_ID_MCS0_7_TXBF1, WL_RATE_1X2_TXBF_MCS7}, + {"VHT8SS1_TXBF1", RATE_GROUP_ID_VHT8_9SS1_TXBF1, WL_RATE_1X2_TXBF_VHT8SS1}, + {"VHT9SS1_TXBF1", RATE_GROUP_ID_VHT8_9SS1_TXBF1, WL_RATE_1X2_TXBF_VHT9SS1}, + {"MCS8_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0, WL_RATE_2X2_TXBF_SDM_MCS8}, + {"MCS9_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0, WL_RATE_2X2_TXBF_SDM_MCS9}, + {"MCS10_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0, WL_RATE_2X2_TXBF_SDM_MCS10}, + {"MCS11_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0, WL_RATE_2X2_TXBF_SDM_MCS11}, + {"MCS12_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0, WL_RATE_2X2_TXBF_SDM_MCS12}, + {"MCS13_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0, WL_RATE_2X2_TXBF_SDM_MCS13}, + {"MCS14_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0, WL_RATE_2X2_TXBF_SDM_MCS14}, + {"MCS15_TXBF0", RATE_GROUP_ID_MCS8_15_TXBF0, WL_RATE_2X2_TXBF_SDM_MCS15}, + {"OFDM6_TXBF2", RATE_GROUP_ID_OFDM_TXBF2, WL_RATE_1X3_TXBF_OFDM_6}, + {"OFDM9_TXBF2", RATE_GROUP_ID_OFDM_TXBF2, WL_RATE_1X3_TXBF_OFDM_9}, + {"OFDM12_TXBF2", RATE_GROUP_ID_OFDM_TXBF2, WL_RATE_1X3_TXBF_OFDM_12}, + {"OFDM18_TXBF2", RATE_GROUP_ID_OFDM_TXBF2, WL_RATE_1X3_TXBF_OFDM_18}, + {"OFDM24_TXBF2", RATE_GROUP_ID_OFDM_TXBF2, WL_RATE_1X3_TXBF_OFDM_24}, + {"OFDM36_TXBF2", RATE_GROUP_ID_OFDM_TXBF2, WL_RATE_1X3_TXBF_OFDM_36}, + {"OFDM48_TXBF2", RATE_GROUP_ID_OFDM_TXBF2, WL_RATE_1X3_TXBF_OFDM_48}, + {"OFDM54_TXBF2", RATE_GROUP_ID_OFDM_TXBF2, WL_RATE_1X3_TXBF_OFDM_54}, + {"MCS0_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2, WL_RATE_1X3_TXBF_MCS0}, + {"MCS1_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2, WL_RATE_1X3_TXBF_MCS1}, + {"MCS2_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2, WL_RATE_1X3_TXBF_MCS2}, + {"MCS3_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2, WL_RATE_1X3_TXBF_MCS3}, + {"MCS4_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2, WL_RATE_1X3_TXBF_MCS4}, + {"MCS5_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2, WL_RATE_1X3_TXBF_MCS5}, + {"MCS6_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2, WL_RATE_1X3_TXBF_MCS6}, + {"MCS7_TXBF2", RATE_GROUP_ID_MCS0_7_TXBF2, WL_RATE_1X3_TXBF_MCS7}, + {"VHT8SS1_TXBF2", RATE_GROUP_ID_VHT8_9SS1_TXBF2, WL_RATE_1X3_TXBF_VHT8SS1}, + {"VHT9SS1_TXBF2", RATE_GROUP_ID_VHT8_9SS1_TXBF2, WL_RATE_1X3_TXBF_VHT9SS1}, + {"MCS8_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1, WL_RATE_2X3_TXBF_SDM_MCS8}, + {"MCS9_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1, WL_RATE_2X3_TXBF_SDM_MCS9}, + {"MCS10_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1, WL_RATE_2X3_TXBF_SDM_MCS10}, + {"MCS11_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1, WL_RATE_2X3_TXBF_SDM_MCS11}, + {"MCS12_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1, WL_RATE_2X3_TXBF_SDM_MCS12}, + {"MCS13_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1, WL_RATE_2X3_TXBF_SDM_MCS13}, + {"MCS14_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1, WL_RATE_2X3_TXBF_SDM_MCS14}, + {"MCS15_TXBF1", RATE_GROUP_ID_MCS8_15_TXBF1, WL_RATE_2X3_TXBF_SDM_MCS15}, + {"VHT8SS2_TXBF1", RATE_GROUP_ID_VHT8_9SS2_TXBF1, WL_RATE_2X3_TXBF_VHT8SS2}, + {"VHT9SS2_TXBF1", RATE_GROUP_ID_VHT8_9SS2_TXBF1, WL_RATE_2X3_TXBF_VHT9SS2}, + {"MCS16_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0, WL_RATE_3X3_TXBF_SDM_MCS16}, + {"MCS17_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0, WL_RATE_3X3_TXBF_SDM_MCS17}, + {"MCS18_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0, WL_RATE_3X3_TXBF_SDM_MCS18}, + {"MCS19_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0, WL_RATE_3X3_TXBF_SDM_MCS19}, + {"MCS20_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0, WL_RATE_3X3_TXBF_SDM_MCS20}, + {"MCS21_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0, WL_RATE_3X3_TXBF_SDM_MCS21}, + {"MCS22_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0, WL_RATE_3X3_TXBF_SDM_MCS22}, + {"MCS23_TXBF0", RATE_GROUP_ID_MCS16_23_TXBF0, WL_RATE_3X3_TXBF_SDM_MCS23}, +}; + +#define MHZ_TO_HALF_MHZ 2 + +const char *get_clm_rate_group_label(int rategroup); +const char *get_reg_rate_string_from_ratespec(int ratespec); +reg_rate_index_t get_reg_rate_index_from_ratespec(int ratespec); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _WLU_RATES_MATRIX_H_ */
diff --git a/src/wl/exe/wlu_remote.h b/src/wl/exe/wlu_remote.h new file mode 100644 index 0000000..cfeb88a --- /dev/null +++ b/src/wl/exe/wlu_remote.h
@@ -0,0 +1,230 @@ +/* + * OS independent remote wl declarations + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_remote.h 425230 2013-09-23 10:53:48Z $ + */ +#ifndef _wlu_remote_h +#define _wlu_remote_h +#include <wlioctl.h> +/* Remote wl declararions */ +#define NO_REMOTE 0 +#define REMOTE_SERIAL 1 +#define REMOTE_SOCKET 2 +#define REMOTE_WIFI 3 +#define REMOTE_DONGLE 4 +#define SHELL_CMD -1 /* Invalid cmd id for shell */ +#define ASD_CMD -2 /* Cmd id for ASD command */ +#define SERVER_RESPONSE_MAX_BUF_LEN 8192 +#define SHELL_RESP_SIZE 1024 +#define CTRLC_PACKET 0xDEADBEAF +#define CTRLC_FLAG -4 +#define VISTA_CMD -3 /* cmd id for remote vista */ + +/* For cross OS support */ +/* For autonegotiation to work, these defines should be + * the same for client and server. + */ +#define UNKNOWN_OS 0 +#define LINUX_OS 1 +#define WIN32_OS 2 +#define MAC_OSX 3 +#define BACKLOG 4 +#define WINVISTA_OS 5 +#define INDONGLE 6 +#define INVALID_OS 7 /* Should be last */ + +/* Used in cdc_ioctl_t.flags field */ +#define REMOTE_SET_IOCTL 1 +#define REMOTE_GET_IOCTL 2 +#define REMOTE_REPLY 4 +#define REMOTE_SHELL_CMD 8 +#define REMOTE_FINDSERVER_IOCTL 16 /* Find remote server */ +#define REMOTE_ASD_CMD 32 /* ASD integration */ +#define RDHD_SET_IOCTL 64 +#define RDHD_GET_IOCTL 128 +#define REMOTE_VISTA_CMD 256 /* for remote vista specific commands */ +#define REMOTE_NEGOTIATE_CMD 512 /* for RWL negotiation */ +#define NEGOTIATE_GET_OS 0 /* detect remote OS */ +#define RWL_WIFI_DEFAULT_TYPE 0x00 +#define RWL_WIFI_DEFAULT_SUBTYPE 0x00 +#define RWL_ACTION_FRAME_DATA_SIZE 1024 /* fixed size for the wifi frame data */ +#define RWL_WIFI_CDC_HEADER_OFFSET 0 +#define RWL_WIFI_FRAG_DATA_SIZE 960 /* max size of the frag data */ +#define RWL_DEFAULT_WIFI_FRAG_COUNT 127 /* maximum fragment count */ +#define RWL_WIFI_RETRY 5 /* CMD retry count for wifi */ +#define RWL_WIFI_RX_RETRY 20 /* WIFI response rerty count */ +#define RWL_WIFI_SEND 5 /* WIFI frame sent count */ +#define RWL_WIFI_RETRY_DELAY 1000 /* wifi specific retry delay */ +#define RWL_WIFI_SEND_DELAY 100 /* delay between two frames */ +#define RWL_WIFI_RX_DELAY 250 /* wait between send and receive */ +#define RWL_WIFI_RX_SHELL_DELAY 1000 /* delay added for shell cmd response read */ +#define RWL_CHANNEL_RX_SCAN_DELAY 10 /* Delay between findserver rx calls */ +#define RWL_CHANNEL_SCAN_WAIT 250 /* Sleep time in between the channel scans */ +#define RWL_WIFI_BUF_LEN 64 +#define RWL_WIFI_SHELL_CMD 1 +#define RWL_WIFI_WL_CMD 0 +#define RWL_WIFI_FIND_SER_CMD "findserver" +#define RWL_WIFI_ACTION_CMD "wifiaction" +#define RWL_WIFI_GET_ACTION_CMD "rwlwifivsaction" +#define RWL_DONGLE_SET_CMD "dongleset" +#define DATA_FRAME_LEN 960 +/* wl & shell cmd work fine for 960 (512+256+128+64) */ + + +/* + * Information about the action frame data fields in the + * dot11_action_wifi_vendor_specific + * cdc struct (1 to 16. This does not include status flag. Since this + * is not directly visible to the driver code we cant use sizeof struct + * cdc_ioctl_t. Hence Ref MAC address offset starts from byte 17. + * REF MAC ADDR (6 bytes (MAC Address len) from byte 17 to 22) + * DUT MAC ADDR (6 bytes after the REF MAC Address byte 23 to 28) + * unused (byte 29 to 49) + * REF/Client Channel offset (50) + * DUT/Server channel offset (51) + * --------------------------------------------------------------------------------------- + * cdc struct|REF MAC ADDR|DUT_MAC_ADDR|un used|REF Channel|DUT channel|Action frame Data| + * 1---------17-----------23-------------------50----------51----------52----------------1040 + * REF MAC addr after CDC struct without status flag (status flag not used by wifi) + */ +#define RWL_ACTION_WIFI_CATEGORY 127 /* Vendor Specific category value for wifi */ +#define RWL_REF_MAC_ADDRESS_OFFSET 17 +#define RWL_DUT_MAC_ADDRESS_OFFSET 23 +#define RWL_WIFI_CLIENT_CHANNEL_OFFSET 50 +#define RWL_WIFI_SERVER_CHANNEL_OFFSET 51 + +#define SUCCESS 1 +#define FAIL -1 +#define NO_PACKET -2 +#define SERIAL_PORT_ERR -3 + +#define DEFAULT_SERVER_PORT 8000 + +#define WL_MAX_BUF_LEN (127 * 1024) +#define MAX_VISTA_ARGC 10 +#define HOST_TO_NETWORK TRUE +#define NETWORK_TO_HOST FALSE + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +/* We don't want the server to allocate bigger buffers for some of the commands + * like scanresults. Server can still allocate 8K memory and send the response + * in fragments. This is used in case of Get commands only. + */ +#define SERVER_RESPONSE_MAX_BUF_LEN 8192 +/* Used to set the cmds for wifi specific init */ +typedef struct remote_wifi_cmds { + uint32 cmd; /* common ioctl definition */ + char *data; /* max size of the data length */ + int value; +} remote_wifi_cmds_t; + +/* Added for debug utility support */ +#define ERR stderr +#define OUTPUT stdout + +#define DEBUG_DEFAULT 0x0001 +#define DEBUG_ERR 0x0001 +#define DEBUG_INFO 0x0002 +#define DEBUG_DBG 0x0004 + +/* #ifdef TARGETOS_symbian */ +#define DPRINT_ERR if (defined_debug & DEBUG_ERR) \ + fprintf +#define DPRINT_INFO if (defined_debug & DEBUG_INFO) \ + fprintf +#define DPRINT_DBG if (defined_debug & DEBUG_DBG) \ + fprintf +extern unsigned short defined_debug; +#ifdef WIN32 +/* Function defined in wlu.c for client and wlu_server_ce.c for server */ +extern int wl_atoip(const char *a, struct ipv4_addr *n); +#endif +/* Function defined to do host to network and network to host conversions */ +void rwl_swap_header(rem_ioctl_t *rem_ptr, bool host_to_network); + +/* Macros to access remote type */ +extern int remote_type; +#define rwl_get_remote_type() (remote_type) +#define rwl_set_remote_type(type) (remote_type = type) + +/* Macros to access server IP and port globals */ +extern char *g_rwl_servIP; +#define rwl_get_server_ip() (g_rwl_servIP) +#define rwl_set_server_ip(ip) (g_rwl_servIP = ip) +extern unsigned short g_rwl_servport; +#define rwl_get_server_port() (g_rwl_servport) +#define rwl_set_server_port(port) (g_rwl_servport = port) + +extern int rwl_read_serial_port(void* hndle, char* read_buf, uint data_size, uint *numread); +extern int rwl_write_serial_port(void* hndle, char* write_buf, unsigned long size, +unsigned long *numwritten); +extern void rwl_sleep(int delay); +extern void* rwl_open_transport(int remote_type, char *port, int ReadTotalTimeout, int debug); +extern int rwl_close_transport(int remote_type, void * handle); +extern int rwl_poll_serial_buffer(void *hndle); +extern int rwl_serial_handle_timeout(void); +extern void rwl_sync_delay(uint noframes); + +#ifdef RWL_SOCKET +extern int rwl_connectsocket(int SocketDes, struct sockaddr* SerAddr, int SizeOfAddr); +extern int rwl_acceptconnection(int SocketDes, struct sockaddr *ClientAddr, int *SizeOfAddr); +extern int rwl_send_to_streamsocket(int SocketDes, const char* SendBuff, int data_size, int Flag); +extern int rwl_receive_from_streamsocket(int SocketDes, char* RecvBuff, int data_size, int Flag); +extern int rwl_init_server_socket_setup(int argc, char** argv, uint remote_type); +extern int rwl_GetifAddr(char *ifname, struct sockaddr_in* sa); +#endif /* RWL_SOCKET */ + +extern int set_interface(void *wl, char *intf_name); + +/* Win32 specific function wlu_pipe_win32.c */ +extern int rwl_init_ws2_32dll(void); +extern int rwl_terminate_ws2_32dll(void); + +/* Function definitions for wlu_client_shared.c and wlu_server_shared.c */ +extern int rwl_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr); +extern int rwl_var_setbuf(void *wl, const char *iovar, void *param, int param_len); +extern int rwl_var_send_vs_actionframe(void* wl, const char* iovar, void* param, int param_len); + +/* Function definitions for wlu_ndis.c/wlu_linux.c and wlu_server_ce.c/wlu_server_linux.c */ +extern int wl_get(void *wl, int cmd, void *buf, int len); +extern int wl_set(void *wl, int cmd, void *buf, int len); +#ifdef RWLASD +typedef unsigned char BYTE; +extern void wfa_dut_init(BYTE **tBuf, BYTE **rBuf, BYTE **paBuf, BYTE **cBuf, struct timeval **); +extern int remote_asd_exec(unsigned char* command, int* cmd_len); +void wfa_dut_deinit(void); +#endif +extern int get_ctrlc_header(void *wl); +extern int remote_tx_response(void *wl, void *buf_ptr, int cmd); +extern rem_ioctl_t *g_rem_ptr; +extern int g_rwl_hndle; +/* Variable to indiate if the server child has completed execution */ +extern volatile sig_atomic_t g_sig_chld; + +/* + * Separate paths are defined for android and linux machines + * / filesystem on android is read only memory + */ +#ifndef WIN32 +#ifdef TARGETENV_android +#define SH_PATH "/data/busybox/sh" +#define SHELL_RESP_PATH "/data/local/RWL/" /* Default path for storing files for shell response */ +#define TEMPLATE "/data/local/RWL/SyncXXXXXX" +#else +#define SHELL_RESP_PATH "/tmp/RWL/" /* Default path for storing files for shell response */ +#define TEMPLATE "/tmp/RWL/SyncXXXXXX" +#define SH_PATH "/bin/sh" +#endif +#endif /* !WIN32 */ +#endif /* _wlu_remote_h */
diff --git a/src/wl/exe/wlu_server_linux.c b/src/wl/exe/wlu_server_linux.c new file mode 100644 index 0000000..b958e5f --- /dev/null +++ b/src/wl/exe/wlu_server_linux.c
@@ -0,0 +1,371 @@ +/* + * Wl server for linux + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_server_linux.c 420848 2013-08-29 08:58:47Z $ + */ + +/* Revision History:Linux port of Remote wl server + * + * Date Author Description + * + * 27-Dec-2007 Suganthi Version 0.1 + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <malloc.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/wait.h> +#include <signal.h> + +#include <sys/ioctl.h> +#include <net/if.h> +#ifndef TARGETENV_android +#include <linux/types.h> +#endif + +#include <linux/sockios.h> +#include <linux/ethtool.h> + +#include <typedefs.h> +#include <wlioctl.h> +#include <dhdioctl.h> +#include <proto/ethernet.h> +#include <bcmendian.h> +#include <bcmutils.h> +#include <bcmcdc.h> +#include <proto/802.11.h> +#include "wlu_remote.h" + + +#define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */ +#define BUF_LENGTH 1000 + +#define dtoh32(i) i + + +const char *rwl_server_name; +void *g_wl_handle; +unsigned short defined_debug = DEBUG_ERR | DEBUG_INFO; +extern int remote_server_exec(int argc, char **argv, void *ifr); + +/* Global to have the PID of the current sync command + * This is required in case the sync command fails to respond, + * the alarm handler shall kill the PID upon a timeout + */ +int g_shellsync_pid; +unsigned char g_return_stat = 0; + +static void +syserr(char *s) +{ + fprintf(stderr, "%s: ", rwl_server_name); + perror(s); + exit(errno); +} +/* The handler for DHD commands */ +int +dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set) +{ + struct ifreq *ifr = (struct ifreq *) dhd; + dhd_ioctl_t ioc; + int ret = 0; + int s; + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + syserr("socket"); + + /* do it */ + ioc.cmd = cmd; + ioc.buf = buf; + ioc.len = len; + ioc.set = set; + ioc.driver = DHD_IOCTL_MAGIC; + ifr->ifr_data = (caddr_t) &ioc; + if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) { + if (cmd != DHD_GET_MAGIC) { + ret = BCME_IOCTL_ERROR; + } + } + /* cleanup */ + close(s); + return ret; +} + +int +wl_ioctl(void *wl, int cmd, void *buf, int len, bool set) +{ + struct ifreq *ifr = (struct ifreq *) wl; + wl_ioctl_t ioc; + int ret = 0; + int s; + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + syserr("socket"); + + /* do it */ + ioc.cmd = cmd; + ioc.buf = buf; + ioc.len = len; + ioc.set = set; + ifr->ifr_data = (caddr_t) &ioc; + if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) { + if (cmd != WLC_GET_MAGIC) { + ret = BCME_IOCTL_ERROR; + } + } + /* cleanup */ + close(s); + return ret; +} + +/* Functions copied from wlu.c to check for the driver adapter in the server machine */ +int +wl_check(void *wl) +{ + int ret; + int val; + + if ((ret = wl_ioctl(wl, WLC_GET_MAGIC, &val, sizeof(int), FALSE)) < 0) + return ret; + if (val != WLC_IOCTL_MAGIC) + return -1; + if ((ret = wl_ioctl(wl, WLC_GET_VERSION, &val, sizeof(int), FALSE)) < 0) + return ret; + val = dtoh32(val); + + if (val > WLC_IOCTL_VERSION) { + fprintf(stderr, "Version mismatch, please upgrade\n"); + return -1; + } + return 0; +} + +static int +wl_get_dev_type(char *name, void *buf, int len) +{ + int s; + int ret; + struct ifreq ifr; + struct ethtool_drvinfo info; + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + syserr("socket"); + + /* get device type */ + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GDRVINFO; + ifr.ifr_data = (caddr_t)&info; + strncpy(ifr.ifr_name, name, IFNAMSIZ); + if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) { + /* print a good diagnostic if not superuser */ + if (errno == EPERM) + syserr("wl_get_dev_type"); + *(char *)buf = '\0'; + } else { + strncpy(buf, info.driver, len); + } + close(s); + return ret; +} + +static void +wl_find_adapter(struct ifreq *ifr) +{ + char proc_net_dev[] = "/proc/net/dev"; + FILE *fp; + char buf[BUF_LENGTH], *c, *name; + char dev_type[DEV_TYPE_LEN]; + + ifr->ifr_name[0] = '\0'; + + if (!(fp = fopen(proc_net_dev, "r"))) + return; + + /* eat first two lines */ + if (!fgets(buf, sizeof(buf), fp) || + !fgets(buf, sizeof(buf), fp)) { + fclose(fp); + return; + } + + while (fgets(buf, sizeof(buf), fp)) { + c = buf; + while (isspace(*c)) + c++; + if (!(name = strsep(&c, ":"))) + continue; + strncpy(ifr->ifr_name, name, IFNAMSIZ-1); + ifr->ifr_name[IFNAMSIZ-1] = 0; + if (wl_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 && + !strncmp(dev_type, "wl", 2)) + if (wl_check((void *) ifr) == 0) + break; + ifr->ifr_name[0] = '\0'; + } + + fclose(fp); +} + +int +wl_get(void *wl, int cmd, void *buf, int len) +{ + int error; + + error = wl_ioctl(wl, cmd, buf, len, FALSE); + + return error; +} + +int +wl_set(void *wl, int cmd, void *buf, int len) +{ + int error; + + error = wl_ioctl(wl, cmd, buf, len, TRUE); + + return error; +} + +extern int set_ctrlc; +void handle_ctrlc(int unused) +{ + UNUSED_PARAMETER(unused); + set_ctrlc = 1; + return; +} + +volatile sig_atomic_t g_sig_chld = 1; +void rwl_chld_handler(int num) +{ + int child_status; + + UNUSED_PARAMETER(num); + /* g_return_stat is being set with the return status of sh commands */ + waitpid(g_shellsync_pid, &child_status, WNOHANG); + if (WIFEXITED(child_status)) + g_return_stat = WEXITSTATUS(child_status); + else if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) + g_return_stat = 0; + else + g_return_stat = 1; + g_sig_chld = 0; +} + +/* Alarm handler called after SHELL_TIMEOUT value + * This handler kills the non-responsive shell process + * with the PID value g_shellsync_pid + */ +static void +sigalrm_handler(int s) +{ + UNUSED_PARAMETER(s); + + if (g_shellsync_pid) { + kill(g_shellsync_pid, SIGINT); + } +#ifdef RWL_SOCKET + g_sig_chld = 0; +#endif +} + +static void +def_handler(int s) +{ + UNUSED_PARAMETER(s); + kill(g_shellsync_pid, SIGKILL); + exit(0); +} + +static void +pipe_handler(int s) +{ + UNUSED_PARAMETER(s); + kill(g_shellsync_pid, SIGKILL); +} + +int +main(int argc, char **argv) +{ + int err = 0; + struct ifreq *ifr; + + rwl_server_name = argv[0]; + + if ((ifr = calloc(1, sizeof(*ifr))) == NULL) + { + DPRINT_ERR(ERR, "wl_server: Unable to allocate memory for handle\n"); + exit(1); + } + + /* use default interface */ + if (!ifr->ifr_name[0]) + wl_find_adapter(ifr); + /* validate the interface */ + if (!ifr->ifr_name[0] || wl_check((void *)ifr)) { + DPRINT_INFO(OUTPUT, "wl_server: wl driver adapter not found\n"); + } + g_wl_handle = ifr; + + /* Register signal handlers */ + signal(SIGCHLD, rwl_chld_handler); + signal(SIGALRM, sigalrm_handler); + signal(SIGTERM, def_handler); + signal(SIGPIPE, pipe_handler); + signal(SIGABRT, def_handler); +#ifdef RWL_DONGLE + signal(SIGINT, handle_ctrlc); +#endif + /* Main server process for all transport types */ + err = remote_server_exec(argc, argv, ifr); + free(ifr); + return err; +} + +/* + * Funtion to store old interface. + */ +void +store_old_interface(void *wl, char *old_intf_name) +{ + strcpy(old_intf_name, ((struct ifreq *)wl)->ifr_name); +} + +/* + * Function to set interface. + */ +int +set_interface(void *wl, char *intf_name) +{ + struct ifreq *ifr = (struct ifreq *)wl; + + if (strlen(intf_name) != 0) { + strncpy(ifr->ifr_name, intf_name, strlen(intf_name) + 1); + return BCME_OK; + } + else { + DPRINT_DBG(OUTPUT, "Default Interface will be used ... \n"); + return BCME_ERROR; + } +}
diff --git a/src/wl/exe/wlu_server_shared.c b/src/wl/exe/wlu_server_shared.c new file mode 100644 index 0000000..f9cd905 --- /dev/null +++ b/src/wl/exe/wlu_server_shared.c
@@ -0,0 +1,1040 @@ +/* + * File Name: wlu_server_shared.c + * Common server specific functions for linux and win32 + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_server_shared.c 428561 2013-10-09 09:32:29Z $ + */ + +/* + * Description: Main Server specific wrappers + * This module implements all the server specific functions + * for Win32 and Linux + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#ifdef TARGETOS_symbian +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/time.h> + +#else +#include <malloc.h> +#endif /* TARGETOS_symbian */ +#include <assert.h> + +#include <errno.h> +#ifndef WIN32 +#include <sys/types.h> +#include <sys/socket.h> +#if !defined(TARGETOS_symbian) +#include <arpa/inet.h> +#include <net/if.h> +#endif +#include <unistd.h> +#include <netdb.h> +#include <signal.h> +#endif /* WIN32 */ + +#ifdef WIN32 +#include <windows.h> +#include <winioctl.h> +#include <ntddndis.h> +#include <typedefs.h> +#include <epictrl.h> +#include <irelay.h> +#include <proto/ethernet.h> +#include <nuiouser.h> +#include <bcmendian.h> +#include <oidencap.h> +#include <bcmutils.h> +#include <proto/802.11.h> +#endif /* WIN32 */ + +#include <bcmcdc.h> +#include <wlioctl.h> +#include <typedefs.h> +#include <bcmendian.h> +#include <bcmutils.h> +#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR) +#include <rwl_wifi.h> +#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */ +#include "wlu.h" +#include "wlu_remote.h" +#include "wlu_pipe.h" +#include "wlu_server_shared.h" +#ifdef RWLASD +extern int g_serv_sock_desc; +#endif +int g_rwl_hndle; +int set_ctrlc = 0; + +#ifdef RWL_DONGLE +static rem_ioctl_t loc_cdc; +static const char* cmdname = "remote"; +static const char* dongleset = "dongleset"; +#endif + +extern void store_old_interface(void *wl, char *old_intf_name); +extern int wl_check(void *wl); + +extern void handle_ctrlc(int unused); +/* Function: rwl_transport_setup + * This will do the initialization for + * for all the transports + */ +static int +rwl_transport_setup(int argc, char** argv) +{ + int transport_descriptor = -1; + + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + +#ifdef RWL_SOCKET + /* This function will parse the socket command line arguments + * & open the socket in listen mode + */ + remote_type = REMOTE_SOCKET; + transport_descriptor = rwl_init_server_socket_setup(argc, argv, remote_type); + + if (transport_descriptor < 0) { + DPRINT_ERR(ERR, "wl_socket_server:Transport setup failed \n"); + } +#endif /* RWL_SOCKET */ +#if defined(RWL_DONGLE) || defined(RWL_WIFI) || defined(RWL_SERIAL) + g_rem_pkt_ptr = &g_rem_pkt; + transport_descriptor = 0; + +#ifdef RWL_WIFI + remote_type = REMOTE_WIFI; +#endif + +#ifdef RWL_DONGLE + remote_type = REMOTE_DONGLE; +#endif /* RWL_DONGLE */ +#ifdef RWL_SERIAL + remote_type = REMOTE_SERIAL; + if (argc < 2) { + DPRINT_ERR(ERR, "Port name is required from the command line\n"); + } else { + (void)*argv++; + DPRINT_DBG(OUTPUT, "Port name is %s\n", *argv); + transport_descriptor = *(int*) rwl_open_transport(remote_type, *argv, 0, 0); + } +#endif /* RWL_SERIAL */ +#endif /* RWL_DONGLE ||RWL_SERIAL ||RWL_WIFI */ +#ifdef RWLASD + g_serv_sock_desc = transport_descriptor; +#endif + return transport_descriptor; + +} + +/* Function: remote_rx_header + * This function will receive the CDC header from client + * for socket transport + * It will receive the command or ioctl from dongle driver for + * dongle UART serial transport and wifi transport. + * Arguments: wl - handle to driver + * : Des - Socket Descriptor to pass in AcceptConnection + * : g_rwl_hndle - Return socket handle that is used for transmission + * : and reception of data in case of socket + * In case of serial, it is just a return value + */ +static int +remote_rx_header(void *wl, int trans_Des) +{ + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(trans_Des); + +#ifdef RWL_SOCKET + { + struct sockaddr_in ClientAddress; + int SizeOfCliAdd = sizeof(ClientAddress); + + /* Get the socket handle g_rwl_hndle for transmission & reception */ + if ((g_rwl_hndle = rwl_acceptconnection(trans_Des, + (struct sockaddr *)&ClientAddress, + &SizeOfCliAdd)) == BCME_ERROR) { + return BCME_ERROR; + } + + /* Get CDC header in order to determine buffer requirements */ + if ((g_rem_ptr = remote_CDC_rx_hdr((void *)&g_rwl_hndle, 0)) == NULL) { + DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n"); + return BCME_ERROR; + } + } +#endif /* RWL_SOCKET */ + +#ifdef RWL_DONGLE + { + void *pkt_ptr = NULL; + int error; + + /* wl driver is polled after every 200 ms (POLLING_TIME) */ + rwl_sleep(POLLING_TIME); + + if ((error = rwl_var_getbuf(wl, cmdname, NULL, 0, &pkt_ptr)) < 0) { + DPRINT_ERR(ERR, "No packet in wl driver\r\n"); + return BCME_ERROR; + } + + DPRINT_DBG(OUTPUT, "Polling the wl driver, error status=%d\n", error); + + if ((*(int *)pkt_ptr) == 0) { + DPRINT_DBG(ERR, "packet not received\n"); + return BCME_ERROR; + } + + DPRINT_DBG(OUTPUT, "packet received\n"); + + /* Extract CDC header in order to determine buffer requirements */ + memcpy(g_rem_pkt_ptr, pkt_ptr, sizeof(rem_packet_t)); + g_rem_ptr = &g_rem_pkt_ptr->rem_cdc; + } +#endif /* RWL_DONGLE */ + +#ifdef RWL_SERIAL + { + if (g_rwl_hndle == -1) { + DPRINT_ERR(ERR, "failed to open com port.\r\n"); + return BCME_ERROR; + } + + if ((g_rem_ptr = remote_CDC_rx_hdr((void *)&g_rwl_hndle, 1)) == NULL) { + DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n"); + return BCME_ERROR; + } + } +#endif /* RWL_SERIAL */ + +#ifdef RWL_WIFI + { + /* Poll the driver for the valid action frame and update the CDC + data */ + dot11_action_wifi_vendor_specific_t *list; + + if ((list = rwl_wifi_allocate_actionframe()) == NULL) { + DPRINT_DBG(OUTPUT, "remote_rx_header: Failed to allocate frame \n"); + return BCME_ERROR; + } + + if (remote_CDC_DATA_wifi_rx((void *)wl, list) < 0) { + free(list); + return BCME_ERROR; + } + + /* copy the valid length of the data to the g_rem_pkt_ptr */ + memcpy(g_rem_pkt_ptr, &list->data[0], sizeof(rem_packet_t)); + g_rem_ptr = &g_rem_pkt_ptr->rem_cdc; + free(list); + } +#endif /* RWL_WIFI */ + + rwl_swap_header(g_rem_ptr, NETWORK_TO_HOST); + + DPRINT_INFO(OUTPUT, "%d %d %d %d\r\n", g_rem_ptr->msg.cmd, + g_rem_ptr->msg.len, g_rem_ptr->msg.flags, g_rem_ptr->data_len); + + return SUCCESS; + +} + +/* Function: remote_rx_data + * This function will receive the data from client + * for different transports + * In case of socket the data comes from a open TCP socket + * However in case of dongle UART or wi-fi the data is accessed + * from the driver buffers. + */ +int +remote_rx_data(void* buf_ptr) +{ +#if defined(RWL_SOCKET) || defined(RWL_SERIAL) + + if ((remote_CDC_rx((void *)&g_rwl_hndle, g_rem_ptr, buf_ptr, + g_rem_ptr->msg.len, 0)) == BCME_ERROR) { + DPRINT_ERR(ERR, "Reading CDC %d data bytes failed\n", g_rem_ptr->msg.len); + return BCME_ERROR; + } +#elif defined(RWL_DONGLE) || defined(RWL_WIFI) + if (g_rem_ptr->data_len != 0) { + int length = g_rem_ptr->data_len; + if (g_rem_ptr->data_len > g_rem_ptr->msg.len) { + length = g_rem_ptr->msg.len; + } + memcpy(buf_ptr, g_rem_pkt_ptr->message, length); + } + else + buf_ptr = NULL; +#else + UNUSED_PARAMETER(buf_ptr); +#endif /* RWL_SOCKET || RWL_SERIAL */ + return SUCCESS; +} + +#ifdef RWL_DONGLE +/* + * Function to send the serial response to wl driver + * The function calculates the no of frames based on the DATA_FRAME_LEN + * adds cdc header to every frame, copies the header and fragmented frame + * into rem_buf_ptr and sends the packet down to wl driver + */ + +static int +rwl_serial_fragmented_tx(void* wl, rem_ioctl_t *rem_ptr, uchar *buf_ptr, int error) +{ + rem_ioctl_t *loc_ptr = &loc_cdc; + uchar* rem_buf_ptr; + uint noframes = 1; /* Default noframes = 1 */ + uint count; + uint frame_count; + uint rem_bytes; + + loc_ptr->msg.cmd = error; + loc_ptr->msg.flags = REMOTE_REPLY; + loc_ptr->msg.len = rem_ptr->msg.len; + loc_ptr->data_len = rem_ptr->data_len; + + /* Fragment the result if it is more than DATA_FRAME_LEN (960) */ + if (loc_ptr->msg.len > DATA_FRAME_LEN) { + /* Calculate no of frames */ + noframes = (loc_ptr->msg.len)/DATA_FRAME_LEN; + if ((loc_ptr->msg.len) % DATA_FRAME_LEN > 0) { + noframes += 1; + rem_bytes = (loc_ptr->msg.len) % DATA_FRAME_LEN; + } else { + rem_bytes = DATA_FRAME_LEN; + } + } else { + rem_bytes = loc_ptr->msg.len; + } + DPRINT_INFO(OUTPUT, "No of frames = %d, rem_bytes:%d\n", noframes, rem_bytes); + count = 0; + frame_count = noframes; + rem_buf_ptr = (uchar*)malloc(DONGLE_TX_FRAME_SIZE + REMOTE_SIZE); + + while (count < noframes) { + memset(rem_buf_ptr, 0, DONGLE_TX_FRAME_SIZE + REMOTE_SIZE); + /* Send reply to client */ + rem_ptr->msg.cmd = loc_ptr->msg.cmd; + rem_ptr->msg.flags = loc_ptr->msg.flags; + rem_ptr->msg.len = loc_ptr->msg.len; + + if (frame_count == 1) + rem_ptr->data_len = rem_bytes; + else + rem_ptr->data_len = DATA_FRAME_LEN; + + DPRINT_DBG(OUTPUT, "GET--rem_ptr->data_len=%d\n", rem_ptr->data_len); + + /* Copy CDC Header */ + memcpy(rem_buf_ptr, (uchar*)rem_ptr, REMOTE_SIZE); + + /* Copy Data now */ + memcpy(&rem_buf_ptr[REMOTE_SIZE], &buf_ptr[count*DATA_FRAME_LEN], + rem_ptr->data_len); + count++; + frame_count--; + + DPRINT_INFO(OUTPUT, "FRAME %d\n", count); + DPRINT_INFO(OUTPUT, "%d %d %d %d\n", rem_ptr->msg.cmd, rem_ptr->msg.len, + rem_ptr->msg.flags, rem_ptr->data_len); + + rwl_sync_delay(noframes); + + if ((error = rwl_var_setbuf(wl, cmdname, rem_buf_ptr, + DONGLE_TX_FRAME_SIZE+REMOTE_SIZE)) < 0) { + DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", error); + if (rem_buf_ptr) + free(rem_buf_ptr); + return BCME_ERROR; + } + else + DPRINT_INFO(OUTPUT, "Packet sent to wl driver,error=%d\n", error); + } + + if (rem_buf_ptr) + free(rem_buf_ptr); + + return error; +} + +/* This function transmits the response to the dongle driver in the case + * of serial dongle transport. + * In the case of big response, it calls the rwl_serial_fragmented_response + * function to fragment the response and sends down to the driver. + */ + +static int +remote_CDC_dongle_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags) +{ + int error; + rem_ioctl_t resp_rem_cdc; + + if (flags & REMOTE_SET_IOCTL) { + uchar* rem_buf_ptr; + /* for set commands message length and data length should be set to zero + * unlike Get Ioctl which will have valid data and message length + */ + resp_rem_cdc.msg.len = 0; + resp_rem_cdc.data_len = 0; + resp_rem_cdc.msg.cmd = cmd; + resp_rem_cdc.msg.flags = REMOTE_REPLY; + + DPRINT_INFO(OUTPUT, "Set:Resp packet:%d %d %d %d\n", resp_rem_cdc.msg.cmd, + resp_rem_cdc.msg.len, resp_rem_cdc.msg.flags, resp_rem_cdc.data_len); + + if ((rem_buf_ptr = (uchar*)malloc(DONGLE_TX_FRAME_SIZE + REMOTE_SIZE)) == NULL) { + DPRINT_ERR(ERR, "malloc failed for remote_CDC_dongle_tx\n"); + return BCME_ERROR; + } + + /* Send reply to client here */ + memcpy(rem_buf_ptr, (char*)(&resp_rem_cdc), REMOTE_SIZE); + if ((error = rwl_var_setbuf((void*)wl, cmdname, rem_buf_ptr, + DONGLE_TX_FRAME_SIZE + REMOTE_SIZE)) < 0) { + DPRINT_ERR(ERR, "unable to send SET results to driver=%d\n", error); + } else + DPRINT_INFO(OUTPUT, "Packet sent to wl driver, error=%d\n", error); + + if (rem_buf_ptr) + free(rem_buf_ptr); + + } else { /* GET_IOCTL */ + resp_rem_cdc.msg.cmd = cmd; + resp_rem_cdc.msg.len = buf_len; + resp_rem_cdc.msg.flags = flags; + resp_rem_cdc.data_len = data_len; + if ((error = rwl_serial_fragmented_tx(wl, &resp_rem_cdc, buf, cmd)) < 0) + DPRINT_ERR(ERR, "wl_server_serial: Return error code failed\n"); + } + return error; +} +#endif /* RWL_DONGLE */ + +/* This function gets the command send by the client from the dongle driver */ +int +rwl_var_getbuf(void* wl, const char* iovar, void* param, int param_len, void** buf_ptr) +{ + int len; + + memset(rwl_buf, 0, WLC_IOCTL_MAXLEN); + strcpy((char*)rwl_buf, iovar); + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&rwl_buf[len], param, param_len); + + *buf_ptr = rwl_buf; + + return wl_get(wl, WLC_GET_VAR, &rwl_buf[0], WLC_IOCTL_MAXLEN); +} + +/* This function will send the buffer to the dongle driver */ +int +rwl_var_setbuf(void* wl, const char* iovar, void* param, int param_len) +{ + int len; + + memset(rwl_buf, 0, WLC_IOCTL_MAXLEN); + strcpy((char*)rwl_buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy(&rwl_buf[len], param, param_len); + + len += param_len; + + DPRINT_DBG(OUTPUT, "setbuf:%s, len:%d\n", rwl_buf, len); + + return wl_set(wl, WLC_SET_VAR, &rwl_buf[0], len); +} + +/* This function will send the buffer to the dongle driver */ +int +rwl_var_send_vs_actionframe(void* wl, const char* iovar, void* param, int param_len) +{ + int len; + + memset(rwl_buf, 0, WLC_IOCTL_MAXLEN); + strcpy((char*) rwl_buf, iovar); + + /* include the null */ + len = strlen(iovar) + 1; + + if (param_len) + memcpy((void*)&rwl_buf[len+ OFFSETOF(wl_action_frame_t, data)], param, param_len); + + /* Set the PacketID (not used by remote WL */ + memset((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, packetId)], 0, 4); + + /* Set the dest addr */ + memcpy((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, da)], + (void*)&rwlea, + ETHER_ADDR_LEN); + + /* set the length */ + memcpy((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, len)], (void*) ¶m_len, 2); + + len += param_len + ETHER_ADDR_LEN + 2 + 4; + + DPRINT_DBG(OUTPUT, "setbuf:%s, len:%d\n", rwl_buf, len); + + return wl_set(wl, WLC_SET_VAR, &rwl_buf[0], len); +} +/* + * This function is used for transmitting the response over different + * transports. + * In case of socket the data is directly sent to the client which is waiting on a open socket. + * In case of socket the data is sent in one big chunk unlike other transports + * + * In case of serial the data is sent to the driver using remote_CDC_dongle_tx function + * which in turn may fragment the data and send it in chunks to the client. + * + * In case of wi-fi the data is sent to the driver using the remote_CDC_tx. However + * in this case the data is converted into 802.11 Action frames and sent using wi-fi driver. + * Arguments: wl - Driver handle + * hndle - Socket handle for socket transport. + */ +int +remote_tx_response(void *wl, void* buf_ptr, int cmd) +{ + int error = -1; + + UNUSED_PARAMETER(wl); + UNUSED_PARAMETER(buf_ptr); + UNUSED_PARAMETER(cmd); + +#if defined(RWL_SOCKET) || defined(RWL_SERIAL) + if ((error = remote_CDC_tx((void*)&g_rwl_hndle, cmd, buf_ptr, g_rem_ptr->msg.len, + g_rem_ptr->msg.len, REMOTE_REPLY, 0)) < 0) + DPRINT_ERR(ERR, "wl_server: Return results failed\n"); +#endif /* RWL_SOCKET || RWL_SERIAL */ + +#ifdef RWL_DONGLE + if ((error = remote_CDC_dongle_tx(wl, cmd, buf_ptr, g_rem_ptr->msg.len, + g_rem_ptr->data_len, g_rem_ptr->msg.flags)) < 0) + DPRINT_ERR(ERR, "wl_server: Return results failed\n"); +#endif /* RWL_DONGLE */ + +#ifdef RWL_WIFI + /* Purge all the queued cmd's , this to ensure late response time out at */ + /* client side and client might issue the next cmd if server is slow */ + rwl_wifi_purge_actionframes(wl); + if ((g_rem_ptr->msg.flags & REMOTE_SHELL_CMD) || + (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL)|| + (g_rem_ptr->msg.flags & REMOTE_ASD_CMD) || + (g_rem_ptr->msg.flags & REMOTE_VISTA_CMD)) { + if ((error = remote_CDC_tx(wl, cmd, buf_ptr, g_rem_ptr->msg.len, + g_rem_ptr->msg.len, REMOTE_REPLY, 0)) < 0) + DPRINT_ERR(ERR, "Wifi_server: Return results failed\n"); + } else { + if ((error = remote_CDC_tx(wl, cmd, buf_ptr, 0, 0, REMOTE_REPLY, 0)) < 0) + DPRINT_ERR(ERR, "Failed due to bad flag %d\n", g_rem_ptr->msg.flags); + } +#endif /* RWL_WIFI */ + return error; +} + +/* Close the Socket handle */ +void close_sock_handle(int hndle) +{ +#ifdef RWL_SOCKET + rwl_close_pipe(remote_type, (void*)&hndle); +#else + UNUSED_PARAMETER(hndle); +#endif +} + + +/* + * Send the response to the remote if the channel of the server matches with the + * server channel. + */ +void remote_wifi_response(void* wl) +{ +#ifdef RWL_WIFI + dot11_action_wifi_vendor_specific_t *list; + + if ((list = rwl_wifi_allocate_actionframe()) == NULL) { + DPRINT_DBG(OUTPUT, "remote_wifi_response: Failed to allocate frame \n"); + return; + } + + /* it's sync frame and received from client */ + memcpy((char*)&list->data[RWL_WIFI_CDC_HEADER_OFFSET], + &g_rem_pkt_ptr[RWL_WIFI_CDC_HEADER_OFFSET], REMOTE_SIZE); + memcpy((char*)&list->data[REMOTE_SIZE], g_rem_pkt_ptr->message, + RWL_WIFI_FRAG_DATA_SIZE); + list->type = RWL_WIFI_FIND_MY_PEER; + /* Store the client mac addr */ + memcpy((void*)&rwlea, (void*)&list->data[RWL_DUT_MAC_ADDRESS_OFFSET], ETHER_ADDR_LEN); + /* send the response to client if server is on the same channel */ + rwl_wifi_find_server_response(wl, list); + + free(list); +#else + UNUSED_PARAMETER(wl); +#endif /* RWL_WIFI */ + return; +} + +/* Function to check IN-dongle mode firmware */ +int +rwl_iovar_check(void *wl) +{ + void *ptr; +#ifdef RWL_WIFI + dot11_action_wifi_vendor_specific_t rec_frame; + + /* Check for indongle mode firmware */ + return rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, &rec_frame, + RWL_WIFI_ACTION_FRAME_SIZE, &ptr); +#endif + UNUSED_PARAMETER(ptr); + UNUSED_PARAMETER(wl); +#ifdef RWL_DONGLE + return rwl_var_getbuf(wl, "remote", NULL, 0, &ptr); +#else + return 0; +#endif +} + + +#ifndef TARGETOS_symbian +/* Function to get a ctrl-c packet */ +int +get_ctrlc_header(void *wl) +{ +#if defined(RWL_SOCKET) || defined(RWL_SERIAL) + fd_set fdset; + struct timeval tv; + UNUSED_PARAMETER(wl); + FD_ZERO(&fdset); + FD_SET((unsigned)g_rwl_hndle, &fdset); + tv.tv_sec = 0; + tv.tv_usec = 0; + if ((select(g_rwl_hndle+1, &fdset, NULL, NULL, &tv)) > 0) { + if (FD_ISSET(g_rwl_hndle, &fdset)) { + remote_CDC_rx_hdr((void *)&g_rwl_hndle, 0); + return BCME_OK; + } + } + return BCME_ERROR; + +#else + return remote_rx_header(wl, 0); +#endif /* if defined(RWL_SOCKET) || defined(RWL_SERIAL) */ +} +#endif /* TARGETOS_symbian */ + +/* Main server module common for all transports + * This module will do the initial transport setups. + * Then it receives the command from client in CDC format + * and transmits the response back to the client. + * In the case of socket, it receives the command from the client + * and sends the response directly to the client via TCP socket. + * + * In the case of serial & wifi , it receives the command from the driver + * and sends the response to the driver. + */ +int +remote_server_exec(int argc, char **argv, void *wl) +{ + int err; + int transport_descriptor; + char *async_cmd_flag = NULL; + int skip; + int download_flag = 0; + FILE *fp = NULL; + char *fn = "dwnldfile.bin"; + char old_intf_name[IFNAMSIZ]; +#ifdef WIN32 + char shell_fname[MAX_SHELL_FILE_LENGTH]; + DWORD dwlen; +#endif +#ifdef RWL_DONGLE + int uart_enable = 1; + /* To set dongle flag when dongle server starts */ + if ((err = rwl_var_setbuf(wl, dongleset, &uart_enable, + sizeof(int))) < 0) { + DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", err); + } +#endif + if (rwl_iovar_check (wl) < 0) { + DPRINT_ERR(ERR, "wl_server: RWL_WIFI/RWL_DONGLE not defined "); + DPRINT_ERR(ERR, "Or In-Dongle mode enabled\n"); + exit(0); + } + /* Initialise for all the transports - socket, serial, and wifi + * In Socket transport, main socket handler will be returned. + */ + if ((transport_descriptor = rwl_transport_setup(argc, argv)) < 0) + return BCME_ERROR; + +#ifdef RWL_WIFI + remote_wifi_ser_init_cmds(wl); +#endif + /* Create a directory /tmp/RWL for the shell response files */ + if (rwl_create_dir() < 0) + return BCME_ERROR; + + +#ifdef RWLASD + /* DUT initialization function */ + wfa_dut_init(&trafficBuf, &respBuf, &parmsVal, &xcCmdBuf, &toutvalp); +#endif + + /* Copy old interface name to restore it */ + store_old_interface(wl, old_intf_name); + + while (1) { + uchar *buf_ptr = NULL; + char *errstr = NULL; +#ifdef VISTA_SERVER + int index; + char *vista_buf[MAX_VISTA_ARGC]; +#endif +#ifdef RWL_SERIAL + g_rwl_hndle = transport_descriptor; +#else + g_rwl_hndle = -1; +#endif +#ifdef RWL_DONGLE + if (set_ctrlc) { + uart_enable = 0; + if ((err = rwl_var_setbuf(wl, dongleset, &uart_enable, + sizeof(int))) < 0) { + DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", err); + } + set_ctrlc = 0; + exit(0); + } +#endif /* RWL_DONGLE */ + + /* Receive the CDC header */ + if ((remote_rx_header(wl, transport_descriptor)) == BCME_ERROR) { + DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n"); + continue; + } + + DPRINT_INFO(OUTPUT, "REC : cmd %d\t msg len %d msg flag %d\t msg status %d\n", + g_rem_ptr->msg.cmd, g_rem_ptr->msg.len, + g_rem_ptr->msg.flags, g_rem_ptr->msg.status); + +#ifdef RWL_WIFI + /* send the response to remote if it is findserver cmd, this is specific to wifi */ + if (g_rem_ptr->msg.flags & REMOTE_FINDSERVER_IOCTL) { + remote_wifi_response(wl); + continue; + } +#endif /* RWL_WIFI */ + + /* + * Allocate buffer only if there is a response message expected. + * Some commands such as up/down do not output anything. + */ + if (g_rem_ptr->msg.len) { + if ((buf_ptr = malloc(g_rem_ptr->msg.len)) == NULL) { + DPRINT_ERR(ERR, "malloc of %d bytes failed\n", g_rem_ptr->msg.len); + continue; + } + } + + /* Receive the data */ + if ((err = remote_rx_data(buf_ptr)) == BCME_ERROR) { + if (buf_ptr) + free(buf_ptr); + continue; + } + + /* Process RWL negotiate commands */ + if (g_rem_ptr->msg.flags & REMOTE_NEGOTIATE_CMD) { + if (g_rem_ptr->msg.cmd == NEGOTIATE_GET_OS) { + if (g_rem_ptr->msg.len >= sizeof(int)) { + *(int*)buf_ptr = LINUX_OS; + g_rem_ptr->msg.len = sizeof(int); + + DPRINT_INFO(OUTPUT, "RESP : os type %d\n", *(int*)buf_ptr); + if (remote_tx_response(wl, buf_ptr, 0) < 0) + DPRINT_ERR(ERR, "\nReturn results failed\n"); + } + } +#ifdef RWL_SOCKET + close_sock_handle(g_rwl_hndle); +#endif /* RWL_SOCKET */ + if (buf_ptr) + free(buf_ptr); + continue; + } + + /* Process command */ + if (g_rem_ptr->msg.flags & REMOTE_SHELL_CMD) { + /* Get the response length first and get the response buffer in case of + * synchronous shell commands and the buf_ptr will have the response file + * name. In case of asynchronous shell commands, buf_ptr + * will be get updated by the remote_shell_execute function. + */ + need_speedy_response = 1; +#ifndef WIN32 + if (buf_ptr) { + async_cmd_flag = strstr((char*)buf_ptr, "%"); + } + if ((err = remote_shell_execute((char*)buf_ptr, wl)) > 0) { + if (async_cmd_flag) + g_rem_ptr->msg.len = err; + } + /* Sync shell command: No need to send response from here */ + else { +#ifdef RWL_SOCKET + /* Transmitted to client. Then close the handle & + * get the new handle for next transmission & reception. + */ + close_sock_handle(g_rwl_hndle); +#endif /* RWL_SOCKET */ + continue; + } +#else + if ((err = remote_shell_execute((char*)buf_ptr, wl)) != SUCCESS) { + DPRINT_ERR(ERR, "Error in executing shell command\n"); + if (buf_ptr) + free(buf_ptr); +#ifdef RWL_SOCKET + /* Transmitted to client. Then close the handle & + * get the new handle for next transmission & reception. + */ + close_sock_handle(g_rwl_hndle); +#endif /* RWL_SOCKET */ + continue; + } + /* Get the response from the temporary file */ + if ((err = remote_shell_get_resp(shell_fname, wl)) != SUCCESS) { + DPRINT_ERR(ERR, "Error in executing shell command\n"); + } + if (buf_ptr) + free(buf_ptr); +#ifdef RWL_SOCKET + /* Transmitted to client. Then close the handle & + * get the new handle for next transmission & reception. + */ + close_sock_handle(g_rwl_hndle); +#endif /* RWL_SOCKET */ + continue; +#endif /* WIN32 */ + } /* REMOTE_SHELL_CMD */ + +#ifdef RWLASD + if (g_rem_ptr->msg.flags & REMOTE_ASD_CMD) { + if ((err = remote_asd_exec(buf_ptr, (int *)&g_rem_ptr->msg.len)) < 0) { + DPRINT_ERR(ERR, "Error in executing asd command\n"); + } + } /* REMOTE_ASD_CMD */ +#endif + +/* + * added to take care of OID base problem for cross OS RWL cleint server + * In case of LX Server and WIN32 client OID base need to be removed + * In case of WIN32 server and LX client OID base need to be added + */ + if (!(g_rem_ptr->msg.flags & REMOTE_ASD_CMD)) { + if (g_rem_ptr->msg.cmd > MAX_IOVAR) + g_rem_ptr->msg.cmd -= WL_OID_BASE; +#if defined(WIN32) + if (g_rem_ptr->msg.cmd < MAX_IOVAR) + g_rem_ptr->msg.cmd += WL_OID_BASE; +#endif + } +#ifdef VISTA_SERVER + if (g_rem_ptr->msg.flags & REMOTE_VISTA_CMD) { + vista_buf[0] = strtok(buf_ptr, " \t\n"); + for (index = 1; (vista_buf[index] = strtok(NULL, " \t\n")) != NULL; + index++); + if ((err = remote_vista_exec(wl, vista_buf)) < 0) { + DPRINT_ERR(ERR, "Error in executing vista command\n"); + } + memcpy(buf_ptr, vista_buf[0], strlen(vista_buf[0])); + g_rem_ptr->msg.len = strlen(vista_buf[0]); + } /* REMOTE_VISTA_CMD */ +#endif /* VISTA_SERVER */ + +#ifndef RWL_DONGLE + if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL || + g_rem_ptr->msg.flags & REMOTE_SET_IOCTL) { + if (strlen(g_rem_ptr->intf_name) != 0) { + struct ifreq ifr; + /* validate the interface */ + memset(&ifr, 0, sizeof(ifr)); + if (g_rem_ptr->intf_name) + strncpy(ifr.ifr_name, g_rem_ptr->intf_name, IFNAMSIZ); + + if (wl_check((void *)&ifr)) { + DPRINT_ERR(ERR, "%s: wl driver adapter not found\n", + g_rem_ptr->intf_name); + /* Signal end of command output */ + g_rem_ptr->msg.len = 0; + remote_tx_response(wl, NULL, BCME_NODEVICE); + if (buf_ptr) + free(buf_ptr); +#ifdef RWL_SOCKET + close_sock_handle(g_rwl_hndle); +#endif + continue; + } + + if (set_interface(wl, g_rem_ptr->intf_name) == BCME_OK) + DPRINT_DBG(OUTPUT, "\n %s Interface will be used \n", + (char *)wl); + } + } +#endif /* ifndef RWL_DONGLE */ + if (g_rem_ptr->msg.flags & REMOTE_SET_IOCTL || + g_rem_ptr->msg.flags & RDHD_SET_IOCTL) { +#ifdef WIN32 +#if defined(RWL_DONGLE) || defined(RWL_WIFI) + /* For commands with msg length as zero initialize the buffer to null */ + if (g_rem_ptr->msg.len == 0) + buf_ptr = NULL; +#endif +#else + if (g_rem_ptr->msg.len == 0) + buf_ptr = NULL; +#endif /* WIN32 */ + + if (g_rem_ptr->msg.flags & REMOTE_SET_IOCTL) { + if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr && + !strncmp((const char *)buf_ptr, + "init", g_rem_ptr->msg.len)) { + DPRINT_INFO(OUTPUT, "REC : init command\n"); + err = 0; + } else if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr && + !strncmp((const char *)buf_ptr, + "download", g_rem_ptr->msg.len)) { + DPRINT_INFO(OUTPUT, "REC : download command\n"); + download_flag = download_flag? 0: 1; + if (download_flag) { + DPRINT_INFO(OUTPUT, "download started\n"); + if (!(fp = fopen(fn, "wb"))) { + DPRINT_ERR(ERR, "Failed to open file\n"); + err = -2; + } + } else { + DPRINT_INFO(OUTPUT, "download completed\n"); + if (fp != NULL) + fclose(fp); + } + err = 0; + } else if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr && + !strncmp((const char *)buf_ptr, + "membytes", g_rem_ptr->msg.len)) { + DPRINT_INFO(OUTPUT, "REC : membytes command\n"); + skip = strlen("membytes ") + 8; + if (fp != NULL) + fwrite(buf_ptr + skip, 1, + g_rem_ptr->msg.len - skip, fp); + else + DPRINT_ERR(ERR, "Download file has been closed.\n"); + err = 0; + } else { + err = wl_ioctl(wl, g_rem_ptr->msg.cmd, + (void *)buf_ptr, g_rem_ptr->msg.len, TRUE); + DPRINT_INFO(OUTPUT, "SEND : cmd %d\t msg len %d\n", + g_rem_ptr->msg.cmd, g_rem_ptr->msg.len); + DPRINT_INFO(OUTPUT, "error code: %d\n", err); + } + } + if (err == BCME_IOCTL_ERROR) { + if (rwl_var_getbuf(wl, "bcmerrorstr", NULL, 0, (void**)&errstr)) { + DPRINT_ERR(ERR, "Error in executing wl_ioctl\r\n"); + } else { + DPRINT_ERR(ERR, "%s\n", errstr); + } + DPRINT_ERR(ERR, "Setting Default Interface1 \n"); + set_interface(wl, old_intf_name); + } + + if (g_rem_ptr->msg.flags & RDHD_SET_IOCTL) { + err = dhd_ioctl(wl, g_rem_ptr->msg.cmd, + (void *)buf_ptr, g_rem_ptr->msg.len, TRUE); + } + g_rem_ptr->msg.flags = REMOTE_SET_IOCTL; + + } /* RDHD/REMOTE_SET_IOCTL */ + + if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL || + g_rem_ptr->msg.flags & RDHD_GET_IOCTL) { + if (g_rem_ptr->msg.cmd == WLC_GET_VAR && buf_ptr && + strncmp((const char *)buf_ptr, "exit", g_rem_ptr->msg.len) == 0) { + /* exit command from remote client terminates server */ + free(buf_ptr); + break; + } + if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL) + err = wl_ioctl(wl, g_rem_ptr->msg.cmd, (void *)buf_ptr, + g_rem_ptr->msg.len, FALSE); + if (err == BCME_IOCTL_ERROR) { + if (rwl_var_getbuf(wl, "bcmerrorstr", NULL, 0, (void**)&errstr)) { + DPRINT_ERR(ERR, + "REMOTE_GET_IOCTL::Error in executing wl_ioctl\n"); + } else { + DPRINT_ERR(ERR, "%s\n", errstr); + } + DPRINT_ERR(ERR, "Setting Default Interface \n"); + set_interface(wl, old_intf_name); + } + + if (g_rem_ptr->msg.flags & RDHD_GET_IOCTL) + err = dhd_ioctl(wl, g_rem_ptr->msg.cmd, (void *)buf_ptr, + g_rem_ptr->msg.len, FALSE); + g_rem_ptr->msg.flags = REMOTE_GET_IOCTL; + } /* REMOTE_GET_IOCTL */ + DPRINT_INFO(OUTPUT, "RESP : cmd %d\t msg len %d\n", + g_rem_ptr->msg.cmd, g_rem_ptr->msg.len); + /* setting back default interface */ + set_interface(wl, old_intf_name); + /* Transmit the response results */ + if (remote_tx_response(wl, buf_ptr, err) < 0) { + DPRINT_ERR(ERR, "\nReturn results failed\n"); + } + +#ifdef RWL_SOCKET + if (g_rem_ptr->msg.flags != REMOTE_SHELL_CMD) + /* Transmitted to client. Then close the handle & get the new handle + * for next transmission & reception. In case of shell commands this + * should be closed in respective shellproc files. + */ + close_sock_handle(g_rwl_hndle); +#endif /* RWL_SOCKET */ + + if (buf_ptr) { + free(buf_ptr); + } + } /* end of while */ +#if defined(RWL_SOCKET) + /* Close the main handle for socket */ + close_sock_handle(transport_descriptor); +#elif defined(RWL_SERIAL) + /* Close the main handle for serial pipe */ + rwl_close_pipe(remote_type, (void*)&transport_descriptor); +#endif + +#ifdef RWLASD + wfa_dut_deinit(); +#endif + + return err; +}
diff --git a/src/wl/exe/wlu_server_shared.h b/src/wl/exe/wlu_server_shared.h new file mode 100644 index 0000000..a63b5c1 --- /dev/null +++ b/src/wl/exe/wlu_server_shared.h
@@ -0,0 +1,67 @@ +/* + * wl server declarations + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: wlu_server_shared.h 287128 2011-09-30 04:27:53Z $ + */ + +#ifndef _wlu_server_shared_h +#define _wlu_server_shared_h + + extern int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set); + + extern int dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set); + +#ifdef RWLASD +/* streams' buffers */ +BYTE *xcCmdBuf = NULL, *parmsVal = NULL; +BYTE *trafficBuf = NULL, *respBuf = NULL; +struct timeval *toutvalp = NULL; +#endif + +#define POLLING_TIME 200 +#define DONGLE_TX_FRAME_SIZE 1024 +#define MESSAGE_LENGTH 1024 +#define MAX_SHELL_FILE_LENGTH 50 +#define MAX_IOVAR 10000 +int remote_type = NO_REMOTE; +rem_ioctl_t *g_rem_ptr; + +extern int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set); + +/* Function prototypes from shellpoc_linux.c/shell_ce.c */ +extern int rwl_create_dir(void); +extern int remote_shell_execute(char *buf_ptr, void *wl); +extern int remote_shell_get_resp(char* shell_fname, void *wl); +extern void rwl_wifi_find_server_response(void *wl, dot11_action_wifi_vendor_specific_t *rec_frame); +extern dot11_action_wifi_vendor_specific_t *rwl_wifi_allocate_actionframe(void); + +/* Common code for serial and wifi */ +#if defined(RWL_DONGLE) || defined(RWL_WIFI) || defined(RWL_SERIAL) +typedef struct rem_packet { + rem_ioctl_t rem_cdc; + uchar message[MESSAGE_LENGTH]; +} rem_packet_t; +#define REMOTE_PACKET_SIZE sizeof(rem_packet_t) + +rem_packet_t *g_rem_pkt_ptr; +rem_packet_t g_rem_pkt; +#endif + +static struct ether_addr rwlea; + +static union { + uchar bufdata[WLC_IOCTL_MAXLEN]; + uint32 alignme; +} bufstruct_wlu; +static uchar* rwl_buf = (uchar*) &bufstruct_wlu.bufdata; +extern int need_speedy_response; + +#endif /* _wlu_server_shared_h_ */
diff --git a/src/wl/phymods/cmn/hal/include/phy_dbg_api.h b/src/wl/phymods/cmn/hal/include/phy_dbg_api.h new file mode 100644 index 0000000..ced8146 --- /dev/null +++ b/src/wl/phymods/cmn/hal/include/phy_dbg_api.h
@@ -0,0 +1,35 @@ +/* + * Debug module public interface (to MAC driver). + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id$ + */ + +#ifndef _phy_dbg_api_h_ +#define _phy_dbg_api_h_ + +/* Debug message levels */ +#define PHYHAL_ERROR 0x0001 +#define PHYHAL_TRACE 0x0002 +#define PHYHAL_INFORM 0x0004 +#define PHYHAL_TMP 0x0008 +#define PHYHAL_TXPWR 0x0010 +#define PHYHAL_CAL 0x0020 +#define PHYHAL_ACI 0x0040 +#define PHYHAL_RADAR 0x0080 +#define PHYHAL_THERMAL 0x0100 +#define PHYHAL_PAPD 0x0200 +#define PHYHAL_FCBS 0x0400 +#define PHYHAL_WD 0x0800 +#define PHYHAL_RXIQ 0x1000 + +#define PHYHAL_TIMESTAMP 0x8000 + +#endif /* _phy_dbg_api_h_ */
diff --git a/src/wl/ppr/include/wlc_ppr.h b/src/wl/ppr/include/wlc_ppr.h new file mode 100644 index 0000000..0329a75 --- /dev/null +++ b/src/wl/ppr/include/wlc_ppr.h
@@ -0,0 +1,360 @@ +/* + * PHY module Power-per-rate API. Provides interface functions and definitions for opaque + * ppr structure for use containing regulatory and board limits and tx power targets. + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: $ + */ + +#ifndef _wlc_ppr_h_ +#define _wlc_ppr_h_ + +#include <bcmwifi_rates.h> +#include <bcmutils.h> +#ifdef BCMDRIVER +#include <osl.h> +#else +#define osl_t void +#endif + +/* Helper macro */ +#define PPR_CHSPEC_BW(x) (CHSPEC_IS80(x) ? WL_TX_BW_80 : \ + (CHSPEC_IS40(x) ? WL_TX_BW_40 : WL_TX_BW_20)) + +#ifndef BCMPHYCORENUM +#define PPR_MAX_TX_CHAINS 3 +#else +#if (BCMPHYCORENUM < 1) || (BCMPHYCORENUM > 3) +#error Invalid number of PHY cores +#endif /* BCMPHYCORENUM < 1 || BCMPHYCORENUM > 3 */ +#define PPR_MAX_TX_CHAINS (BCMPHYCORENUM) +#endif /* !defined(BCMPHYCORENUM) */ + +/* Opaque PPR data - it keeps its structure to itself */ +typedef struct ppr ppr_t; + + +/* Power values for DSSS 1, 2, 5.5, 11 */ +typedef struct ppr_dsss_rateset { int8 pwr[WL_RATESET_SZ_DSSS]; } ppr_dsss_rateset_t; + +/* Power values for OFDM 6, 9, 12... 54 */ +typedef struct ppr_ofdm_rateset { int8 pwr[WL_RATESET_SZ_OFDM]; } ppr_ofdm_rateset_t; + +/* Power values one set of 8 HT MCS values (0-7, 8-15, etc) */ +typedef struct ppr_ht_mcs_rateset { int8 pwr[WL_RATESET_SZ_HT_MCS]; } ppr_ht_mcs_rateset_t; + +/* Power values one set of 10 VHT MCS values (0-9) */ +typedef struct ppr_vht_mcs_rateset { int8 pwr[WL_RATESET_SZ_VHT_MCS]; } ppr_vht_mcs_rateset_t; + + +/* API Routines */ + +/* Initialization routine for opaque PPR struct */ +void ppr_init(ppr_t* pprptr, wl_tx_bw_t bw); + +/* Reinitialization routine for opaque PPR struct */ +void ppr_clear(ppr_t* pprptr); + + +/* Size routine for user alloc/dealloc */ +uint32 ppr_size(wl_tx_bw_t bw); + +/* Size routine for user serialization alloc */ +uint32 ppr_ser_size(const ppr_t* pprptr); + +/* Size routine for user serialization alloc for a given bw */ +uint32 ppr_ser_size_by_bw(wl_tx_bw_t bw); + +/* Init allocated memory with a ppr serialization head + * This function must be called if serialization side has different + * compilation conditions (e.g PPR_MAX_TX_CHAINS, WL_BEAMFORMING etc.) + */ +int ppr_init_ser_mem_by_bw(uint8* pbuf, wl_tx_bw_t bw, uint32 len); + +/* Init allocated memory with a ppr serialization head for the given ppr pointer + * This function must be called if serialization side has different + * compilation conditions (e.g PPR_MAX_TX_CHAINS, WL_BEAMFORMING etc.) + */ +int ppr_init_ser_mem(uint8* pbuf, ppr_t * ppr, uint32 len); + +/* Constructor routine for opaque PPR struct */ +ppr_t* ppr_create(osl_t *osh, wl_tx_bw_t bw); + +/* Destructor routine for opaque PPR struct */ +void ppr_delete(osl_t *osh, ppr_t* pprptr); + +/* Type routine for inferring opaque structure size */ +wl_tx_bw_t ppr_get_ch_bw(const ppr_t* pprptr); + +/* Type routine to get ppr supported maximum bw */ +wl_tx_bw_t ppr_get_max_bw(void); + +/* Get the DSSS values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_get_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains, + ppr_dsss_rateset_t* dsss); + +/* Get the OFDM values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_get_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains, + ppr_ofdm_rateset_t* ofdm); + +/* Get the HT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_get_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, ppr_ht_mcs_rateset_t* mcs); + +/* Get the VHT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_get_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, ppr_vht_mcs_rateset_t* mcs); + +/* Get the minimum power for a VHT MCS rate specified by Nss, with the given bw and tx chains. + * Disabled rates are ignored + */ +int ppr_get_vht_mcs_min(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, int8* mcs_min); + + +/* Routines to set target powers per rate for a whole rate set */ + +/* Set the DSSS values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_set_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains, + const ppr_dsss_rateset_t* dsss); + +/* Set the OFDM values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_set_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains, + const ppr_ofdm_rateset_t* ofdm); + +/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_set_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, const ppr_ht_mcs_rateset_t* mcs); + +/* Set the VHT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_set_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, const ppr_vht_mcs_rateset_t* mcs); + + +/* Routines to set a whole rate set to a single target value */ + +/* Set the DSSS values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_set_same_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains, const int8 power); + +/* Set the OFDM values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_set_same_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains, + const int8 power); + +/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_set_same_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, const int8 power); + + +/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_set_same_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, const int8 power); + + +/* Helper routines to operate on the entire ppr set */ + +/* Ensure no rate limit is greater than the specified maximum */ +uint ppr_apply_max(ppr_t* pprptr, int8 max); + +/* Make disabled rates explicit. If one rate in a group is disabled, disable the whole group */ +int ppr_force_disabled(ppr_t* pprptr, int8 threshold); + +/* + * Reduce total transmitted power to level of constraint. + * For two chain rates, the per-antenna power must be halved. + * For three chain rates, it must be a third of the constraint. + */ +uint ppr_apply_constraint_total_tx(ppr_t* pprptr, int8 constraint); + +/* Ensure no rate limit is lower than the specified minimum */ +uint ppr_apply_min(ppr_t* pprptr, int8 min); + + +/* Ensure no rate limit in this ppr set is greater than the corresponding limit in ppr_cap */ +uint ppr_apply_vector_ceiling(ppr_t* pprptr, const ppr_t* ppr_cap); + +/* Ensure no rate limit in this ppr set is lower than the corresponding limit in ppr_min */ +uint ppr_apply_vector_floor(ppr_t* pprptr, const ppr_t* ppr_min); + + +/* Get the maximum power in the ppr set */ +int8 ppr_get_max(ppr_t* pprptr); + +/* + * Get the minimum power in the ppr set excluding disallowed + * rates and powers set to the minimum for the phy + */ +int8 ppr_get_min(ppr_t* pprptr, int8 floor); + + +/* Get the maximum power for a given bandwidth in the ppr set */ +int8 ppr_get_max_for_bw(ppr_t* pprptr, wl_tx_bw_t bw); + +/* Get the minimum power for a given bandwidth in the ppr set */ +int8 ppr_get_min_for_bw(ppr_t* pprptr, wl_tx_bw_t bw); + + +typedef void (*ppr_mapfn_t)(void *context, uint8 *a, uint8 *b); + +/* Map the given function with its context value over the two power vectors */ +void ppr_map_vec_dsss(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, + ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_chains_t tx_chains); + +/* Map the given function with its context value over the two power vectors */ +void ppr_map_vec_ofdm(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, + ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains); + +/* Map the given function with its context value over the two power vectors */ +void ppr_map_vec_ht_mcs(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, + ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains); + +/* Map the given function with its context value over the two power vectors */ +void ppr_map_vec_vht_mcs(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, + ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains); + +/* Map the given function with its context value over the two power vectors */ +void ppr_map_vec_all(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2); + +/* Get the first index that is larger than a given power level */ +int16 ppr_get_idx(ppr_t* pprptr, int8 pwr); + +/* Set PPR struct to a certain power level */ +void ppr_set_cmn_val(ppr_t* pprptr, int8 val); + +/* Make an identical copy of a ppr structure (for ppr_bw==all case) */ +void ppr_copy_struct(ppr_t* pprptr_s, ppr_t* pprptr_d); + +/* Subtract each power from a common value and re-store */ +void ppr_cmn_val_minus(ppr_t* pprptr, int8 val); + +/* Compare two ppr variables p1 and p2, save the min. value of each + * contents to variable p1 + */ +void ppr_compare_min(ppr_t* p1, ppr_t* p2); + +/* compare two ppr variables p1 and p2, save the max. value of each + * contents to variable p1 + */ +void ppr_compare_max(ppr_t* p1, ppr_t* p2); + +/* Serialize the contents of the opaque ppr struct. + * Writes number of bytes copied, zero on error. + * Returns error code, BCME_OK if successful. + */ +int ppr_serialize(const ppr_t* pprptr, uint8* buf, uint buflen, uint* bytes_copied); + +/* Deserialize the contents of a buffer into an existing opaque ppr struct. + * The ppr struct *must* be of the same type as the one that was serialized. + * Returns error code, BCME_OK if successful. + */ +int ppr_deserialize(ppr_t* pprptr, const uint8* buf, uint buflen); + +/* Deserialize the contents of a buffer into a new opaque ppr struct. + * Creates an opaque structure referenced by *pptrptr, NULL on error. + * Returns error code, BCME_OK if successful. + */ +int ppr_deserialize_create(osl_t *osh, const uint8* buf, uint buflen, ppr_t** pprptr); + +/* Subtract a common value from each power and re-store */ +void ppr_minus_cmn_val(ppr_t* pprptr, int8 val); + +/* Add a common value to the given bw struct components */ +void ppr_plus_cmn_val(ppr_t* pprptr, int8 val); + +/* Multiply a percentage */ +void ppr_multiply_percentage(ppr_t* pprptr, uint8 val); + + +#ifdef WLTXPWR_CACHE + +/** + * Usage of the WLTXPWR_CACHE API: + * 1. Reserve one or more entries in the cache for a specific chanspec: + * wlc_phy_txpwr_setup_entry(chanspec1); + * wlc_phy_txpwr_setup_entry(chanspec2); + * 2. Use any of the getter/setter functions. Note that they may return an error on a chanspec + * that was not reserved. For setter functions, for pointer type arguments (e.g. ppr_t), the + * cache maintains a reference to the caller provided object rather than copying it. + * 3. Use wlc_phy_txpwr_cache_clear() or wlc_phy_txpwr_cache_invalidate() to get rid of cache + * entries. Note that this clears, amongst others, ppr_t structs. + * + * For non-BMAC builds, only the cache is allowed to delete the ppr_t object, and the driver code is + * not allowed to reuse it for another channel as it can when the cache is not being used. + * + * For BMAC builds, the cache has to be made to release the stf offsets object to avoid some nasty + * race conditions. + * + * Mike thinks when this is reimplemented for trunk he would consider having a reference count + * associated with each object to make this cleaner. + * + * Note that the functions start with wlc_phy_* despite not residing in the PHY code. This is + * probably for historical reasons. + */ + +enum txpwr_cache_info_type { + TXPWR_CACHE_STF_OFFSETS, /* PPR offsets for stf */ + TXPWR_CACHE_POWER_OFFSETS, /* PPR offsets for phy */ + TXPWR_CACHE_NUM_TYPES, /* How many types of pwr info */ +}; + +#define TXPWR_STF_PWR_MIN_INVALID 0x80 +#define TXPWR_STF_TARGET_PWR_MIN_INVALID 0x40 +#define TXPWR_STF_TARGET_PWR_NOT_CACHED 0x20 + +extern ppr_t* wlc_phy_get_cached_pwr(chanspec_t chanspec, uint pwr_type); + +extern int wlc_phy_set_cached_pwr(osl_t *osh, chanspec_t chanspec, uint pwr_type, ppr_t* pwrptr); + +extern uint8 wlc_phy_get_cached_pwr_max(chanspec_t chanspec, uint core); + +extern int wlc_phy_set_cached_pwr_max(chanspec_t chanspec, uint core, uint8 max_pwr); + +extern uint8 wlc_phy_get_cached_pwr_min(chanspec_t chanspec, uint core); + +extern int wlc_phy_set_cached_pwr_min(chanspec_t chanspec, uint core, uint8 min_pwr); + +extern int wlc_phy_get_cached_stf_target_pwr_min(chanspec_t chanspec); + +extern int wlc_phy_set_cached_stf_target_pwr_min(chanspec_t chanspec, int min_pwr); + +extern int8 wlc_phy_get_cached_txchain_offsets(chanspec_t chanspec, uint core); + +extern int wlc_phy_set_cached_txchain_offsets(chanspec_t chanspec, uint core, int8 offset); + +extern bool wlc_phy_txpwr_cache_is_cached(chanspec_t chanspec); + +extern bool wlc_phy_is_pwr_cached(uint pwr_type, ppr_t* pwrptr); + +extern void wlc_phy_uncache_pwr(uint pwr_type, ppr_t* pwrptr); + +extern chanspec_t wlc_phy_txpwr_cache_find_other_cached_chanspec(chanspec_t chanspec); + +extern void wlc_phy_txpwr_cache_clear(osl_t *osh, chanspec_t chanspec); + +extern void wlc_phy_txpwr_cache_invalidate(void); + +extern void wlc_phy_txpwr_cache_close(osl_t *osh); + +extern int wlc_phy_txpwr_setup_entry(chanspec_t chanspec); + +extern bool wlc_phy_get_stf_ppr_cached(chanspec_t chanspec); + +extern void wlc_phy_set_stf_ppr_cached(chanspec_t chanspec, bool bcached); + +extern int wlc_phy_get_cached_stf_pwr_min_dbm(void); + +extern void wlc_phy_set_cached_stf_pwr_min_dbm(int min_pwr); + +extern void wlc_phy_set_cached_stf_max_offset(chanspec_t chanspec, uint8 max_offset); + +extern uint8 wlc_phy_get_cached_stf_max_offset(chanspec_t chanspec); +#endif /* WLTXPWR_CACHE */ +#endif /* _wlc_ppr_h_ */
diff --git a/src/wl/ppr/src/wlc_ppr.c b/src/wl/ppr/src/wlc_ppr.c new file mode 100644 index 0000000..448821a --- /dev/null +++ b/src/wl/ppr/src/wlc_ppr.c
@@ -0,0 +1,2456 @@ +/* + * PHY module Power-per-rate API. Provides interface functions and definitions for + * ppr structure for use containing regulatory and board limits and tx power targets. + * + * Copyright (C) 2016, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: $ + */ + + +#include <typedefs.h> +#include <bcmendian.h> +#include <bcmwifi_channels.h> +#include <wlc_ppr.h> + +#ifndef BCMDRIVER + +#ifndef WL_BEAMFORMING +#define WL_BEAMFORMING /* enable TxBF definitions for utility code */ +#endif + +#ifndef bcopy +#include <string.h> +#include <stdlib.h> +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#endif + +#ifndef ASSERT +#define ASSERT(exp) do {} while (0) +#endif +#endif /* BCMDRIVER */ + +/* ppr local TXBF_ENAB() macro because wlc->pub struct is not accessible */ +#ifdef WL_BEAMFORMING +#if defined(WLTXBF_DISABLED) +#define PPR_TXBF_ENAB() (0) +#else +#define PPR_TXBF_ENAB() (1) +#endif +#else +#define PPR_TXBF_ENAB() (0) +#endif /* WL_BEAMFORMING */ + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + +#define PPR_SERIALIZATION_VER 1 + +/* ppr deserialization header */ +typedef BWL_PRE_PACKED_STRUCT struct ppr_deser_header { + uint8 version; + uint8 bw; + uint16 per_band_size; + uint32 flags; +} BWL_POST_PACKED_STRUCT ppr_deser_header_t; + + +typedef BWL_PRE_PACKED_STRUCT struct ppr_ser_mem_flag { + uint32 magic_word; + uint32 flag; +} BWL_POST_PACKED_STRUCT ppr_ser_mem_flag_t; + + +#define WLC_TXPWR_DB_FACTOR 4 /* conversion for phy txpwr cacluations that use .25 dB units */ + + +/* QDB() macro takes a dB value and converts to a quarter dB value */ +#ifdef QDB +#undef QDB +#endif +#define QDB(n) ((n) * WLC_TXPWR_DB_FACTOR) + + +/* Flag bits in serialization/deserialization */ +#define PPR_MAX_TX_CHAIN_MASK 0x00000003 /* mask of Tx chains */ +#define PPR_BEAMFORMING 0x00000004 /* bit indicates BF is on */ +#define PPR_SER_MEM_WORD 0xBEEFC0FF /* magic word indicates serialization start */ + + +/* size of serialization header */ +#define SER_HDR_LEN sizeof(ppr_deser_header_t) + + +/* Per band tx powers */ +typedef BWL_PRE_PACKED_STRUCT struct pprpb { + /* start of 20MHz tx power limits */ + int8 p_1x1dsss[WL_RATESET_SZ_DSSS]; /* Legacy CCK/DSSS */ + int8 p_1x1ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM transmission */ + int8 p_1x1vhtss1[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 1x1mcs0 */ +#if (PPR_MAX_TX_CHAINS > 1) + int8 p_1x2dsss[WL_RATESET_SZ_DSSS]; /* Legacy CCK/DSSS */ + int8 p_1x2cdd_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM CDD transmission */ + int8 p_1x2cdd_vhtss1[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 1x2cdd_mcs0 */ + int8 p_2x2stbc_vhtss1[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 2x2stbc_mcs0 */ + int8 p_2x2vhtss2[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 2x2sdm_mcs8 */ +#if (PPR_MAX_TX_CHAINS > 2) + int8 p_1x3dsss[WL_RATESET_SZ_DSSS]; /* Legacy CCK/DSSS */ + int8 p_1x3cdd_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM CDD transmission */ + int8 p_1x3cdd_vhtss1[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 1x3cdd_mcs0 */ + int8 p_2x3stbc_vhtss1[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 2x3stbc_mcs0 */ + int8 p_2x3vhtss2[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 2x3sdm_mcs8 spexp1 */ + int8 p_3x3vhtss3[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 3x3sdm_mcs16 */ +#endif + +#ifdef WL_BEAMFORMING + int8 p_1x2txbf_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM TXBF transmission */ + int8 p_1x2txbf_vhtss1[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 1x2txbf_mcs0 */ + int8 p_2x2txbf_vhtss2[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 2x2txbf_mcs8 */ +#if (PPR_MAX_TX_CHAINS > 2) + int8 p_1x3txbf_ofdm[WL_RATESET_SZ_OFDM]; /* 20 MHz Legacy OFDM TXBF transmission */ + int8 p_1x3txbf_vhtss1[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 1x3txbf_mcs0 */ + int8 p_2x3txbf_vhtss2[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 2x3txbf_mcs8 */ + int8 p_3x3txbf_vhtss3[WL_RATESET_SZ_VHT_MCS]; /* 8HT/10VHT pwrs starting at 3x3txbf_mcs16 */ +#endif +#endif /* WL_BEAMFORMING */ +#endif /* PPR_MAX_TX_CHAINS > 1 */ +} BWL_POST_PACKED_STRUCT pprpbw_t; + + +#define PPR_CHAIN1_FIRST OFFSETOF(pprpbw_t, p_1x1dsss) +#define PPR_CHAIN1_END (OFFSETOF(pprpbw_t, p_1x1vhtss1) + sizeof(((pprpbw_t *)0)->p_1x1vhtss1)) +#define PPR_CHAIN1_SIZE PPR_CHAIN1_END +#if (PPR_MAX_TX_CHAINS > 1) +#define PPR_CHAIN2_FIRST OFFSETOF(pprpbw_t, p_1x2dsss) +#define PPR_CHAIN2_FIRST_MCS OFFSETOF(pprpbw_t, p_1x2cdd_vhtss1) +#define PPR_CHAIN2_END (OFFSETOF(pprpbw_t, p_2x2vhtss2) + sizeof(((pprpbw_t *)0)->p_2x2vhtss2)) +#define PPR_CHAIN2_SIZE (PPR_CHAIN2_END - PPR_CHAIN2_FIRST) +#define PPR_CHAIN2_MCS_SIZE (PPR_CHAIN2_END - PPR_CHAIN2_FIRST_MCS) +#if (PPR_MAX_TX_CHAINS > 2) +#define PPR_CHAIN3_FIRST OFFSETOF(pprpbw_t, p_1x3dsss) +#define PPR_CHAIN3_FIRST_MCS OFFSETOF(pprpbw_t, p_1x3cdd_vhtss1) +#define PPR_CHAIN3_END (OFFSETOF(pprpbw_t, p_3x3vhtss3) + sizeof(((pprpbw_t *)0)->p_3x3vhtss3)) +#define PPR_CHAIN3_SIZE (PPR_CHAIN3_END - PPR_CHAIN3_FIRST) +#define PPR_CHAIN3_MCS_SIZE (PPR_CHAIN3_END - PPR_CHAIN3_FIRST_MCS) +#endif + +#ifdef WL_BEAMFORMING +#define PPR_BF_CHAIN2_FIRST OFFSETOF(pprpbw_t, p_1x2txbf_ofdm) +#define PPR_BF_CHAIN2_FIRST_MCS OFFSETOF(pprpbw_t, p_1x2txbf_vhtss1) +#define PPR_BF_CHAIN2_END (OFFSETOF(pprpbw_t, p_2x2txbf_vhtss2) + \ + sizeof(((pprpbw_t *)0)->p_2x2txbf_vhtss2)) +#define PPR_BF_CHAIN2_SIZE (PPR_BF_CHAIN2_END - PPR_BF_CHAIN2_FIRST) +#define PPR_BF_CHAIN2_MCS_SIZE (PPR_BF_CHAIN2_END - PPR_BF_CHAIN2_FIRST_MCS) +#if (PPR_MAX_TX_CHAINS > 2) +#define PPR_BF_CHAIN3_FIRST OFFSETOF(pprpbw_t, p_1x3txbf_ofdm) +#define PPR_BF_CHAIN3_FIRST_MCS OFFSETOF(pprpbw_t, p_1x3txbf_vhtss1) +#define PPR_BF_CHAIN3_END (OFFSETOF(pprpbw_t, p_3x3txbf_vhtss3) + \ + sizeof(((pprpbw_t *)0)->p_3x3txbf_vhtss3)) +#define PPR_BF_CHAIN3_SIZE (PPR_BF_CHAIN3_END - PPR_BF_CHAIN3_FIRST) +#define PPR_BF_CHAIN3_MCS_SIZE (PPR_BF_CHAIN3_END - PPR_BF_CHAIN3_FIRST_MCS) +#endif + +#endif /* WL_BEAMFORMING */ +#endif /* PPR_MAX_TX_CHAINS > 1 */ + + +#define PPR_BW_MAX WL_TX_BW_80 /* Maximum supported bandwidth */ + +/* Structure to contain ppr values for a 20MHz channel */ +typedef BWL_PRE_PACKED_STRUCT struct ppr_bw_20 { + /* 20MHz tx power limits */ + pprpbw_t b20; +} BWL_POST_PACKED_STRUCT ppr_bw_20_t; + + +/* Structure to contain ppr values for a 40MHz channel */ +typedef BWL_PRE_PACKED_STRUCT struct ppr_bw_40 { + /* 40MHz tx power limits */ + pprpbw_t b40; + /* 20in40MHz tx power limits */ + pprpbw_t b20in40; +} BWL_POST_PACKED_STRUCT ppr_bw_40_t; + + +/* Structure to contain ppr values for an 80MHz channel */ +typedef BWL_PRE_PACKED_STRUCT struct ppr_bw_80 { + /* 80MHz tx power limits */ + pprpbw_t b80; + /* 20in80MHz tx power limits */ + pprpbw_t b20in80; + /* 40in80MHz tx power limits */ + pprpbw_t b40in80; +} BWL_POST_PACKED_STRUCT ppr_bw_80_t; + + +/* + * This is the initial implementation of the structure we're hiding. It is sized to contain only + * the set of powers it requires, so the union is not necessarily the size of the largest member. + */ + +BWL_PRE_PACKED_STRUCT struct ppr { + wl_tx_bw_t ch_bw; + + BWL_PRE_PACKED_STRUCT union { + ppr_bw_20_t ch20; + ppr_bw_40_t ch40; + ppr_bw_80_t ch80; + } ppr_bw; +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + + +/* Returns a flag of ppr conditions (chains, txbf etc.) */ +static uint32 ppr_get_flag(void) +{ + uint32 flag = 0; + flag |= PPR_MAX_TX_CHAINS & PPR_MAX_TX_CHAIN_MASK; +#if PPR_MAX_TX_CHAINS > 1 + if (PPR_TXBF_ENAB()) { + flag |= PPR_BEAMFORMING; + } +#endif + return flag; +} + +static uint16 ppr_ser_size_per_band(uint32 flags) +{ + uint16 ret = PPR_CHAIN1_SIZE; /* at least 1 chain rates should be there */ + uint8 chain = flags & PPR_MAX_TX_CHAIN_MASK; + bool bf = (flags & PPR_BEAMFORMING) != 0; + BCM_REFERENCE(chain); + BCM_REFERENCE(bf); +#if (PPR_MAX_TX_CHAINS > 1) + if (chain > 1) { + ret += PPR_CHAIN2_SIZE; + } +#if (PPR_MAX_TX_CHAINS > 2) + if (chain > 2) { + ret += PPR_CHAIN3_SIZE; + } +#endif + +#ifdef WL_BEAMFORMING + if (PPR_TXBF_ENAB() && bf) { + ret += PPR_BF_CHAIN2_SIZE; + } +#if (PPR_MAX_TX_CHAINS > 2) + if (PPR_TXBF_ENAB() && bf && chain > 2) { + ret += PPR_BF_CHAIN3_SIZE; + } +#endif +#endif /* WL_BEAMFORMING */ +#endif /* PPR_MAX_TX_CHAINS > 1 */ + return ret; +} + +/* Return the required serialization size based on the flag field. */ +static uint ppr_ser_size_by_flag(uint32 flag, wl_tx_bw_t bw) +{ + uint ret = ppr_ser_size_per_band(flag); + switch (bw) { + case WL_TX_BW_20: + break; + case WL_TX_BW_40: + ret *= sizeof(ppr_bw_40_t)/sizeof(pprpbw_t); + break; + case WL_TX_BW_80: + ret *= sizeof(ppr_bw_80_t)/sizeof(pprpbw_t); + break; + default: + ASSERT(0); + } + return ret; +} + +#define COPY_PPR_TOBUF(x, y) do { bcopy(&pprbuf[x], *buf, y); \ + *buf += y; ret += y; } while (0); + + +/* Serialize ppr data of a bandwidth into the given buffer */ +static uint ppr_serialize_block(const uint8* pprbuf, uint8** buf, uint32 serflag) +{ + uint ret = 0; +#if (PPR_MAX_TX_CHAINS > 1) + uint chain = serflag & PPR_MAX_TX_CHAIN_MASK; /* chain number in serialized block */ + bool bf = (serflag & PPR_BEAMFORMING) != 0; +#endif + + COPY_PPR_TOBUF(PPR_CHAIN1_FIRST, PPR_CHAIN1_SIZE); +#if (PPR_MAX_TX_CHAINS > 1) + BCM_REFERENCE(bf); + if (chain > 1) { + COPY_PPR_TOBUF(PPR_CHAIN2_FIRST, PPR_CHAIN2_SIZE); + } +#if (PPR_MAX_TX_CHAINS > 2) + if (chain > 2) { + COPY_PPR_TOBUF(PPR_CHAIN3_FIRST, PPR_CHAIN3_SIZE); + } +#endif +#ifdef WL_BEAMFORMING + if (PPR_TXBF_ENAB() && bf) { + COPY_PPR_TOBUF(PPR_BF_CHAIN2_FIRST, PPR_BF_CHAIN2_SIZE); + } +#if (PPR_MAX_TX_CHAINS > 2) + if (PPR_TXBF_ENAB() && bf && chain > 2) { + COPY_PPR_TOBUF(PPR_BF_CHAIN3_FIRST, PPR_BF_CHAIN3_SIZE); + } +#endif +#endif /* WL_BEAMFORMING */ +#endif /* (PPR_MAX_TX_CHAINS > 1) */ + return ret; +} + + +/* Serialize ppr data of each bandwidth into the given buffer, returns bytes copied */ +static uint ppr_serialize_data(const ppr_t *pprptr, uint8* buf, uint32 serflag) +{ + uint ret = sizeof(ppr_deser_header_t); + ppr_deser_header_t* header = (ppr_deser_header_t*)buf; + ASSERT(pprptr && buf); + header->version = PPR_SERIALIZATION_VER; + header->bw = (uint8)pprptr->ch_bw; + header->flags = HTON32(ppr_get_flag()); + header->per_band_size = HTON16(ppr_ser_size_per_band(serflag)); + + buf += sizeof(*header); + switch (header->bw) { + case WL_TX_BW_20: + { + const uint8* pprbuf = (const uint8*)&pprptr->ppr_bw.ch20.b20; + ret += ppr_serialize_block(pprbuf, &buf, serflag); + } + break; + case WL_TX_BW_40: + { + const uint8* pprbuf = (const uint8*)&pprptr->ppr_bw.ch40.b40; + ret += ppr_serialize_block(pprbuf, &buf, serflag); + pprbuf = (const uint8*)&pprptr->ppr_bw.ch40.b20in40; + ret += ppr_serialize_block(pprbuf, &buf, serflag); + } + break; + case WL_TX_BW_80: + { + const uint8* pprbuf = (const uint8*)&pprptr->ppr_bw.ch80.b80; + ret += ppr_serialize_block(pprbuf, &buf, serflag); + pprbuf = (const uint8*)&pprptr->ppr_bw.ch80.b20in80; + ret += ppr_serialize_block(pprbuf, &buf, serflag); + pprbuf = (const uint8*)&pprptr->ppr_bw.ch80.b40in80; + ret += ppr_serialize_block(pprbuf, &buf, serflag); + } + break; + default: + ASSERT(0); + } + return ret; +} + + +/* Copy serialized ppr data of a bandwidth */ +static void ppr_copy_serdata(uint8* pobuf, const uint8** inbuf, uint32 flag, uint16 per_band_size) +{ + uint chain = flag & PPR_MAX_TX_CHAIN_MASK; + bool bf = (flag & PPR_BEAMFORMING) != 0; + uint16 len = PPR_CHAIN1_SIZE; + BCM_REFERENCE(chain); + BCM_REFERENCE(bf); + bcopy(*inbuf, pobuf, PPR_CHAIN1_SIZE); + *inbuf += PPR_CHAIN1_SIZE; +#if (PPR_MAX_TX_CHAINS > 1) + if (chain > 1) { + bcopy(*inbuf, &pobuf[PPR_CHAIN2_FIRST], PPR_CHAIN2_SIZE); + *inbuf += PPR_CHAIN2_SIZE; + len += PPR_CHAIN2_SIZE; + } +#if (PPR_MAX_TX_CHAINS > 2) + if (chain > 2) { + bcopy(*inbuf, &pobuf[PPR_CHAIN3_FIRST], PPR_CHAIN3_SIZE); + *inbuf += PPR_CHAIN3_SIZE; + len += PPR_CHAIN3_SIZE; + } +#endif + +#ifdef WL_BEAMFORMING + if (PPR_TXBF_ENAB() && bf) { + bcopy(*inbuf, &pobuf[PPR_BF_CHAIN2_FIRST], PPR_BF_CHAIN2_SIZE); + *inbuf += PPR_BF_CHAIN2_SIZE; + len += PPR_BF_CHAIN2_SIZE; + } +#if (PPR_MAX_TX_CHAINS > 2) + if (PPR_TXBF_ENAB() && bf && chain > 2) { + bcopy(*inbuf, &pobuf[PPR_BF_CHAIN3_FIRST], PPR_BF_CHAIN3_SIZE); + *inbuf += PPR_BF_CHAIN3_SIZE; + len += PPR_BF_CHAIN3_SIZE; + } +#endif +#endif /* WL_BEAMFORMING */ +#endif /* (PPR_MAX_TX_CHAINS > 1) */ + if (len < per_band_size) { + *inbuf += (per_band_size - len); + } +} + + +/* Deserialize data into a ppr_t structure */ +static void +ppr_deser_cpy(ppr_t* pptr, const uint8* inbuf, uint32 flag, wl_tx_bw_t bw, uint16 per_band_size) +{ + pptr->ch_bw = bw; + switch (bw) { + case WL_TX_BW_20: + { + uint8* pobuf = (uint8*)&pptr->ppr_bw.ch20; + ppr_copy_serdata(pobuf, &inbuf, flag, per_band_size); + } + break; + case WL_TX_BW_40: + { + uint8* pobuf = (uint8*)&pptr->ppr_bw.ch40.b40; + ppr_copy_serdata(pobuf, &inbuf, flag, per_band_size); + pobuf = (uint8*)&pptr->ppr_bw.ch40.b20in40; + ppr_copy_serdata(pobuf, &inbuf, flag, per_band_size); + } + break; + case WL_TX_BW_80: + { + uint8* pobuf = (uint8*)&pptr->ppr_bw.ch80.b80; + ppr_copy_serdata(pobuf, &inbuf, flag, per_band_size); + pobuf = (uint8*)&pptr->ppr_bw.ch80.b20in80; + ppr_copy_serdata(pobuf, &inbuf, flag, per_band_size); + pobuf = (uint8*)&pptr->ppr_bw.ch80.b40in80; + ppr_copy_serdata(pobuf, &inbuf, flag, per_band_size); + } + break; + default: + ASSERT(0); + } +} + + +/* Get a pointer to the power values for a given channel bandwidth */ +static pprpbw_t* ppr_get_bw_powers_20(ppr_t* p, wl_tx_bw_t bw) +{ + pprpbw_t* pwrs = NULL; + + if (bw == WL_TX_BW_20) + pwrs = &p->ppr_bw.ch20.b20; + /* else */ + /* ASSERT(0); */ + return pwrs; +} + + +/* Get a pointer to the power values for a given channel bandwidth */ +static pprpbw_t* ppr_get_bw_powers_40(ppr_t* p, wl_tx_bw_t bw) +{ + pprpbw_t* pwrs = NULL; + + switch (bw) { + case WL_TX_BW_40: + pwrs = &p->ppr_bw.ch40.b40; + break; + case WL_TX_BW_20: + + case WL_TX_BW_20IN40: + pwrs = &p->ppr_bw.ch40.b20in40; + break; + default: + /* ASSERT(0); */ + break; + } + return pwrs; +} + + +/* Get a pointer to the power values for a given channel bandwidth */ +static pprpbw_t* ppr_get_bw_powers_80(ppr_t* p, wl_tx_bw_t bw) +{ + pprpbw_t* pwrs = NULL; + + switch (bw) { + case WL_TX_BW_80: + pwrs = &p->ppr_bw.ch80.b80; + break; + case WL_TX_BW_20: + case WL_TX_BW_20IN40: + case WL_TX_BW_20IN80: + pwrs = &p->ppr_bw.ch80.b20in80; + break; + case WL_TX_BW_40: + case WL_TX_BW_40IN80: + pwrs = &p->ppr_bw.ch80.b40in80; + break; + default: + /* ASSERT(0); */ + break; + } + return pwrs; +} + + +typedef pprpbw_t* (*wlc_ppr_get_bw_pwrs_fn_t)(ppr_t* p, wl_tx_bw_t bw); + +typedef struct { + wl_tx_bw_t ch_bw; /* Bandwidth of the channel for which powers are stored */ + /* Function to retrieve the powers for the requested bandwidth */ + wlc_ppr_get_bw_pwrs_fn_t fn; +} wlc_ppr_get_bw_pwrs_pair_t; + + +static const wlc_ppr_get_bw_pwrs_pair_t ppr_get_bw_pwrs_fn[] = { + {WL_TX_BW_20, ppr_get_bw_powers_20}, + {WL_TX_BW_40, ppr_get_bw_powers_40}, + {WL_TX_BW_80, ppr_get_bw_powers_80} +}; + + +/* Get a pointer to the power values for a given channel bandwidth */ +static pprpbw_t* ppr_get_bw_powers(ppr_t* p, wl_tx_bw_t bw) +{ + uint32 i; + + if (p == NULL) { + return NULL; + } + + for (i = 0; i < (int)ARRAYSIZE(ppr_get_bw_pwrs_fn); i++) { + if (ppr_get_bw_pwrs_fn[i].ch_bw == p->ch_bw) + return ppr_get_bw_pwrs_fn[i].fn(p, bw); + } + + ASSERT(0); + return NULL; +} + + +/* + * Rate group power finder functions: ppr_get_xxx_group() + * To preserve the opacity of the PPR struct, even inside the API we try to limit knowledge of + * its details. Almost all API functions work on the powers for individual rate groups, rather than + * directly accessing the struct. Once the section of the structure corresponding to the bandwidth + * has been identified using ppr_get_bw_powers(), the ppr_get_xxx_group() functions use knowledge + * of the number of spatial streams, the number of tx chains, and the expansion mode to return a + * pointer to the required group of power values. + */ + +/* Get a pointer to the power values for the given dsss rate group for a given channel bandwidth */ +static int8* ppr_get_dsss_group(pprpbw_t* bw_pwrs, wl_tx_chains_t tx_chains) +{ + int8* group_pwrs = NULL; + + switch (tx_chains) { +#if (PPR_MAX_TX_CHAINS > 1) +#if (PPR_MAX_TX_CHAINS > 2) + case WL_TX_CHAINS_3: + group_pwrs = bw_pwrs->p_1x3dsss; + break; +#endif + case WL_TX_CHAINS_2: + group_pwrs = bw_pwrs->p_1x2dsss; + break; +#endif /* PPR_MAX_TX_CHAINS > 1 */ + case WL_TX_CHAINS_1: + group_pwrs = bw_pwrs->p_1x1dsss; + break; + default: + ASSERT(0); + break; + } + return group_pwrs; +} + + +/* Get a pointer to the power values for the given ofdm rate group for a given channel bandwidth */ +static int8* ppr_get_ofdm_group(pprpbw_t* bw_pwrs, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains) +{ + int8* group_pwrs = NULL; + BCM_REFERENCE(mode); + switch (tx_chains) { +#if (PPR_MAX_TX_CHAINS > 1) +#if (PPR_MAX_TX_CHAINS > 2) + case WL_TX_CHAINS_3: +#ifdef WL_BEAMFORMING + if (mode == WL_TX_MODE_TXBF) + group_pwrs = bw_pwrs->p_1x3txbf_ofdm; + else +#endif + group_pwrs = bw_pwrs->p_1x3cdd_ofdm; + break; +#endif /* PPR_MAX_TX_CHAINS > 2 */ + case WL_TX_CHAINS_2: +#ifdef WL_BEAMFORMING + if (mode == WL_TX_MODE_TXBF) + group_pwrs = bw_pwrs->p_1x2txbf_ofdm; + else +#endif + group_pwrs = bw_pwrs->p_1x2cdd_ofdm; + break; +#endif /* PPR_MAX_TX_CHAINS > 1 */ + case WL_TX_CHAINS_1: + group_pwrs = bw_pwrs->p_1x1ofdm; + break; + default: + ASSERT(0); + break; + } + return group_pwrs; +} + + +/* + * Tables to provide access to HT/VHT rate group powers. This avoids an ugly nested switch with + * messy conditional compilation. + * + * Access to a given table entry is via table[chains - Nss][mode], except for the Nss3 table, which + * only has one row, so it can be indexed directly by table[mode]. + * + * Separate tables are provided for each of Nss1, Nss2 and Nss3 because they are all different + * sizes. A combined table would be very sparse, and this arrangement also simplifies the + * conditional compilation. + * + * Each row represents a given number of chains, so there's no need for a zero row. Because + * chains >= Nss is always true, there is no one-chain row for Nss2 and there are no one- or + * two-chain rows for Nss3. With the tables correctly sized, we can index the rows + * using [chains - Nss]. + * + * Then, inside each row, we index by mode: + * WL_TX_MODE_NONE, WL_TX_MODE_STBC, WL_TX_MODE_CDD, WL_TX_MODE_TXBF. + */ + +#define OFFSNONE (-1) + +static const int mcs_groups_nss1[PPR_MAX_TX_CHAINS][WL_NUM_TX_MODES] = { + /* WL_TX_MODE_NONE + WL_TX_MODE_STBC + WL_TX_MODE_CDD + WL_TX_MODE_TXBF + */ + /* 1 chain */ + {OFFSETOF(pprpbw_t, p_1x1vhtss1), + OFFSNONE, + OFFSNONE, + OFFSNONE}, +#if (PPR_MAX_TX_CHAINS > 1) + /* 2 chain */ + {OFFSNONE, + OFFSNONE, + OFFSETOF(pprpbw_t, p_1x2cdd_vhtss1), + OFFSNONE}, +#if (PPR_MAX_TX_CHAINS > 2) + /* 3 chain */ + {OFFSNONE, + OFFSNONE, + OFFSETOF(pprpbw_t, p_1x3cdd_vhtss1), + OFFSNONE} +#endif +#endif /* PPR_MAX_TX_CHAINS > 1 */ +}; + +#ifdef WL_BEAMFORMING +/* mcs group with TXBF data */ +static const int mcs_groups_nss1_txbf[PPR_MAX_TX_CHAINS][WL_NUM_TX_MODES] = { + /* WL_TX_MODE_NONE + WL_TX_MODE_STBC + WL_TX_MODE_CDD + WL_TX_MODE_TXBF + */ + /* 1 chain */ + {OFFSETOF(pprpbw_t, p_1x1vhtss1), + OFFSNONE, + OFFSNONE, + OFFSNONE}, +#if (PPR_MAX_TX_CHAINS > 1) + /* 2 chain */ + {OFFSNONE, + OFFSNONE, + OFFSETOF(pprpbw_t, p_1x2cdd_vhtss1), + OFFSETOF(pprpbw_t, p_1x2txbf_vhtss1)}, +#if (PPR_MAX_TX_CHAINS > 2) + /* 3 chain */ + {OFFSNONE, + OFFSNONE, + OFFSETOF(pprpbw_t, p_1x3cdd_vhtss1), + OFFSETOF(pprpbw_t, p_1x3txbf_vhtss1)} +#endif +#endif /* PPR_MAX_TX_CHAINS > 1 */ +}; +#endif /* WL_BEAMFORMING */ + +#if (PPR_MAX_TX_CHAINS > 1) +static const int mcs_groups_nss2[PPR_MAX_TX_CHAINS - 1][WL_NUM_TX_MODES] = { + /* 2 chain */ + {OFFSETOF(pprpbw_t, p_2x2vhtss2), + OFFSETOF(pprpbw_t, p_2x2stbc_vhtss1), + OFFSNONE, + OFFSNONE}, +#if (PPR_MAX_TX_CHAINS > 2) + /* 3 chain */ + {OFFSETOF(pprpbw_t, p_2x3vhtss2), + OFFSETOF(pprpbw_t, p_2x3stbc_vhtss1), + OFFSNONE, + OFFSNONE} +#endif +}; + +#ifdef WL_BEAMFORMING +/* mcs group with TXBF data */ +static const int mcs_groups_nss2_txbf[PPR_MAX_TX_CHAINS - 1][WL_NUM_TX_MODES] = { + /* 2 chain */ + {OFFSETOF(pprpbw_t, p_2x2vhtss2), + OFFSETOF(pprpbw_t, p_2x2stbc_vhtss1), + OFFSNONE, + OFFSETOF(pprpbw_t, p_2x2txbf_vhtss2)}, +#if (PPR_MAX_TX_CHAINS > 2) + /* 3 chain */ + {OFFSETOF(pprpbw_t, p_2x3vhtss2), + OFFSETOF(pprpbw_t, p_2x3stbc_vhtss1), + OFFSNONE, + OFFSETOF(pprpbw_t, p_2x3txbf_vhtss2)} +#endif +}; +#endif /* WL_BEAMFORMING */ + +#if (PPR_MAX_TX_CHAINS > 2) +static const int mcs_groups_nss3[WL_NUM_TX_MODES] = { +/* 3 chains only */ + OFFSETOF(pprpbw_t, p_3x3vhtss3), + OFFSNONE, + OFFSNONE, + OFFSNONE, +}; + +#ifdef WL_BEAMFORMING +/* mcs group with TXBF data */ +static const int mcs_groups_nss3_txbf[WL_NUM_TX_MODES] = { +/* 3 chains only */ + OFFSETOF(pprpbw_t, p_3x3vhtss3), + OFFSNONE, + OFFSNONE, + OFFSETOF(pprpbw_t, p_3x3txbf_vhtss3) +}; +#endif /* WL_BEAMFORMING */ +#endif /* PPR_MAX_TX_CHAINS > 2 */ +#endif /* PPR_MAX_TX_CHAINS > 1 */ + +/* Get a pointer to the power values for the given rate group for a given channel bandwidth */ +static int8* ppr_get_mcs_group(pprpbw_t* bw_pwrs, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains) +{ + int8* group_pwrs = NULL; + int offset; + + switch (Nss) { +#if (PPR_MAX_TX_CHAINS > 1) +#if (PPR_MAX_TX_CHAINS > 2) + case WL_TX_NSS_3: + if (tx_chains == WL_TX_CHAINS_3) { +#ifdef WL_BEAMFORMING + if (PPR_TXBF_ENAB()) { + offset = mcs_groups_nss3_txbf[mode]; + } else +#endif /* WL_BEAMFORMING */ + { + offset = mcs_groups_nss3[mode]; + } + if (offset != OFFSNONE) { + group_pwrs = (int8*)bw_pwrs + offset; + } + } + else + ASSERT(0); + break; +#endif /* PPR_MAX_TX_CHAINS > 2 */ + case WL_TX_NSS_2: + if ((tx_chains >= WL_TX_CHAINS_2) && (tx_chains <= PPR_MAX_TX_CHAINS)) { +#ifdef WL_BEAMFORMING + if (PPR_TXBF_ENAB()) { + offset = mcs_groups_nss2_txbf[tx_chains - Nss][mode]; + } else +#endif /* WL_BEAMFORMING */ + { + offset = mcs_groups_nss2[tx_chains - Nss][mode]; + } + if (offset != OFFSNONE) { + group_pwrs = (int8*)bw_pwrs + offset; + } + } + else + ASSERT(0); + break; +#endif /* PPR_MAX_TX_CHAINS > 1 */ + case WL_TX_NSS_1: + if (tx_chains <= PPR_MAX_TX_CHAINS) { +#ifdef WL_BEAMFORMING + if (PPR_TXBF_ENAB()) { + offset = mcs_groups_nss1_txbf[tx_chains - Nss][mode]; + } else +#endif /* WL_BEAMFORMING */ + { + offset = mcs_groups_nss1[tx_chains - Nss][mode]; + } + if (offset != OFFSNONE) { + group_pwrs = (int8*)bw_pwrs + offset; + } + } + else + ASSERT(0); + break; + default: + ASSERT(0); + break; + } + return group_pwrs; +} + +/* Size routine for user alloc/dealloc */ +static uint32 ppr_pwrs_size(wl_tx_bw_t bw) +{ + uint32 size; + + switch (bw) { + case WL_TX_BW_20: + size = sizeof(ppr_bw_20_t); + break; + case WL_TX_BW_40: + size = sizeof(ppr_bw_40_t); + break; + case WL_TX_BW_80: + size = sizeof(ppr_bw_80_t); + break; + default: + ASSERT(0); + size = 0; + break; + } + return size; +} + + +/* Initialization routine */ +void ppr_init(ppr_t* pprptr, wl_tx_bw_t bw) +{ + memset(pprptr, (int8)WL_RATE_DISABLED, ppr_size(bw)); + pprptr->ch_bw = bw; +} + + +/* Reinitialization routine for opaque PPR struct */ +void ppr_clear(ppr_t* pprptr) +{ + memset((uchar*)&pprptr->ppr_bw, (int8)WL_RATE_DISABLED, ppr_pwrs_size(pprptr->ch_bw)); +} + + +/* Size routine for user alloc/dealloc */ +uint32 ppr_size(wl_tx_bw_t bw) +{ + return ppr_pwrs_size(bw) + sizeof(wl_tx_bw_t); +} + + +/* Size routine for user serialization alloc */ +uint32 ppr_ser_size(const ppr_t* pprptr) +{ + return ppr_pwrs_size(pprptr->ch_bw) + SER_HDR_LEN; /* struct size plus headers */ +} + + +/* Size routine for user serialization alloc */ +uint32 ppr_ser_size_by_bw(wl_tx_bw_t bw) +{ + return ppr_pwrs_size(bw) + SER_HDR_LEN; /* struct size plus headers */ +} + + +/* Constructor routine for opaque PPR struct */ +ppr_t* ppr_create(osl_t *osh, wl_tx_bw_t bw) +{ + ppr_t* pprptr; + + ASSERT((bw == WL_TX_BW_20) || (bw == WL_TX_BW_40) || (bw == WL_TX_BW_80)); +#ifndef BCMDRIVER + BCM_REFERENCE(osh); + if ((pprptr = (ppr_t*)malloc((uint)ppr_size(bw))) != NULL) { +#else + if ((pprptr = (ppr_t*)MALLOC(osh, (uint)ppr_size(bw))) != NULL) { +#endif + ppr_init(pprptr, bw); + } + return pprptr; +} + + +/* Init flags in the memory block for serialization, the serializer will check + * the flag to decide which ppr to be copied + */ +int ppr_init_ser_mem_by_bw(uint8* pbuf, wl_tx_bw_t bw, uint32 len) +{ + ppr_ser_mem_flag_t *pmflag; + + if (pbuf == NULL || ppr_ser_size_by_bw(bw) > len) + return BCME_BADARG; + + pmflag = (ppr_ser_mem_flag_t *)pbuf; + pmflag->magic_word = HTON32(PPR_SER_MEM_WORD); + pmflag->flag = HTON32(ppr_get_flag()); + + /* init the memory */ + memset(pbuf + sizeof(*pmflag), (uint8)WL_RATE_DISABLED, len-sizeof(*pmflag)); + return BCME_OK; +} + + +int ppr_init_ser_mem(uint8* pbuf, ppr_t * ppr, uint32 len) +{ + return ppr_init_ser_mem_by_bw(pbuf, ppr->ch_bw, len); +} + + +/* Destructor routine for opaque PPR struct */ +void ppr_delete(osl_t *osh, ppr_t* pprptr) +{ + ASSERT((pprptr->ch_bw == WL_TX_BW_20) || (pprptr->ch_bw == WL_TX_BW_40) || + (pprptr->ch_bw == WL_TX_BW_80)); +#ifndef BCMDRIVER + BCM_REFERENCE(osh); + free(pprptr); +#else + MFREE(osh, pprptr, (uint)ppr_size(pprptr->ch_bw)); +#endif +} + + +/* Type routine for inferring opaque structure size */ +wl_tx_bw_t ppr_get_ch_bw(const ppr_t* pprptr) +{ + return pprptr->ch_bw; +} + + +/* Type routine to get ppr supported maximum bw */ +wl_tx_bw_t ppr_get_max_bw(void) +{ + return PPR_BW_MAX; +} + + +/* Get the dsss values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_get_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains, + ppr_dsss_rateset_t* dsss) +{ + pprpbw_t* bw_pwrs; + const int8* powers; + int cnt = 0; + + ASSERT(pprptr); + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = ppr_get_dsss_group(bw_pwrs, tx_chains); + if (powers != NULL) { + bcopy(powers, dsss->pwr, sizeof(*dsss)); + cnt = sizeof(*dsss); + } + } + if (cnt == 0) { + memset(dsss->pwr, (int8)WL_RATE_DISABLED, sizeof(*dsss)); + } + return cnt; +} + + +/* Get the ofdm values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_get_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains, + ppr_ofdm_rateset_t* ofdm) +{ + pprpbw_t* bw_pwrs; + const int8* powers; + int cnt = 0; + + ASSERT(pprptr); + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = ppr_get_ofdm_group(bw_pwrs, mode, tx_chains); + if (powers != NULL) { + bcopy(powers, ofdm->pwr, sizeof(*ofdm)); + cnt = sizeof(*ofdm); + } + } + if (cnt == 0) { + memset(ofdm->pwr, (int8)WL_RATE_DISABLED, sizeof(*ofdm)); + } + return cnt; +} + + +/* Get the HT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_get_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, ppr_ht_mcs_rateset_t* mcs) +{ + pprpbw_t* bw_pwrs; + const int8* powers; + int cnt = 0; + + ASSERT(pprptr); + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains); + if (powers != NULL) { + bcopy(powers, mcs->pwr, sizeof(*mcs)); + cnt = sizeof(*mcs); + } + } + if (cnt == 0) { + memset(mcs->pwr, (int8)WL_RATE_DISABLED, sizeof(*mcs)); + } + + return cnt; +} + + +/* Get the VHT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_get_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, ppr_vht_mcs_rateset_t* mcs) +{ + pprpbw_t* bw_pwrs; + const int8* powers; + int cnt = 0; + + ASSERT(pprptr); + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains); + if (powers != NULL) { + bcopy(powers, mcs->pwr, sizeof(*mcs)); + cnt = sizeof(*mcs); + } + } + if (cnt == 0) { + memset(mcs->pwr, (int8)WL_RATE_DISABLED, sizeof(*mcs)); + } + return cnt; +} + + +#define TXPPR_TXPWR_MAX 0x7f /* WLC_TXPWR_MAX */ + +/* Get the minimum power for a VHT MCS rate specified by Nss, with the given bw and tx chains. + * Disabled rates are ignored + */ +int ppr_get_vht_mcs_min(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, int8* mcs_min) +{ + pprpbw_t* bw_pwrs; + const int8* powers; + int result = BCME_ERROR; + uint i = 0; + + *mcs_min = TXPPR_TXPWR_MAX; + + ASSERT(pprptr); + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains); + if (powers != NULL) { + for (i = 0; i < sizeof(ppr_vht_mcs_rateset_t); i++) { + /* ignore disabled rates! */ + if (powers[i] != WL_RATE_DISABLED) + *mcs_min = MIN(*mcs_min, powers[i]); + } + result = BCME_OK; + } + } + return result; +} + + +/* Routines to set target powers per rate in a group */ + +/* Set the dsss values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_set_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains, + const ppr_dsss_rateset_t* dsss) +{ + pprpbw_t* bw_pwrs; + int8* powers; + int cnt = 0; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = (int8*)ppr_get_dsss_group(bw_pwrs, tx_chains); + if (powers != NULL) { + bcopy(dsss->pwr, powers, sizeof(*dsss)); + cnt = sizeof(*dsss); + } + } + return cnt; +} + + +/* Set the ofdm values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_set_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains, + const ppr_ofdm_rateset_t* ofdm) +{ + pprpbw_t* bw_pwrs; + int8* powers; + int cnt = 0; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = (int8*)ppr_get_ofdm_group(bw_pwrs, mode, tx_chains); + if (powers != NULL) { + bcopy(ofdm->pwr, powers, sizeof(*ofdm)); + cnt = sizeof(*ofdm); + } + } + return cnt; +} + + +/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_set_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, const ppr_ht_mcs_rateset_t* mcs) +{ + pprpbw_t* bw_pwrs; + int8* powers; + int cnt = 0; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = (int8*)ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains); + if (powers != NULL) { + bcopy(mcs->pwr, powers, sizeof(*mcs)); + cnt = sizeof(*mcs); + } + } + return cnt; +} + + +/* Set the VHT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_set_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, const ppr_vht_mcs_rateset_t* mcs) +{ + pprpbw_t* bw_pwrs; + int8* powers; + int cnt = 0; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + powers = (int8*)ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains); + if (powers != NULL) { + bcopy(mcs->pwr, powers, sizeof(*mcs)); + cnt = sizeof(*mcs); + } + } + return cnt; +} + + +/* Routines to set rate groups to a single target value */ + +/* Set the dsss values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_set_same_dsss(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_chains_t tx_chains, const int8 power) +{ + pprpbw_t* bw_pwrs; + int8* dest_group; + int cnt = 0; + int i; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + dest_group = (int8*)ppr_get_dsss_group(bw_pwrs, tx_chains); + if (dest_group != NULL) { + cnt = sizeof(ppr_dsss_rateset_t); + for (i = 0; i < cnt; i++) + *dest_group++ = power; + } + } + return cnt; +} + + +/* Set the ofdm values for the given number of tx_chains and 20, 20in40, etc. */ +int ppr_set_same_ofdm(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains, + const int8 power) +{ + pprpbw_t* bw_pwrs; + int8* dest_group; + int cnt = 0; + int i; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + dest_group = (int8*)ppr_get_ofdm_group(bw_pwrs, mode, tx_chains); + if (dest_group != NULL) { + cnt = sizeof(ppr_ofdm_rateset_t); + for (i = 0; i < cnt; i++) + *dest_group++ = power; + } + } + return cnt; +} + + +/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_set_same_ht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, const int8 power) +{ + pprpbw_t* bw_pwrs; + int8* dest_group; + int cnt = 0; + int i; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + dest_group = (int8*)ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains); + if (dest_group != NULL) { + cnt = sizeof(ppr_ht_mcs_rateset_t); + for (i = 0; i < cnt; i++) + *dest_group++ = power; + } + } + return cnt; +} + + +/* Set the HT MCS values for the group specified by Nss, with the given bw and tx chains */ +int ppr_set_same_vht_mcs(ppr_t* pprptr, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains, const int8 power) +{ + pprpbw_t* bw_pwrs; + int8* dest_group; + int cnt = 0; + int i; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + dest_group = (int8*)ppr_get_mcs_group(bw_pwrs, Nss, mode, tx_chains); + if (dest_group != NULL) { + cnt = sizeof(ppr_vht_mcs_rateset_t); + for (i = 0; i < cnt; i++) + *dest_group++ = power; + } + } + return cnt; +} + + +/* Helper routines to operate on the entire ppr set */ + +/* Ensure no rate limit is greater than the cap */ +uint ppr_apply_max(ppr_t* pprptr, int8 maxval) +{ + uint i; + int8* rptr = (int8*)&pprptr->ppr_bw; + + for (i = 0; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++) { + *rptr = MIN(*rptr, maxval); + } + return i; +} + + +/* + * Check for any power in the rate group at or below the threshold. If any is + * found, set the entire group to WL_RATE_DISABLED. An exception is made for + * VHT 8 and 9 which will not cause the entire group to be disabled if they + * are disabled or below the threshold. + */ +static void ppr_force_disabled_group(int8* powers, int8 threshold, uint len) +{ + uint i; + + for (i = 0; (i < len) && (i < WL_RATESET_SZ_HT_MCS); i++) { + /* if we find a below-threshold rate in the set... */ + if (powers[i] <= threshold) { + /* disable the entire rate set and return */ + for (i = 0; i < len; i++) { + powers[i] = WL_RATE_DISABLED; + } + return; + } + } + /* VHT 8 and 9 can be disabled separately */ + for (; i < len; i++) { + if (powers[i] <= threshold) { + powers[i] = WL_RATE_DISABLED; + } + } +} + + +/* + * Make low power rates (below the threshold) explicitly disabled. + * If one rate in a group is disabled, disable the whole group. + */ +int ppr_force_disabled(ppr_t* pprptr, int8 threshold) +{ + wl_tx_bw_t bw; + + for (bw = WL_TX_BW_20; bw <= WL_TX_BW_80; bw++) { + pprpbw_t* bw_pwrs = ppr_get_bw_powers(pprptr, bw); + + if (bw_pwrs != NULL) { + int8* powers; +#if (PPR_MAX_TX_CHAINS > 1) + int8* mcs_powers; +#endif + powers = (int8*)ppr_get_dsss_group(bw_pwrs, WL_TX_CHAINS_1); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_DSSS); + + powers = (int8*)ppr_get_ofdm_group(bw_pwrs, + WL_TX_MODE_NONE, WL_TX_CHAINS_1); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM); + + powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_NONE, + WL_TX_CHAINS_1); + ASSERT(powers); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_VHT_MCS); + +#if (PPR_MAX_TX_CHAINS > 1) + powers = (int8*)ppr_get_dsss_group(bw_pwrs, WL_TX_CHAINS_2); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_DSSS); + + powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_CDD, WL_TX_CHAINS_2); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM); + + mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_CDD, + WL_TX_CHAINS_2); + ASSERT(mcs_powers); + for (powers = mcs_powers; powers < &mcs_powers[PPR_CHAIN2_MCS_SIZE]; + powers += WL_RATESET_SZ_VHT_MCS) { + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_VHT_MCS); + } + +#ifdef WL_BEAMFORMING + if (PPR_TXBF_ENAB()) { + powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_TXBF, + WL_TX_CHAINS_2); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM); + + mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, + WL_TX_MODE_TXBF, WL_TX_CHAINS_2); + ASSERT(mcs_powers); + for (powers = mcs_powers; + powers < &mcs_powers[PPR_BF_CHAIN2_MCS_SIZE]; + powers += WL_RATESET_SZ_VHT_MCS) { + ppr_force_disabled_group(powers, threshold, + WL_RATESET_SZ_VHT_MCS); + } + } +#endif /* WL_BEAMFORMING */ + +#if (PPR_MAX_TX_CHAINS > 2) + powers = (int8*)ppr_get_dsss_group(bw_pwrs, WL_TX_CHAINS_3); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_DSSS); + + powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_CDD, WL_TX_CHAINS_3); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM); + + mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, WL_TX_MODE_CDD, + WL_TX_CHAINS_3); + ASSERT(mcs_powers); + for (powers = mcs_powers; powers < &mcs_powers[PPR_CHAIN3_MCS_SIZE]; + powers += WL_RATESET_SZ_VHT_MCS) { + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_VHT_MCS); + } + +#ifdef WL_BEAMFORMING + if (PPR_TXBF_ENAB()) { + powers = (int8*)ppr_get_ofdm_group(bw_pwrs, WL_TX_MODE_TXBF, + WL_TX_CHAINS_3); + ppr_force_disabled_group(powers, threshold, WL_RATESET_SZ_OFDM); + + mcs_powers = (int8*)ppr_get_mcs_group(bw_pwrs, WL_TX_NSS_1, + WL_TX_MODE_TXBF, WL_TX_CHAINS_3); + ASSERT(mcs_powers); + for (powers = mcs_powers; + powers < &mcs_powers[PPR_BF_CHAIN3_MCS_SIZE]; + powers += WL_RATESET_SZ_VHT_MCS) { + ppr_force_disabled_group(powers, threshold, + WL_RATESET_SZ_VHT_MCS); + } + } +#endif /* WL_BEAMFORMING */ +#endif /* (PPR_MAX_TX_CHAINS > 2) */ +#endif /* (PPR_MAX_TX_CHAINS > 1) */ + } + } + return BCME_OK; +} + + +#if (PPR_MAX_TX_CHAINS > 1) +#define APPLY_CONSTRAINT(x, y, max) do { \ + ret += (y - x); \ + for (i = x; i < y; i++) \ + pprbuf[i] = MIN(pprbuf[i], max); \ + } while (0); + + +/* Apply appropriate single-, two- and three-chain constraints across the appropriate ppr block */ +static uint ppr_apply_constraint_to_block(int8* pprbuf, int8 constraint) +{ + uint ret = 0; + uint i = 0; + int8 constraint_2chain = constraint - QDB(3); +#if (PPR_MAX_TX_CHAINS > 2) + int8 constraint_3chain = constraint - (QDB(4) + 3); /* - 4.75dBm */ +#endif + + APPLY_CONSTRAINT(PPR_CHAIN1_FIRST, PPR_CHAIN1_END, constraint); + APPLY_CONSTRAINT(PPR_CHAIN2_FIRST, PPR_CHAIN2_END, constraint_2chain); +#if (PPR_MAX_TX_CHAINS > 2) + APPLY_CONSTRAINT(PPR_CHAIN3_FIRST, PPR_CHAIN3_END, constraint_3chain); +#endif +#ifdef WL_BEAMFORMING + APPLY_CONSTRAINT(PPR_BF_CHAIN2_FIRST, PPR_BF_CHAIN2_END, constraint_2chain); +#if (PPR_MAX_TX_CHAINS > 2) + APPLY_CONSTRAINT(PPR_BF_CHAIN3_FIRST, PPR_BF_CHAIN3_END, constraint_3chain); +#endif +#endif /* WL_BEAMFORMING */ + return ret; +} +#endif /* (PPR_MAX_TX_CHAINS > 1) */ + + +/* + * Reduce total transmitted power to level of constraint. + * For two chain rates, the per-antenna power must be halved. + * For three chain rates, it must be a third of the constraint. + */ +uint ppr_apply_constraint_total_tx(ppr_t* pprptr, int8 constraint) +{ + uint ret = 0; + +#if (PPR_MAX_TX_CHAINS > 1) + int8* pprbuf; + ASSERT(pprptr); + + switch (pprptr->ch_bw) { + case WL_TX_BW_20: + { + pprbuf = (int8*)&pprptr->ppr_bw.ch20.b20; + ret += ppr_apply_constraint_to_block(pprbuf, constraint); + } + break; + case WL_TX_BW_40: + { + pprbuf = (int8*)&pprptr->ppr_bw.ch40.b40; + ret += ppr_apply_constraint_to_block(pprbuf, constraint); + pprbuf = (int8*)&pprptr->ppr_bw.ch40.b20in40; + ret += ppr_apply_constraint_to_block(pprbuf, constraint); + } + break; + case WL_TX_BW_80: + { + pprbuf = (int8*)&pprptr->ppr_bw.ch80.b80; + ret += ppr_apply_constraint_to_block(pprbuf, constraint); + pprbuf = (int8*)&pprptr->ppr_bw.ch80.b20in80; + ret += ppr_apply_constraint_to_block(pprbuf, constraint); + pprbuf = (int8*)&pprptr->ppr_bw.ch80.b40in80; + ret += ppr_apply_constraint_to_block(pprbuf, constraint); + } + break; + default: + ASSERT(0); + } + +#else + ASSERT(pprptr); + ret = ppr_apply_max(pprptr, constraint); +#endif /* PPR_MAX_TX_CHAINS > 1 */ + return ret; +} + + +/* Ensure no rate limit is lower than the specified minimum */ +uint ppr_apply_min(ppr_t* pprptr, int8 minval) +{ + uint i; + int8* rptr = (int8*)&pprptr->ppr_bw; + + for (i = 0; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++) { + *rptr = MAX(*rptr, minval); + } + return i; +} + + +/* Ensure no rate limit in this ppr set is greater than the corresponding limit in ppr_cap */ +uint ppr_apply_vector_ceiling(ppr_t* pprptr, const ppr_t* ppr_cap) +{ + uint i = 0; + int8* rptr = (int8*)&pprptr->ppr_bw; + const int8* capptr = (const int8*)&ppr_cap->ppr_bw; + + if (pprptr->ch_bw == ppr_cap->ch_bw) { + for (i = 0; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++, capptr++) { + *rptr = MIN(*rptr, *capptr); + } + } + return i; +} + + +/* Ensure no rate limit in this ppr set is lower than the corresponding limit in ppr_min */ +uint ppr_apply_vector_floor(ppr_t* pprptr, const ppr_t* ppr_min) +{ + uint i = 0; + int8* rptr = (int8*)&pprptr->ppr_bw; + const int8* minptr = (const int8*)&ppr_min->ppr_bw; + + if (pprptr->ch_bw == ppr_min->ch_bw) { + for (i = 0; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++, minptr++) { + *rptr = MAX((uint8)*rptr, (uint8)*minptr); + } + } + return i; +} + + +/* Get the maximum power in the ppr set */ +int8 ppr_get_max(ppr_t* pprptr) +{ + uint i; + int8* rptr = (int8*)&pprptr->ppr_bw; + int8 maxval = *rptr++; + + for (i = 1; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++) { + maxval = MAX(maxval, *rptr); + } + return maxval; +} + + +/* + * Get the minimum power in the ppr set, excluding disallowed + * rates and (possibly) powers set to the minimum for the phy + */ +int8 ppr_get_min(ppr_t* pprptr, int8 floor) +{ + uint i; + int8* rptr = (int8*)&pprptr->ppr_bw; + int8 minval = WL_RATE_DISABLED; + + for (i = 0; (i < ppr_pwrs_size(pprptr->ch_bw)) && ((minval == WL_RATE_DISABLED) || + (minval == floor)); i++, rptr++) { + minval = *rptr; + } + for (; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++) { + if ((*rptr != WL_RATE_DISABLED) && (*rptr != floor)) + minval = MIN(minval, *rptr); + } + return minval; +} + + +/* Get the maximum power for a given bandwidth in the ppr set */ +int8 ppr_get_max_for_bw(ppr_t* pprptr, wl_tx_bw_t bw) +{ + uint i; + const pprpbw_t* bw_pwrs; + const int8* rptr; + int8 maxval; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + rptr = (const int8*)bw_pwrs; + maxval = *rptr++; + + for (i = 1; i < sizeof(*bw_pwrs); i++, rptr++) { + maxval = MAX(maxval, *rptr); + } + } else { + maxval = WL_RATE_DISABLED; + } + return maxval; +} + + +/* Get the minimum power for a given bandwidth in the ppr set */ +int8 ppr_get_min_for_bw(ppr_t* pprptr, wl_tx_bw_t bw) +{ + uint i; + const pprpbw_t* bw_pwrs; + const int8* rptr; + int8 minval; + + bw_pwrs = ppr_get_bw_powers(pprptr, bw); + if (bw_pwrs != NULL) { + rptr = (const int8*)bw_pwrs; + minval = *rptr++; + + for (i = 1; i < sizeof(*bw_pwrs); i++, rptr++) { + minval = MIN(minval, *rptr); + } + } else + minval = WL_RATE_DISABLED; + return minval; +} + + +/* Map the given function with its context value over the two power vectors */ +void +ppr_map_vec_dsss(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2, + wl_tx_bw_t bw, wl_tx_chains_t tx_chains) +{ + pprpbw_t* bw_pwrs1; + pprpbw_t* bw_pwrs2; + int8* powers1; + int8* powers2; + uint i; + + ASSERT(pprptr1); + ASSERT(pprptr2); + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + powers1 = (int8*)ppr_get_dsss_group(bw_pwrs1, tx_chains); + powers2 = (int8*)ppr_get_dsss_group(bw_pwrs2, tx_chains); + if ((powers1 != NULL) && (powers2 != NULL)) { + for (i = 0; i < WL_RATESET_SZ_DSSS; i++) + (fn)(context, (uint8*)powers1++, (uint8*)powers2++); + } + } +} + + +/* Map the given function with its context value over the two power vectors */ +void +ppr_map_vec_ofdm(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2, + wl_tx_bw_t bw, wl_tx_mode_t mode, wl_tx_chains_t tx_chains) +{ + pprpbw_t* bw_pwrs1; + pprpbw_t* bw_pwrs2; + int8* powers1; + int8* powers2; + uint i; + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + powers1 = (int8*)ppr_get_ofdm_group(bw_pwrs1, mode, tx_chains); + powers2 = (int8*)ppr_get_ofdm_group(bw_pwrs2, mode, tx_chains); + if ((powers1 != NULL) && (powers2 != NULL)) { + for (i = 0; i < WL_RATESET_SZ_OFDM; i++) + (fn)(context, (uint8*)powers1++, (uint8*)powers2++); + } + } +} + + +/* Map the given function with its context value over the two power vectors */ +void +ppr_map_vec_ht_mcs(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, + ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, + wl_tx_chains_t tx_chains) +{ + pprpbw_t* bw_pwrs1; + pprpbw_t* bw_pwrs2; + int8* powers1; + int8* powers2; + uint i; + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + powers1 = (int8*)ppr_get_mcs_group(bw_pwrs1, Nss, mode, tx_chains); + powers2 = (int8*)ppr_get_mcs_group(bw_pwrs2, Nss, mode, tx_chains); + if ((powers1 != NULL) && (powers2 != NULL)) { + for (i = 0; i < WL_RATESET_SZ_HT_MCS; i++) + (fn)(context, (uint8*)powers1++, (uint8*)powers2++); + } + } +} + + +/* Map the given function with its context value over the two power vectors */ +void +ppr_map_vec_vht_mcs(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, + ppr_t* pprptr2, wl_tx_bw_t bw, wl_tx_nss_t Nss, wl_tx_mode_t mode, wl_tx_chains_t + tx_chains) +{ + pprpbw_t* bw_pwrs1; + pprpbw_t* bw_pwrs2; + int8* powers1; + int8* powers2; + uint i; + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, bw); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, bw); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + powers1 = (int8*)ppr_get_mcs_group(bw_pwrs1, Nss, mode, tx_chains); + powers2 = (int8*)ppr_get_mcs_group(bw_pwrs2, Nss, mode, tx_chains); + if ((powers1 != NULL) && (powers2 != NULL)) { + for (i = 0; i < WL_RATESET_SZ_VHT_MCS; i++) + (fn)(context, (uint8*)powers1++, (uint8*)powers2++); + } + } +} + + +/* Map the given function with its context value over the two power vectors */ + +void +ppr_map_vec_all(ppr_mapfn_t fn, void* context, ppr_t* pprptr1, ppr_t* pprptr2) +{ + uint i; + pprpbw_t* bw_pwrs1; + pprpbw_t* bw_pwrs2; + int8* rptr1 = (int8*)&pprptr1->ppr_bw; + int8* rptr2 = (int8*)&pprptr2->ppr_bw; + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, WL_TX_BW_20); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, WL_TX_BW_20); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + rptr1 = (int8*)bw_pwrs1; + rptr2 = (int8*)bw_pwrs2; + for (i = 0; i < sizeof(pprpbw_t); i++, rptr1++, rptr2++) { + (fn)(context, (uint8*)rptr1, (uint8*)rptr2); + } + } + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, WL_TX_BW_40); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, WL_TX_BW_40); + + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + rptr1 = (int8*)bw_pwrs1; + rptr2 = (int8*)bw_pwrs2; + for (i = 0; i < sizeof(pprpbw_t); i++, rptr1++, rptr2++) { + (fn)(context, (uint8*)rptr1, (uint8*)rptr2); + } + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, WL_TX_BW_20IN40); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, WL_TX_BW_20IN40); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + rptr1 = (int8*)bw_pwrs1; + rptr2 = (int8*)bw_pwrs2; + for (i = 0; i < sizeof(pprpbw_t); i++, rptr1++, rptr2++) { + (fn)(context, (uint8*)rptr1, (uint8*)rptr2); + } + } + } + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, WL_TX_BW_80); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, WL_TX_BW_80); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + rptr1 = (int8*)bw_pwrs1; + rptr2 = (int8*)bw_pwrs2; + for (i = 0; i < sizeof(pprpbw_t); i++, rptr1++, rptr2++) { + (fn)(context, (uint8*)rptr1, (uint8*)rptr2); + } + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, WL_TX_BW_20IN80); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, WL_TX_BW_20IN80); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + rptr1 = (int8*)bw_pwrs1; + rptr2 = (int8*)bw_pwrs2; + for (i = 0; i < sizeof(pprpbw_t); i++, rptr1++, rptr2++) { + (fn)(context, (uint8*)rptr1, (uint8*)rptr2); + } + } + + bw_pwrs1 = ppr_get_bw_powers(pprptr1, WL_TX_BW_40IN80); + bw_pwrs2 = ppr_get_bw_powers(pprptr2, WL_TX_BW_40IN80); + if ((bw_pwrs1 != NULL) && (bw_pwrs2 != NULL)) { + rptr1 = (int8*)bw_pwrs1; + rptr2 = (int8*)bw_pwrs2; + for (i = 0; i < sizeof(pprpbw_t); i++, rptr1++, rptr2++) { + (fn)(context, (uint8*)rptr1, (uint8*)rptr2); + } + } + } +} + + +/* Set PPR struct to a certain power level */ +void +ppr_set_cmn_val(ppr_t* pprptr, int8 val) +{ + memset((uchar*)&pprptr->ppr_bw, val, ppr_pwrs_size(pprptr->ch_bw)); +} + + +/* Make an identical copy of a ppr structure (for ppr_bw==all case) */ +void +ppr_copy_struct(ppr_t* pprptr_s, ppr_t* pprptr_d) +{ + int8* rptr_s = (int8*)&pprptr_s->ppr_bw; + int8* rptr_d = (int8*)&pprptr_d->ppr_bw; + /* ASSERT(ppr_pwrs_size(pprptr_d->ch_bw) >= ppr_pwrs_size(pprptr_s->ch_bw)); */ + + if (pprptr_s->ch_bw == pprptr_d->ch_bw) + bcopy(rptr_s, rptr_d, ppr_pwrs_size(pprptr_s->ch_bw)); + else { + const pprpbw_t* src_bw_pwrs; + pprpbw_t* dest_bw_pwrs; + + src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_20); + dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_20); + if (src_bw_pwrs && dest_bw_pwrs) + bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs, + sizeof(*src_bw_pwrs)); + + src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_40); + dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_40); + if (src_bw_pwrs && dest_bw_pwrs) + bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs, + sizeof(*src_bw_pwrs)); + + src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_20IN40); + dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_20IN40); + if (src_bw_pwrs && dest_bw_pwrs) + bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs, + sizeof(*src_bw_pwrs)); + + src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_80); + dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_80); + if (src_bw_pwrs && dest_bw_pwrs) + bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs, + sizeof(*src_bw_pwrs)); + + src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_20IN80); + dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_20IN80); + if (src_bw_pwrs && dest_bw_pwrs) + bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs, + sizeof(*src_bw_pwrs)); + + src_bw_pwrs = ppr_get_bw_powers(pprptr_s, WL_TX_BW_40IN80); + dest_bw_pwrs = ppr_get_bw_powers(pprptr_d, WL_TX_BW_40IN80); + if (src_bw_pwrs && dest_bw_pwrs) + bcopy((const uint8*)src_bw_pwrs, (uint8*)dest_bw_pwrs, + sizeof(*src_bw_pwrs)); + } +} + + +/* Subtract each power from a common value and re-store */ +void +ppr_cmn_val_minus(ppr_t* pprptr, int8 val) +{ + uint i; + int8* rptr = (int8*)&pprptr->ppr_bw; + + for (i = 0; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++) { + if (*rptr != (int8)WL_RATE_DISABLED) + *rptr = val - *rptr; + } + +} + + +/* Subtract a common value from each power and re-store */ +void +ppr_minus_cmn_val(ppr_t* pprptr, int8 val) +{ + uint i; + int8* rptr = (int8*)&pprptr->ppr_bw; + + for (i = 0; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++) { + if (*rptr != (int8)WL_RATE_DISABLED) + *rptr = (*rptr > val) ? (*rptr - val) : 0; + } + +} + + +/* Add a common value to each power and re-store */ +void +ppr_plus_cmn_val(ppr_t* pprptr, int8 val) +{ + uint i; + int8* rptr = (int8*)&pprptr->ppr_bw; + + for (i = 0; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++) { + if (*rptr != (int8)WL_RATE_DISABLED) + *rptr += val; + } + +} + + +/* Multiply by a percentage */ +void +ppr_multiply_percentage(ppr_t* pprptr, uint8 val) +{ + uint i; + int8* rptr = (int8*)&pprptr->ppr_bw; + + for (i = 0; i < ppr_pwrs_size(pprptr->ch_bw); i++, rptr++) { + if (*rptr != (int8)WL_RATE_DISABLED) + *rptr = (*rptr * val) / 100; + } + +} + + +/* Compare two ppr variables p1 and p2, save the min value of each + * contents to variable p1 + */ +void +ppr_compare_min(ppr_t* p1, ppr_t* p2) +{ + uint i; + int8* rptr1 = NULL; + int8* rptr2 = NULL; + uint32 pprsize = 0; + + if (p1->ch_bw == p2->ch_bw) { + rptr1 = (int8*)&p1->ppr_bw; + rptr2 = (int8*)&p2->ppr_bw; + pprsize = ppr_pwrs_size(p1->ch_bw); + } + + for (i = 0; i < pprsize; i++, rptr1++, rptr2++) { + *rptr1 = MIN(*rptr1, *rptr2); + } +} + + +/* Compare two ppr variables p1 and p2, save the max. value of each + * contents to variable p1 + */ +void +ppr_compare_max(ppr_t* p1, ppr_t* p2) +{ + uint i; + int8* rptr1 = NULL; + int8* rptr2 = NULL; + uint32 pprsize = 0; + + if (p1->ch_bw == p2->ch_bw) { + rptr1 = (int8*)&p1->ppr_bw; + rptr2 = (int8*)&p2->ppr_bw; + pprsize = ppr_pwrs_size(p1->ch_bw); + } + + for (i = 0; i < pprsize; i++, rptr1++, rptr2++) { + *rptr1 = MAX(*rptr1, *rptr2); + } +} + + +/* Serialize the contents of the opaque ppr struct. + * Writes number of bytes copied, zero on error. + * Returns error code, BCME_OK if successful. + */ +int +ppr_serialize(const ppr_t* pprptr, uint8* buf, uint buflen, uint* bytes_copied) +{ + int err = BCME_OK; + if (buflen <= sizeof(ppr_ser_mem_flag_t)) { + err = BCME_BUFTOOSHORT; + } else { + ppr_ser_mem_flag_t *smem_flag = (ppr_ser_mem_flag_t *)buf; + uint32 flag = NTOH32(smem_flag->flag); + + /* check if memory contains a valid flag, if not, use current + * condition (num of chains, txbf etc.) to serialize data. + */ + if (NTOH32(smem_flag->magic_word) != PPR_SER_MEM_WORD) { + flag = ppr_get_flag(); + } + + if (buflen >= ppr_ser_size_by_flag(flag, pprptr->ch_bw)) { + *bytes_copied = ppr_serialize_data(pprptr, buf, flag); + } else { + err = BCME_BUFTOOSHORT; + } + } + return err; +} + + +/* Deserialize the contents of a buffer into an opaque ppr struct. + * Creates an opaque structure referenced by *pptrptr, NULL on error. + * Returns error code, BCME_OK if successful. + */ +int +ppr_deserialize_create(osl_t *osh, const uint8* buf, uint buflen, ppr_t** pprptr) +{ + const uint8* bptr = buf; + int err = BCME_OK; + ppr_t* lpprptr = NULL; + + if ((buflen > SER_HDR_LEN) && (bptr != NULL) && (*bptr == PPR_SERIALIZATION_VER)) { + const ppr_deser_header_t * ser_head = (const ppr_deser_header_t *)bptr; + wl_tx_bw_t ch_bw = ser_head->bw; + /* struct size plus header */ + uint32 ser_size = ppr_pwrs_size(ch_bw) + SER_HDR_LEN; + + if ((lpprptr = ppr_create(osh, ch_bw)) != NULL) { + uint32 flags = NTOH32(ser_head->flags); + uint16 per_band_size = NTOH16(ser_head->per_band_size); + /* set the data with default value before deserialize */ + ppr_set_cmn_val(lpprptr, WL_RATE_DISABLED); + + ppr_deser_cpy(lpprptr, bptr + sizeof(*ser_head), flags, ch_bw, + per_band_size); + } else if (buflen < ser_size) { + err = BCME_BUFTOOSHORT; + } else { + err = BCME_NOMEM; + } + } else if (buflen <= SER_HDR_LEN) { + err = BCME_BUFTOOSHORT; + } else if (bptr == NULL) { + err = BCME_BADARG; + } else { + err = BCME_VERSION; + } + *pprptr = lpprptr; + return err; +} + + +/* Deserialize the contents of a buffer into an opaque ppr struct. + * Creates an opaque structure referenced by *pptrptr, NULL on error. + * Returns error code, BCME_OK if successful. + */ +int +ppr_deserialize(ppr_t* pprptr, const uint8* buf, uint buflen) +{ + const uint8* bptr = buf; + int err = BCME_OK; + ASSERT(pprptr); + if ((buflen > SER_HDR_LEN) && (bptr != NULL) && (*bptr == PPR_SERIALIZATION_VER)) { + const ppr_deser_header_t * ser_head = (const ppr_deser_header_t *)bptr; + wl_tx_bw_t ch_bw = ser_head->bw; + + if (ch_bw == pprptr->ch_bw) { + uint32 flags = NTOH32(ser_head->flags); + uint16 per_band_size = NTOH16(ser_head->per_band_size); + ppr_set_cmn_val(pprptr, WL_RATE_DISABLED); + ppr_deser_cpy(pprptr, bptr + sizeof(*ser_head), flags, ch_bw, + per_band_size); + } else { + err = BCME_BADARG; + } + } else if (buflen <= SER_HDR_LEN) { + err = BCME_BUFTOOSHORT; + } else if (bptr == NULL) { + err = BCME_BADARG; + } else { + err = BCME_VERSION; + } + return err; +} + + +#ifdef WLTXPWR_CACHE + +#define MAX_TXPWR_CACHE_ENTRIES 2 +#define TXPWR_ALL_INVALID 0xff +#define TXPWR_CACHE_TXPWR_MAX 0x7f /* WLC_TXPWR_MAX; */ + +/* transmit power cache */ +typedef struct tx_pwr_cache_entry { + chanspec_t chanspec; + ppr_t* cache_pwrs[TXPWR_CACHE_NUM_TYPES]; + uint8 tx_pwr_max[PPR_MAX_TX_CHAINS]; + uint8 tx_pwr_min[PPR_MAX_TX_CHAINS]; + int8 txchain_offsets[PPR_MAX_TX_CHAINS]; + uint8 data_invalid_flags; + int stf_tx_target_pwr_min; +} tx_pwr_cache_entry_t; + +#ifdef TXPWR_CACHE_IN_ROM +uint8 txpwr_cache[MAX_TXPWR_CACHE_ENTRIES*16] = {0}; +#endif + +static tx_pwr_cache_entry_t tx_pwr_cache[MAX_TXPWR_CACHE_ENTRIES] = {{0}, {0}}; + +static int stf_tx_pwr_min = TXPWR_CACHE_TXPWR_MAX; + +static tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_get_entry(chanspec_t chanspec); +static tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_get_diff_entry(chanspec_t chanspec); +static void wlc_phy_txpwr_cache_clear_entry(osl_t *osh, tx_pwr_cache_entry_t* entryptr); + + +/* Find a cache entry for the specified chanspec. */ +static tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_get_entry(chanspec_t chanspec) +{ + uint i; + tx_pwr_cache_entry_t* entryptr = NULL; + + for (i = 0; i < (MAX_TXPWR_CACHE_ENTRIES) && (entryptr == NULL); i++) { + if (tx_pwr_cache[i].chanspec == chanspec) { + entryptr = &tx_pwr_cache[i]; + } + } + return entryptr; +} + + +/* Find a cache entry that's NOT for the specified chanspec. */ +static tx_pwr_cache_entry_t* wlc_phy_txpwr_cache_get_diff_entry(chanspec_t chanspec) +{ + uint i; + tx_pwr_cache_entry_t* entryptr = NULL; + + for (i = 0; i < (MAX_TXPWR_CACHE_ENTRIES) && (entryptr == NULL); i++) { + if (tx_pwr_cache[i].chanspec != chanspec) { + entryptr = &tx_pwr_cache[i]; + } + } + return entryptr; +} + + +/* Clear a specific cache entry. Delete any ppr_t structs and clear the pointers. */ +static void wlc_phy_txpwr_cache_clear_entry(osl_t *osh, tx_pwr_cache_entry_t* entryptr) +{ + uint i; + + entryptr->chanspec = 0; + + ASSERT(entryptr != NULL); + for (i = 0; i < TXPWR_CACHE_NUM_TYPES; i++) { + if (entryptr->cache_pwrs[i] != NULL) { + ppr_delete(osh, entryptr->cache_pwrs[i]); + entryptr->cache_pwrs[i] = NULL; + } + } + /* + * Don't bother with max, min and txchain_offsets, as they need to be + * initialised when the entry is setup for a new chanspec + */ +} + + +/* + * Get a ppr_t struct of a given type from the cache for the specified chanspec. + * Don't return the pointer if the cached data is invalid. + */ +ppr_t* wlc_phy_get_cached_pwr(chanspec_t chanspec, uint pwr_type) +{ + ppr_t* pwrptr = NULL; + + if (pwr_type < TXPWR_CACHE_NUM_TYPES) { + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if ((entryptr != NULL) && + ((entryptr->data_invalid_flags & (0x01 << pwr_type)) == 0)) + pwrptr = entryptr->cache_pwrs[pwr_type]; + } + + return pwrptr; +} + + +/* Add a ppr_t struct of a given type to the cache for the specified chanspec. */ +int wlc_phy_set_cached_pwr(osl_t *osh, chanspec_t chanspec, uint pwr_type, ppr_t* pwrptr) +{ + int result = BCME_NOTFOUND; + + if (pwr_type < TXPWR_CACHE_NUM_TYPES) { + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if (entryptr != NULL) { + if ((entryptr->cache_pwrs[pwr_type] != NULL) && + (entryptr->cache_pwrs[pwr_type] != pwrptr)) { + ppr_delete(osh, entryptr->cache_pwrs[pwr_type]); + } + entryptr->cache_pwrs[pwr_type] = pwrptr; + entryptr->data_invalid_flags &= ~(0x01 << pwr_type); /* now valid */ + result = BCME_OK; + } + } + return result; +} + +/* Indicate if we have cached a particular ppr_t struct for any chanspec. */ +bool wlc_phy_is_pwr_cached(uint pwr_type, ppr_t* pwrptr) +{ + bool result = FALSE; + uint i; + + if (pwr_type < TXPWR_CACHE_NUM_TYPES) { + for (i = 0; (i < MAX_TXPWR_CACHE_ENTRIES) && (result == FALSE); i++) { + if (tx_pwr_cache[i].cache_pwrs[pwr_type] == pwrptr) { + result = TRUE; + } + } + } + return result; +} + +/* Get the minimum target power for all cores for the chanspec. */ +int wlc_phy_get_cached_stf_target_pwr_min(chanspec_t chanspec) +{ + int min_pwr = TXPWR_CACHE_TXPWR_MAX; + + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if ((entryptr != NULL) && + ((entryptr->data_invalid_flags & (TXPWR_STF_TARGET_PWR_MIN_INVALID)) == 0)) + min_pwr = entryptr->stf_tx_target_pwr_min; + + return min_pwr; +} + + +/* set the minimum target power for all cores for the chanspec. */ +int wlc_phy_set_cached_stf_target_pwr_min(chanspec_t chanspec, int min_pwr) +{ + int result = BCME_NOTFOUND; + + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if (entryptr != NULL) { + entryptr->stf_tx_target_pwr_min = min_pwr; + entryptr->data_invalid_flags &= ~TXPWR_STF_TARGET_PWR_MIN_INVALID; /* now valid */ + result = BCME_OK; + } + return result; +} + + +/* Get the maximum power for the specified core and chanspec. */ +uint8 wlc_phy_get_cached_pwr_max(chanspec_t chanspec, uint core) +{ + uint8 max_pwr = WL_RATE_DISABLED; + + if (core < PPR_MAX_TX_CHAINS) { + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if (entryptr != NULL) + max_pwr = entryptr->tx_pwr_max[core]; + } + + return max_pwr; +} + + +/* Set the maximum power for the specified core and chanspec. */ +int wlc_phy_set_cached_pwr_max(chanspec_t chanspec, uint core, uint8 max_pwr) +{ + int result = BCME_NOTFOUND; + + if (core < PPR_MAX_TX_CHAINS) { + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if (entryptr != NULL) { + entryptr->tx_pwr_max[core] = max_pwr; + result = BCME_OK; + } + } + return result; +} + + +/* Get the minimum power for the specified core and chanspec. */ +uint8 wlc_phy_get_cached_pwr_min(chanspec_t chanspec, uint core) +{ + uint8 min_pwr = WL_RATE_DISABLED; + + if (core < PPR_MAX_TX_CHAINS) { + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if (entryptr != NULL) + min_pwr = entryptr->tx_pwr_min[core]; + } + + return min_pwr; +} + + +/* Set the minimum power for the specified core and chanspec. */ +int wlc_phy_set_cached_pwr_min(chanspec_t chanspec, uint core, uint8 min_pwr) +{ + int result = BCME_NOTFOUND; + + if (core < PPR_MAX_TX_CHAINS) { + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if (entryptr != NULL) { + entryptr->tx_pwr_min[core] = min_pwr; + result = BCME_OK; + } + } + return result; +} + + +/* Get the txchain offsets for the specified chanspec. */ +int8 wlc_phy_get_cached_txchain_offsets(chanspec_t chanspec, uint core) +{ + uint8 offset = WL_RATE_DISABLED; + + if (core < PPR_MAX_TX_CHAINS) { + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if (entryptr != NULL) + offset = entryptr->txchain_offsets[core]; + } + + return offset; +} + + +/* Set the txchain offsets for the specified chanspec. */ +int wlc_phy_set_cached_txchain_offsets(chanspec_t chanspec, uint core, int8 offset) +{ + int result = BCME_NOTFOUND; + + if (core < PPR_MAX_TX_CHAINS) { + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + + if (entryptr != NULL) { + entryptr->txchain_offsets[core] = offset; + result = BCME_OK; + } + } + return result; +} + + +/* Indicate if we have a cache entry for the specified chanspec. */ +bool wlc_phy_txpwr_cache_is_cached(chanspec_t chanspec) +{ + bool result = FALSE; + + if (wlc_phy_txpwr_cache_get_entry(chanspec)) { + result = TRUE; + } + return result; +} + + +/* Find a cache entry that's NOT for the specified chanspec. Return the chanspec. */ +chanspec_t wlc_phy_txpwr_cache_find_other_cached_chanspec(chanspec_t chanspec) +{ + chanspec_t chan = 0; + + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_diff_entry(chanspec); + if (entryptr != NULL) { + chan = entryptr->chanspec; + } + return chan; +} + + +/* Find a specific cache entry and clear it. */ +void wlc_phy_txpwr_cache_clear(osl_t *osh, chanspec_t chanspec) +{ + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + if (entryptr != NULL) { + wlc_phy_txpwr_cache_clear_entry(osh, entryptr); + } +} + + +/* Invalidate all cached data. */ +void wlc_phy_txpwr_cache_invalidate(void) +{ + uint j; + + for (j = 0; j < MAX_TXPWR_CACHE_ENTRIES; j++) { + tx_pwr_cache_entry_t* entryptr = &tx_pwr_cache[j]; + if (entryptr->chanspec != 0) { + uint i; + entryptr->data_invalid_flags = TXPWR_ALL_INVALID; + for (i = 0; i < PPR_MAX_TX_CHAINS; i++) { + entryptr->tx_pwr_min[i] = TXPWR_CACHE_TXPWR_MAX; + entryptr->tx_pwr_max[i] = WL_RATE_DISABLED; + entryptr->txchain_offsets[i] = WL_RATE_DISABLED; + } + entryptr->stf_tx_target_pwr_min = TXPWR_CACHE_TXPWR_MAX; + } + } +} + +/* Clear all cache entries. */ +void wlc_phy_txpwr_cache_close(osl_t *osh) +{ + uint i; + + for (i = 0; i < MAX_TXPWR_CACHE_ENTRIES; i++) { + tx_pwr_cache_entry_t* entryptr = &tx_pwr_cache[i]; + if (entryptr->chanspec != 0) { + wlc_phy_txpwr_cache_clear_entry(osh, entryptr); + } + } +} + + +/* Find an empty cache entry and initialise it. */ +int wlc_phy_txpwr_setup_entry(chanspec_t chanspec) +{ + int result = BCME_NOTFOUND; + /* find an empty entry */ + tx_pwr_cache_entry_t* entryptr = wlc_phy_txpwr_cache_get_entry(0); + if (entryptr != NULL) { + uint i; + + entryptr->chanspec = chanspec; + for (i = 0; i < PPR_MAX_TX_CHAINS; i++) { + entryptr->tx_pwr_min[i] = TXPWR_CACHE_TXPWR_MAX; /* WLC_TXPWR_MAX; */ + entryptr->tx_pwr_max[i] = WL_RATE_DISABLED; + entryptr->txchain_offsets[i] = WL_RATE_DISABLED; + } + entryptr->stf_tx_target_pwr_min = TXPWR_CACHE_TXPWR_MAX; + entryptr->data_invalid_flags |= TXPWR_STF_TARGET_PWR_NOT_CACHED; + result = BCME_OK; + } + return result; +} + +/* Drop any reference to a particular ppr_t struct from the cache. */ +void wlc_phy_uncache_pwr(uint pwr_type, ppr_t* pwrptr) +{ + bool result = FALSE; + uint i; + + if (pwr_type < TXPWR_CACHE_NUM_TYPES) { + for (i = 0; (i < MAX_TXPWR_CACHE_ENTRIES) && (result == FALSE); i++) { + if (tx_pwr_cache[i].cache_pwrs[pwr_type] == pwrptr) { + tx_pwr_cache[i].cache_pwrs[pwr_type] = NULL; + } + } + } +} + +bool wlc_phy_get_stf_ppr_cached(chanspec_t chanspec) +{ + bool ret = FALSE; + tx_pwr_cache_entry_t *entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + if (entryptr != NULL) + ret = !(entryptr->data_invalid_flags & TXPWR_STF_TARGET_PWR_NOT_CACHED); + return ret; +} + +void wlc_phy_set_stf_ppr_cached(chanspec_t chanspec, bool bcached) +{ + tx_pwr_cache_entry_t *entryptr = wlc_phy_txpwr_cache_get_entry(chanspec); + if (entryptr != NULL) { + if (bcached) + entryptr->data_invalid_flags &= ~TXPWR_STF_TARGET_PWR_NOT_CACHED; + else + entryptr->data_invalid_flags |= TXPWR_STF_TARGET_PWR_NOT_CACHED; + } +} + +/* Get the cached minimum Tx power */ +int wlc_phy_get_cached_stf_pwr_min_dbm(void) +{ + return stf_tx_pwr_min; +} + +/* set the cached minimum Tx power */ +void wlc_phy_set_cached_stf_pwr_min_dbm(int min_pwr) +{ + stf_tx_pwr_min = min_pwr; +} + +#endif /* WLTXPWR_CACHE */