diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 26b6adcf9..c2b604f89 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -9,7 +9,7 @@ on: jobs: build: runs-on: ubuntu-latest - + strategy: matrix: platform: @@ -17,6 +17,8 @@ jobs: makefile_path: "build/linux/rpi/makefile" - name: "Banana Pi R4 - MLO" makefile_path: "build/linux/bpi/makefile" + - name: "Platform Mock Unittests" + makefile_path: "build/linux/mockplatform/makefile" fail-fast: false name: Build for ${{ matrix.platform.name }} @@ -69,7 +71,9 @@ jobs: golang \ pkg-config \ libperl-dev \ - libjson-c-dev + libjson-c-dev \ + libgtest-dev \ + libgmock-dev # Steps for ucode installation required for hostapd compilation git clone https://github.com/jow-/ucode.git ucode @@ -92,4 +96,4 @@ jobs: - name: Build OneWiFi for ${{ matrix.platform.name }} working-directory: easymesh_project/OneWifi run: | - make -f ${{ matrix.platform.makefile_path }} all \ No newline at end of file + make -f ${{ matrix.platform.makefile_path }} all diff --git a/build/linux/mockplatform/makefile b/build/linux/mockplatform/makefile new file mode 100644 index 000000000..243684799 --- /dev/null +++ b/build/linux/mockplatform/makefile @@ -0,0 +1,541 @@ +# +# The PROGRAM macro defines the name of the program or project. It +# allows the program name to be changed by editing in only one +# location +# + +# +# Command line parameters: Edit these parameters so that you can +# easily run the sample by typing "make -f Makefile.Linux run". +# +# You will need to: +# (1) Describe parameters here. ex: IN_SHAPEFILE is the input shapefile +# (2) Define parameters below this comment box. +# ex: IN_SHAPEFILE = /mycomp/data/shapefile.shp +# (3) Add the parameters to the run target at the end of this file +# ex: ./$(PROGRAM) $(IN_SHAPEFILE) +# + +# +# The INCLUDEDIRS macro contains a list of include directories +# to pass to the compiler so it can find necessary header files. +# +# The LIBDIRS macro contains a list of library directories +# to pass to the linker so it can find necessary libraries. +# +# The LIBS macro contains a list of libraries that the the +# executable must be linked against. +# + +include build/linux/makefile.inc + + +EASY_MESH_NODE = 1 +EM_APP = 1 +ONEWIFI_STA_MGR_APP_SUPPORT = 1 + +# wifi hal rules +HAL_LIBRARY = $(INSTALLDIR)/lib/libwifihal.a +WEBCONFIG_LIBRARY = $(INSTALLDIR)/lib/libwebconfig.a +HE_BUS_LIBRARY = $(INSTALLDIR)/lib/libhebus.a + +INCLUDE_HAL_LIB_DIRS = \ + -I$(ONE_WIFI_HOME)/include \ + -I$(WIFI_RDK_HAL)/src \ + -I$(WIFI_RDK_HAL)/util_crypto \ + -I$(WIFI_DEVICE_HAL)/ \ + -I$(WIFI_SYSCALL_WRAPPER)/source/ \ + -I$(WIFI_CJSON)/ + +INCLUDE_HOSTAP_LIB_DIRS = \ + -I$(WIFI_HOSTAP_BASE) \ + -I$(WIFI_HOSTAP_SUPPLICANT) \ + -I$(WIFI_HOSTAP_SRC) \ + -I$(WIFI_HOSTAP_SRC)/ap \ + -I$(WIFI_HOSTAP_SRC)/utils \ + -I$(WIFI_HOSTAP_SRC)/drivers \ + +EXCLUDE = $(WIFI_RDK_HAL)/src/wifi_hal_frame_test.c $(WIFI_RDK_HAL)/src/wifi_hal_dpp.c + +HAL_LIB_SOURCES = $(filter-out $(EXCLUDE),$(wildcard $(WIFI_RDK_HAL)/src/*.c)) \ + $(wildcard $(WIFI_RDK_HAL)/platform/raspberry-pi/*.c) \ + $(wildcard $(WIFI_DEVICE_HAL)/*.c) \ + $(WIFI_HOSTAP_SRC)/ap/ieee802_11_auth.c \ + $(WIFI_HOSTAP_SRC)/ap/ap_config.c \ + $(WIFI_HOSTAP_SRC)/ap/ieee802_11.c \ + $(WIFI_HOSTAP_SRC)/ap/ieee802_11_shared.c \ + $(WIFI_HOSTAP_SRC)/ap/ieee802_11_vht.c \ + $(WIFI_HOSTAP_SRC)/ap/ieee802_11_he.c \ + $(WIFI_HOSTAP_SRC)/ap/ieee802_11_ht.c \ + $(WIFI_HOSTAP_SRC)/ap/ieee802_1x.c \ + $(WIFI_HOSTAP_SRC)/ap/ap_mlme.c \ + $(WIFI_HOSTAP_SRC)/ap/ap_list.c \ + $(WIFI_HOSTAP_SRC)/ap/sta_info.c \ + $(WIFI_HOSTAP_SRC)/ap/wnm_ap.c \ + $(WIFI_HOSTAP_SRC)/ap/wpa_auth.c \ + $(WIFI_HOSTAP_SRC)/ap/wpa_auth_ie.c \ + $(WIFI_HOSTAP_SRC)/ap/wpa_auth_glue.c \ + $(WIFI_HOSTAP_SRC)/ap/wps_hostapd.c \ + $(WIFI_HOSTAP_SRC)/ap/pmksa_cache_auth.c \ + $(WIFI_HOSTAP_SRC)/ap/eap_user_db.c \ + $(WIFI_HOSTAP_SRC)/ap/tkip_countermeasures.c \ + $(WIFI_HOSTAP_SRC)/ap/hostapd.c \ + $(WIFI_HOSTAP_SRC)/ap/beacon.c \ + $(WIFI_HOSTAP_SRC)/ap/hs20.c \ + $(WIFI_HOSTAP_SRC)/ap/rrm.c \ + $(WIFI_HOSTAP_SRC)/ap/wmm.c \ + $(WIFI_HOSTAP_SRC)/ap/authsrv.c \ + $(WIFI_HOSTAP_SRC)/ap/bss_load.c \ + $(WIFI_HOSTAP_SRC)/ap/vlan.c \ + $(WIFI_HOSTAP_SRC)/ap/vlan_init.c \ + $(WIFI_HOSTAP_SRC)/ap/vlan_ifconfig.c \ + $(WIFI_HOSTAP_SRC)/ap/ap_drv_ops.c \ + $(WIFI_HOSTAP_SRC)/ap/accounting.c \ + $(WIFI_HOSTAP_SRC)/ap/neighbor_db.c \ + $(WIFI_HOSTAP_SRC)/ap/drv_callbacks.c \ + $(WIFI_HOSTAP_SRC)/ap/ctrl_iface_ap.c \ + $(WIFI_HOSTAP_SRC)/ap/hw_features.c \ + $(WIFI_HOSTAP_SRC)/ap/dfs.c \ + $(WIFI_HOSTAP_SRC)/ap/utils.c \ + $(WIFI_HOSTAP_SRC)/ap/greylist.c \ + $(WIFI_HOSTAP_SRC)/eapol_auth/eapol_auth_sm.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_methods.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_gtc.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_identity.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_md5.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_mschapv2.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_peap.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_tls_common.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_tls.c \ + $(WIFI_HOSTAP_SRC)/eap_server/eap_server_ttls.c \ + $(WIFI_HOSTAP_SRC)/eap_common/chap.c \ + $(WIFI_HOSTAP_SRC)/eap_common/eap_peap_common.c \ + $(WIFI_HOSTAP_SRC)/eap_common/eap_common.c \ + $(WIFI_HOSTAP_SRC)/eap_common/eap_pwd_common.c \ + $(wildcard $(WIFI_HOSTAP_SRC)/eap_peer/*.c) \ + $(WIFI_HOSTAP_SRC)/wps/wps.c \ + $(WIFI_HOSTAP_SRC)/wps/wps_attr_build.c \ + $(WIFI_HOSTAP_SRC)/wps/wps_attr_parse.c \ + $(WIFI_HOSTAP_SRC)/wps/wps_attr_process.c \ + $(WIFI_HOSTAP_SRC)/wps/wps_dev_attr.c \ + $(WIFI_HOSTAP_SRC)/wps/wps_common.c \ + $(WIFI_HOSTAP_SRC)/wps/wps_registrar.c \ + $(WIFI_HOSTAP_SRC)/wps/wps_enrollee.c \ + $(WIFI_HOSTAP_SRC)/radius/radius.c \ + $(WIFI_HOSTAP_SRC)/radius/radius_client.c \ + $(WIFI_HOSTAP_SRC)/radius/radius_das.c \ + $(WIFI_HOSTAP_SRC)/utils/wpabuf.c \ + $(WIFI_HOSTAP_SRC)/utils/wpa_debug.c \ + $(WIFI_HOSTAP_SRC)/utils/os_unix.c \ + $(WIFI_HOSTAP_SRC)/utils/eloop.c \ + $(WIFI_HOSTAP_SRC)/utils/common.c \ + $(WIFI_HOSTAP_SRC)/utils/ip_addr.c \ + $(WIFI_HOSTAP_SRC)/utils/uuid.c \ + $(WIFI_HOSTAP_SRC)/utils/radiotap.c \ + $(WIFI_HOSTAP_SRC)/utils/crc32.c \ + $(WIFI_HOSTAP_SRC)/common/wpa_common.c \ + $(WIFI_HOSTAP_SRC)/common/hw_features_common.c \ + $(WIFI_HOSTAP_SRC)/common/ieee802_11_common.c \ + $(WIFI_HOSTAP_SRC)/common/ctrl_iface_common.c \ + $(WIFI_HOSTAP_SRC)/common/dragonfly.c \ + $(WIFI_HOSTAP_SRC)/crypto/crypto_openssl.c \ + $(WIFI_HOSTAP_SRC)/crypto/ms_funcs.c \ + $(WIFI_HOSTAP_SRC)/crypto/sha1-prf.c \ + $(WIFI_HOSTAP_SRC)/crypto/sha1-pbkdf2.c \ + $(WIFI_HOSTAP_SRC)/crypto/random.c \ + $(WIFI_HOSTAP_SRC)/crypto/tls_internal.c \ + $(WIFI_HOSTAP_SRC)/crypto/dh_groups.c \ + $(WIFI_HOSTAP_SRC)/crypto/sha1.c \ + $(WIFI_HOSTAP_SRC)/crypto/sha1-internal.c \ + $(WIFI_HOSTAP_SRC)/crypto/sha256-internal.c \ + $(WIFI_HOSTAP_SRC)/crypto/md5-internal.c \ + $(WIFI_HOSTAP_SRC)/crypto/sha256.c \ + $(WIFI_HOSTAP_SRC)/crypto/sha256-prf.c \ + $(WIFI_HOSTAP_SRC)/crypto/aes-cbc.c \ + $(WIFI_HOSTAP_SRC)/crypto/aes-internal.c \ + $(WIFI_HOSTAP_SRC)/l2_packet/l2_packet_linux.c \ + $(WIFI_HOSTAP_SRC)/rsn_supp/wpa.c \ + $(WIFI_HOSTAP_SRC)/rsn_supp/wpa_ie.c \ + $(WIFI_HOSTAP_SRC)/rsn_supp/wpa_ft.c \ + $(WIFI_HOSTAP_SRC)/rsn_supp/pmksa_cache.c \ + $(WIFI_HOSTAP_SRC)/rsn_supp/preauth.c \ + $(WIFI_HOSTAP_SRC)/eapol_supp/eapol_supp_sm.c \ + $(WIFI_HOSTAP_BASE)/hostapd/ctrl_iface.c \ + $(WIFI_HOSTAP_BASE)/hostapd/config_file.c \ + $(WIFI_HOSTAP_BASE)/hostapd/eap_register.c \ + $(WIFI_HOSTAP_SRC)/drivers/drivers.c \ + $(WIFI_HOSTAP_SRC)/drivers/driver_common.c \ + $(WIFI_HOSTAP_SRC)/drivers/driver_nl80211.c \ + $(WIFI_HOSTAP_SRC)/drivers/driver_nl80211_event.c \ + $(WIFI_HOSTAP_SRC)/drivers/driver_nl80211_monitor.c \ + $(WIFI_HOSTAP_SRC)/drivers/driver_nl80211_scan.c \ + $(WIFI_HOSTAP_SRC)/drivers/driver_nl80211_capa.c \ + $(WIFI_HOSTAP_SRC)/drivers/linux_ioctl.c \ + $(WIFI_HOSTAP_SRC)/drivers/netlink.c \ + $(WIFI_HOSTAP_SRC)/drivers/rfkill.c \ + +HAL_LIB_OBJECTS = $(HAL_LIB_SOURCES:.c=.o) # expands to list of object files +ALL_HAL_LIB_OBJECTS = $(HAL_LIB_OBJECTS) +HAL_LIB_FLAGS = -g -fPIC $(INCLUDE_HAL_LIB_DIRS) -DENABLE_FEATURE_MESHWIFI -DRASPBERRY_PI_PORT -D_PLATFORM_RASPBERRYPI_ -DCONFIG_HW_CAPABILITIES -DEM_APP +HOSTAP_LIB_FLAGS = -g -fPIC $(INCLUDE_HOSTAP_LIB_DIRS) -DHOSTAPD -DCONFIG_CRYPTO_INTERNAL -DCONFIG_DRIVER_NL80211 -DNEED_AP_MLME -DCONFIG_IEEE80211AC -DCONFIG_IEEE80211AX -DCONFIG_IEEE80211N -DCONFIG_WPS -DIEEE8021X_EAPOL -DEAP_SERVER_IDENTITY -DEAP_SERVER_MD5 -DEAP_SERVER_TLS -DEAP_SERVER_MSCHAPV2 -DEAP_SERVER_PEAP -DEAP_SERVER_TTLS -DCONFIG_ECC -DRDK_ONEWIFI -DCONFIG_IEEE80211W -DCONFIG_OPENSSL_CMAC -DCONFIG_LIBNL20 -DCONFIG_HS20 -DCONFIG_WNM_AP +HOSTAP_LIB_FLAGS += -DHOSTAPD_2_10 -DCONFIG_WEP -DFEATURE_SUPPORT_RADIUSGREYLIST -DCONFIG_DRIVER_BRCM -DCONFIG_DRIVER_BRCM_MAP + +# wifi agent rules + +LDFLAGS = $(LIBDIRS) $(LIBS) + +PROGRAM = $(INSTALLDIR)/bin/OneWifi + +INCLUDEDIRS = \ + -I$(WIFI_CCSP_COMMON_LIB)/source/cosa/include \ + -I$(WIFI_CCSP_COMMON_LIB)/source/cosa/include/linux \ + -I$(WIFI_CCSP_COMMON_LIB)/source/cosa/package/slap/include \ + -I$(WIFI_CCSP_COMMON_LIB)/source/ccsp/components/include \ + -I$(WIFI_CCSP_COMMON_LIB)/source/ccsp/components/common/MessageBusHelper/include \ + -I$(WIFI_CCSP_COMMON_LIB)/source/ccsp/components/common/PoamIrepFolder \ + -I$(WIFI_CCSP_COMMON_LIB)/source/ccsp/custom \ + -I$(WIFI_CCSP_COMMON_LIB)/source/ccsp/include \ + -I$(WIFI_CCSP_COMMON_LIB)/source/debug_api/include \ + -I$(WIFI_CCSP_COMMON_LIB)/source/dm_pack \ + -I$(WIFI_CCSP_COMMON_LIB)/source/util_api/http/include \ + -I$(WIFI_CCSP_COMMON_LIB)/source/util_api/ansc/include \ + -I$(WIFI_CCSP_COMMON_LIB)/WebConfig_Framework \ + -I$(WIFI_MSGPACK)/include \ + -I$(WIFI_UTOPIA)/source/include \ + -I$(WIFI_UTOPIA)/source/util/print_uptime \ + -I$(WIFI_DBUS)/ \ + -I$(BASE_DIR) \ + -I$(ONE_WIFI_HOME)/source/dml/tr_181/sbapi \ + -I$(ONE_WIFI_HOME)/source/sampleapps \ + -I$(ONE_WIFI_HOME)/source/dml/tr_181/ml \ + -I$(ONE_WIFI_HOME)/source/dml/wifi_ssp \ + -I$(ONE_WIFI_HOME)/source/ccsp \ + -I$(ONE_WIFI_HOME)/source/utils \ + -I$(ONE_WIFI_HOME)/source/utils/mtrx/inc \ + -I$(ONE_WIFI_HOME)/source/stats \ + -I$(ONE_WIFI_HOME)/source/stubs \ + -I$(ONE_WIFI_HOME)/source/dml/linux \ + -I$(ONE_WIFI_HOME)/source/platform/linux \ + -I$(ONE_WIFI_HOME)/source/platform/common \ + -I$(ONE_WIFI_HOME)/lib/pktgen/ \ + -I$(ONE_WIFI_HOME)/source/core \ + -I$(ONE_WIFI_HOME)/source/apps \ + -I$(ONE_WIFI_HOME)/source/apps/analytics \ + -I$(ONE_WIFI_HOME)/source/apps/multi_ap \ + -I$(ONE_WIFI_HOME)/source/apps/blaster \ + -I$(ONE_WIFI_HOME)/source/apps/cac \ + -I$(ONE_WIFI_HOME)/source/apps/csi \ + -I$(ONE_WIFI_HOME)/source/apps/harvester \ + -I$(ONE_WIFI_HOME)/source/apps/levl \ + -I$(ONE_WIFI_HOME)/source/apps/memwraptool \ + -I$(ONE_WIFI_HOME)/source/apps/sta_mgr \ + -I$(ONE_WIFI_HOME)/source/apps/motion \ + -I$(ONE_WIFI_HOME)/source/apps/ocs \ + -I$(ONE_WIFI_HOME)/source/apps/sm \ + -I$(ONE_WIFI_HOME)/source/apps/whix \ + -I$(ONE_WIFI_HOME)/source/apps/easyconnect \ + -I$(ONE_WIFI_HOME)/source/apps/em \ + -I$(ONE_WIFI_HOME)/source/apps/linkquality \ + -I$(ONE_WIFI_HOME)/source/apps/wifi_sensing/inc \ + -I$(ONE_WIFI_HOME)/source/utils/quality_mgr/inc/ \ + -I$(ONE_WIFI_HOME)/source/utils/math_utils/inc/ \ + -I$(ONE_WIFI_HOME)/source/core/services \ + -I$(ONE_WIFI_HOME)/include/tr_181/ml \ + -I$(ONE_WIFI_HOME)/include \ + -I$(ONE_WIFI_HOME)/source/db \ + -I$(ONE_WIFI_HOME)/lib/common \ + -I$(ONE_WIFI_HOME)/lib/log \ + -I$(ONE_WIFI_HOME)/lib/ds \ + -I$(ONE_WIFI_HOME)/lib/ovsdb \ + -I$(ONE_WIFI_HOME)/lib/pjs \ + -I$(ONE_WIFI_HOME)/lib/json_util \ + -I$(ONE_WIFI_HOME)/lib/inc \ + -I$(ONE_WIFI_HOME)/lib/osa \ + -I$(ONE_WIFI_HOME)/lib/const \ + -I$(ONE_WIFI_HOME)/lib/schema \ + -I$(ONE_WIFI_HOME)/lib/datapipeline \ + -I$(WIFI_HAL_INTERFACE) \ + -I/usr/local/ssl/include/ \ + -I/usr/include/libnl3 \ + -I$(WIFI_HOSTAP_BASE) \ + -I$(WIFI_HOSTAP_SRC) \ + -I$(WIFI_HOSTAP_SRC)/ap \ + -I$(WIFI_NETLINK)/include \ + -I$(WIFI_TROWER_BASE) \ + +LIBDIRS = \ + -L$(INSTALLDIR)/lib \ + -L/usr/local/lib \ + -L/usr/local/ssl/lib/ \ + +ifneq ($(OS), Darwin) +LIBDIRS += -L$(INSTALLDIR)/lib/platform/x86-64 +else +LIBDIRS += -L$(INSTALLDIR)/lib/platform/darwin +endif + +LIBS = -lm -luuid -lwifihal -lpthread -ldl -ljansson -lev -lssl -lcrypto -lnl-3 -lnl-genl-3 -lnl-route-3 -lavro -lcjson + +# +# The CXXSOURCES macro contains a list of source files. +# +# The CXXOBJECTS macro converts the CXXSOURCES macro into a list +# of object files. +# +# The CFLAGS macro contains a list of options to be passed to +# the compiler. Adding "-g" to this line will cause the compiler +# to add debugging information to the executable. +# +# The CXX macro defines the C++ compiler. +# +# The LDFLAGS macro contains all of the library and library +# directory information to be passed to the linker. +# + +CSOURCES = $(wildcard $(ONE_WIFI_HOME)/source/db/wifi_db.c) \ + $(filter-out $(ONE_WIFI_HOME)/source/core/services/vap_svc_mesh_pod.c,$(wildcard $(ONE_WIFI_HOME)/source/core/services/*.c)) \ + $(wildcard $(ONE_WIFI_HOME)/source/apps/*.c) \ + $(wildcard $(ONE_WIFI_HOME)/source/apps/linkquality/*.c) \ + $(wildcard $(ONE_WIFI_HOME)/source/stubs/*.c) \ + $(wildcard $(ONE_WIFI_HOME)/source/stats/*.c) \ + $(ONE_WIFI_HOME)/lib/common/util.c \ + $(ONE_WIFI_HOME)/source/core/wifi_8021x.c \ + $(ONE_WIFI_HOME)/source/core/wifi_ctrl_wifiapi_handlers.c \ + $(ONE_WIFI_HOME)/source/core/wifi_ctrl.c \ + $(ONE_WIFI_HOME)/source/core/wifi_ctrl_rbus_handlers.c \ + $(ONE_WIFI_HOME)/source/core/wifi_ctrl_queue_handlers.c \ + $(ONE_WIFI_HOME)/source/core/wifi_ctrl_webconfig.c \ + $(ONE_WIFI_HOME)/source/core/wifi_multidoc_webconfig.c \ + $(ONE_WIFI_HOME)/source/core/wifi_mgr.c \ + $(ONE_WIFI_HOME)/source/core/wifi_events.c \ + $(ONE_WIFI_HOME)/source/ccsp/ccsp.c \ + $(ONE_WIFI_HOME)/source/utils/collection.c \ + $(ONE_WIFI_HOME)/source/utils/scheduler.c \ + $(ONE_WIFI_HOME)/source/utils/mtrx/src/mtrx.c \ + $(ONE_WIFI_HOME)/source/dml/linux/wifi_dml.c \ + $(ONE_WIFI_HOME)/source/platform/linux/misc.c \ + $(ONE_WIFI_HOME)/source/platform/linux/bus.c \ + $(ONE_WIFI_HOME)/source/platform/common/common.c \ + +WEBCONFIG_SOURCES = $(ONE_WIFI_HOME)/source/webconfig/wifi_decoder.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_encoder.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_associated_client.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_dml.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_home.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_lnf.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_macfilter.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_mesh_backhaul.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_mesh_backhaul_sta.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_mesh.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_mesh_sta.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_null.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_private.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_radio.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_stats_config.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_steering_clients.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_steering_config.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_vif_neighbors.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_wifiapi_radio.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_wifiapi_vap.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_wifi_config.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_xfinity.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_radio_stats.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_neighbor_stats.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_assocdevice_stats.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_radio_temperature.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_radiodiag_stats.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_multivap.c \ + $(ONE_WIFI_HOME)/source/utils/wifi_util.c \ + +MATH_UTIL_SOURCES = $(wildcard $(ONE_WIFI_HOME)/source/utils/math_utils/src/*.cpp) \ + +QUALITY_MANAGER_SOURCES = $(wildcard $(ONE_WIFI_HOME)/source/utils/quality_mgr/src/*.cpp) \ + +HEBUS_SOURCES = $(wildcard $(ONE_WIFI_HOME)/source/platform/linux/he_bus/src/*.c) \ + +INCLUDE_HE_LIB_DIRS = \ + -I$(ONE_WIFI_HOME)/source/platform/linux/he_bus/inc \ + +ifdef EASY_MESH_NODE + INCLUDEDIRS += -I$(ONE_WIFI_EM_HOME)/inc + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_easymesh_translator.c +endif + +ifdef ONEWIFI_CSI_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/csi/*.c) \ + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_csi.c +endif + + +ifdef ONEWIFI_CAC_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/cac/*.c) \ + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_cac.c +endif + + +ifdef ONEWIFI_MOTION_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/motion/*.c) +endif + +ifdef ONEWIFI_HARVESTER_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/harvester/*.c) \ + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_harvester.c +endif + +ifdef ONEWIFI_LEVL_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/levl/*.c) \ + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_levl.c +endif + +ifdef ONEWIFI_WHIX_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/whix/*.c) +endif + +ifdef ONEWIFI_BLASTER_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/blaster/*.c) \ + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_blaster.c +endif + +ifdef ONEWIFI_EASYCONNECT_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/easyconnect/*.c) +endif + +ifdef ONEWIFI_STA_MGR_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/sta_mgr/*.c) +endif + +ifdef ONEWIFI_MEMWRAPTOOL_APP_SUPPORT + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/memwraptool/*.c) \ + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_memwraptool.c +endif + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_ignite.c + +ifdef EM_APP + #INCLUDEDIRS += -I$(ONE_WIFI_HOME)/source/apps/em + CSOURCES += $(wildcard $(ONE_WIFI_HOME)/source/apps/em/*.c) + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_easymesh_config.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_beacon_report.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_em_channel_stats.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_em_sta_link_metrics.c \ + $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_em_ap_metrics_report.c +endif + WEBCONFIG_SOURCES += $(ONE_WIFI_HOME)/source/webconfig/wifi_webconfig_link_report.c + +COBJECTS = $(CSOURCES:.c=.o) # expands to list of object files + +WEBCONFIG_OBJECTS = $(WEBCONFIG_SOURCES:.c=.o) # expands to list of object files +ALL_WEBCFG_LIB_OBJECTS = $(WEBCONFIG_OBJECTS) + +MATH_UTIL_OBJECTS = $(MATH_UTIL_SOURCES:.cpp=.o) # expands to list of object files +ALL_MATH_UTIL_LIB_OBJECTS = $(MATH_UTIL_OBJECTS) + +QUALITY_MANAGER_OBJECTS = $(QUALITY_MANAGER_SOURCES:.cpp=.o) # expands to list of object files +ALL_QUALITY_MANAGER_LIB_OBJECTS = $(QUALITY_MANAGER_OBJECTS) + +HEBUS_OBJECTS = $(HEBUS_SOURCES:.c=.o) # expands to list of object files +ALL_HEBUS_LIB_OBJECTS = $(HEBUS_OBJECTS) + +ALLOBJECTS = $(CXXOBJECTS) $(COBJECTS) $(WEBCONFIG_OBJECTS) $(MATH_UTIL_OBJECTS) $(QUALITY_MANAGER_OBJECTS) $(HEBUS_OBJECTS) + +CFLAGS = $(INCLUDEDIRS) $(INCLUDE_HE_LIB_DIRS) -g -fPIC -D_ANSC_LINUX -D_COSA_INTEL_USG_ATOM_ -DUSE_NOTIFY_COMPONENT -DCISCO_XB3_PLATFORM_CHANGES -DDUAL_CORE_XB3 -DFEATURE_ONE_WIFI -DWIFI_HAL_VERSION_3 -DFEATURE_SUPPORT_PASSPOINT -DFEATURE_SUPPORT_WEBCONFIG -DRASPBERRY_PI_PORT -DNL80211_ACL -D_PLATFORM_RASPBERRYPI_ -DEASY_MESH_NODE -DEM_APP \ + -DONEWIFI_STA_MGR_APP_SUPPORT + +ifneq ($(OS), Darwin) +CFLAGS += -DPLATFORM_LINUX +else +CFLAGS += -DPLATFORM_OSX +endif + +LDFLAGS = $(LIBDIRS) $(LIBS) + +$(BUILD_DIR): + @mkdir -p $(INSTALLDIR)/lib + @mkdir -p $(INSTALLDIR)/bin +# +# Default target: the first target is the default target. +# Just type "make -f Makefile.Linux" to build it. +# + + +all: $(BUILD_DIR) $(CMN_LIBRARY) $(HAL_LIBRARY) $(WEBCONFIG_LIBRARY) $(HE_BUS_LIBRARY) $(PROGRAM) test + +$(CMN_LIBRARY): $(ALL_CMN_LIB_OBJECTS) + $(AR) $@ $^ + +$(HAL_LIBRARY): $(ALL_HAL_LIB_OBJECTS) + $(AR) $@ $^ + +$(WEBCONFIG_LIBRARY): $(ALL_WEBCFG_LIB_OBJECTS) + $(AR) $@ $^ + +$(HE_BUS_LIBRARY): $(ALL_HEBUS_LIB_OBJECTS) + $(AR) $@ $^ +# +# Link target: automatically builds its object dependencies before +# executing its link command. +# + +$(PROGRAM): $(ALLOBJECTS) + $(CXX) -o $@ $(ALLOBJECTS) $(LDFLAGS) + +# +# Object targets: rules that define objects, their dependencies, and +# a list of commands for compilation. +# + +%.o: %.c + $(CC) $(CMN_LIB_FLAGS) $(CFLAGS) $(HAL_LIB_FLAGS) $(HOSTAP_LIB_FLAGS) -o $@ -c $< + +%.o: %.cpp + $(CXX) $(CFLAGS) -o $@ -c $< + +# +# Clean target: "make -f Makefile.Linux clean" to remove unwanted objects and executables. +# + +clean: + $(RM) $(ALLOBJECTS) $(ALL_CMN_LIB_OBJECTS) $(ALL_HAL_LIB_OBJECTS) $(CMN_LIBRARY) $(HE_BUS_LIBRARY) $(WEBCONFIG_LIBRARY) $(HAL_LIBRARY) $(HOSTAP_LIBRARY) $(PROGRAM) $(GTEST_BINARY) + +# +# Run target: "make -f Makefile.Linux run" to execute the application +# You will need to add $(VARIABLE_NAME) for any command line parameters +# that you defined earlier in this file. +# + +run: + ./$(PROGRAM) + +setup: + ./build/linux/rpi/setup.sh + +stamgrsetup: + ./build/linux/stamgr_setup.sh + +vapsetup: + cp ./build/linux/MultiVap_InterfaceMap.json /nvram/InterfaceMap.json + cp ./build/linux/EasymeshCfg.json /nvram/EasymeshCfg.json + ./build/linux/create_virtual_intf.sh wlan1 4 + +# gtest build process: we keep the build otherwise identical to the rpi build with the following changes +# - additional source files covering the gtest main, tests, and platform mocks +# - replace wifi_mgr.o with wifi_mgr_nomain.o -- identical except that the main function is stripped out +GTEST_SOURCES = $(ONE_WIFI_HOME)/source/test/gtest_main.cpp \ + $(ONE_WIFI_HOME)/source/test/wifi_ctrl_webconfig_test.cpp + +PLATFORM_MOCK_SOURCES = $(ONE_WIFI_HOME)/source/test/platform_mocks.c + +GTEST_OBJECTS = $(GTEST_SOURCES:.cpp=.o) +GTEST_ALLOBJECTS = $(patsubst %wifi_mgr.o,%wifi_mgr_nomain.o, $(ALLOBJECTS)) +PLATFORM_MOCK_OBJECTS = $(PLATFORM_MOCK_SOURCES:.c=.o) +GTEST_BINARY = OneWifi_gtest.bin + +$(GTEST_BINARY): $(GTEST_ALLOBJECTS) $(PLATFORM_MOCK_OBJECTS) $(GTEST_OBJECTS) $(CMN_LIBRARY) $(HAL_LIBRARY) $(WEBCONFIG_LIBRARY) $(HE_BUS_LIBRARY) + $(CXX) -o $@ $(GTEST_ALLOBJECTS) $(GTEST_OBJECTS) $(PLATFORM_MOCK_OBJECTS) $(LDFLAGS) --coverage -lgtest -lgmock + +%wifi_mgr_nomain.o: %wifi_mgr.o + objcopy --strip-symbol=main $^ $@ + +test: OneWifi_gtest.bin + ./OneWifi_gtest.bin diff --git a/config/Data_Elements_JSON_Schema_v3.0.json b/config/Data_Elements_JSON_Schema_v3.0.json index 05a8717c3..d52ff7e9f 100644 --- a/config/Data_Elements_JSON_Schema_v3.0.json +++ b/config/Data_Elements_JSON_Schema_v3.0.json @@ -3068,6 +3068,12 @@ "type": "integer", "minimum": -127, "maximum": 127 + }, + "X_AIRTIES_OperatingStandards": { + "type": "string", + "description": "List of 802.11 standards in operation for this radio instance", + "enum": ["a", "b", "g", "n", "ac", "ax", "be", "bn"] + } } } } diff --git a/include/wifi_base.h b/include/wifi_base.h index 47a0e7c0e..7c4945bca 100644 --- a/include/wifi_base.h +++ b/include/wifi_base.h @@ -392,6 +392,22 @@ typedef struct { unsigned int app_info; //This is respective specific variable. Can be used by app for internal event identification } __attribute__((packed)) wifi_mon_stats_args_t; +typedef struct { + wifi_neighbor_ap2_t base; + uint8_t opClass; + int score; +} neighbor_with_opclass_t; + +typedef struct { + neighbor_with_opclass_t neighbors[16]; + int ap_index; + uint32_t num_neighbors; + mac_address_t sta_mac; + uint8_t dialog_token; + uint8_t query_reason; + uint8_t request_mode; + bool neighbor_list_present; +} em_btm_req_ctrl_msg_t; typedef struct { wifi_mon_stats_type_t data_type; @@ -923,6 +939,9 @@ typedef struct { int noise_floor; int channel_util; int vlan_id; + eapol_msg_type_t eapol_msg_type; /* M1 / M2 / M3 */ + eapol_frame_type_t eapol_frame_type; /* Assoc / Reassoc */ + unsigned int eapol_status_type_counts[6]; int access_accept_counts; int eap_success_counts; int eap_failure_reason_counts; diff --git a/include/wifi_events.h b/include/wifi_events.h index 0867a38a3..fd4f38976 100644 --- a/include/wifi_events.h +++ b/include/wifi_events.h @@ -116,6 +116,7 @@ typedef enum { wifi_event_br_report, wifi_event_hal_csa_beacon_frame, wifi_event_hal_wps_results, + wifi_event_hal_wnm_action_frame, wifi_event_hal_max, // Commands @@ -179,6 +180,7 @@ typedef enum { wifi_event_type_xfi_tel_enable_rfc, wifi_event_type_sm_app_enable, wifi_event_type_link_quality_rfc, + wifi_event_type_send_btm_req, wifi_event_command_max, wifi_event_monitor_diagnostics = wifi_event_type_base @@ -216,6 +218,7 @@ typedef enum { wifi_event_monitor_update_interop_interval, wifi_event_monitor_channel_status, wifi_event_monitor_eap_status, + wifi_event_monitor_reassoc_req, wifi_event_monitor_max, // Tunnel diff --git a/scripts/OneWiFi_Selfheal.sh b/scripts/OneWiFi_Selfheal.sh index 540023fe5..8cadb219a 100644 --- a/scripts/OneWiFi_Selfheal.sh +++ b/scripts/OneWiFi_Selfheal.sh @@ -94,7 +94,7 @@ print_wifi_2g_txprobe_cnt() sync_all_wifi_2g_txprobe_cnt() { - pre_rxprobe_req_2g_cnt=`wl -i wl0.1 counters | grep -m 1 "rxprobereq " | cut -d ":" -f2-7 | awk '{print $6}'` + pre_rxprobe_req_2g_cnt=`wl -i wl0.1 counters | grep -o "rxprobereq [0-9]*" | awk '{print $2}'` cur_rxprobe_req_2g_cnt=$pre_rxprobe_req_2g_cnt pre_txprobe_resp_2g_cnt=`wl -i wl0.1 counters | grep -m 1 "txprobersp " | cut -d ":" -f2-7 | awk '{print $8}'` @@ -107,7 +107,7 @@ check_wifi_2g_stuck_status() sync_all_wifi_2g_txprobe_cnt print_wifi_2g_txprobe_cnt else - cur_rxprobe_req_2g_cnt=`wl -i wl0.1 counters | grep -m 1 "rxprobereq " | cut -d ":" -f2-7 | awk '{print $6}'` + cur_rxprobe_req_2g_cnt=`wl -i wl0.1 counters | grep -o "rxprobereq [0-9]*" | awk '{print $2}'` if [ $cur_rxprobe_req_2g_cnt -gt $pre_rxprobe_req_2g_cnt ]; then cur_txprobe_resp_2g_cnt=`wl -i wl0.1 counters | grep -m 1 "txprobersp " | cut -d ":" -f2-7 | awk '{print $8}'` if [ $cur_txprobe_resp_2g_cnt -eq $pre_txprobe_resp_2g_cnt ]; then @@ -134,7 +134,7 @@ print_wifi_5g_txprobe_cnt() sync_all_wifi_5g_txprobe_cnt() { - pre_rxprobe_req_5g_cnt=`wl -i wl1.1 counters | grep -m 1 "rxprobereq " | cut -d ":" -f2-7 | awk '{print $6}'` + pre_rxprobe_req_5g_cnt=`wl -i wl1.1 counters | grep -o "rxprobereq [0-9]*" | awk '{print $2}'` cur_rxprobe_req_5g_cnt=$pre_rxprobe_req_5g_cnt pre_txprobe_resp_5g_cnt=`wl -i wl1.1 counters | grep -m 1 "txprobersp " | cut -d ":" -f2-7 | awk '{print $8}'` @@ -147,7 +147,7 @@ check_wifi_5g_stuck_status() sync_all_wifi_5g_txprobe_cnt print_wifi_5g_txprobe_cnt else - cur_rxprobe_req_5g_cnt=`wl -i wl1.1 counters | grep -m 1 "rxprobereq " | cut -d ":" -f2-7 | awk '{print $6}'` + cur_rxprobe_req_5g_cnt=`wl -i wl1.1 counters | grep -o "rxprobereq [0-9]*" | awk '{print $2}'` if [ $cur_rxprobe_req_5g_cnt -gt $pre_rxprobe_req_5g_cnt ]; then cur_txprobe_resp_5g_cnt=`wl -i wl1.1 counters | grep -m 1 "txprobersp " | cut -d ":" -f2-7 | awk '{print $8}'` if [ $cur_txprobe_resp_5g_cnt -eq $pre_txprobe_resp_5g_cnt ]; then diff --git a/source/apps/csi/wifi_csi.c b/source/apps/csi/wifi_csi.c index 4a40e0eb5..3822ce53f 100644 --- a/source/apps/csi/wifi_csi.c +++ b/source/apps/csi/wifi_csi.c @@ -230,9 +230,23 @@ int csi_stop_fn(void* csi_app, unsigned int ap_index, mac_addr_t mac_addr, int s csi_mac_data_t *mac_data = (csi_mac_data_t *)hash_map_get(app->data.u.csi.csi_sounding_mac_map, mac_str); if (mac_data == NULL) { - wifi_util_info_print(WIFI_APPS, "%s:%d Rogue Disable Request from app %d\n", __func__, __LINE__, sounding_app); - return 0; + // We hash in MLO case by link address, so we need to + // map this for MLO clients, since apps use MLD MAC + mac_data = (csi_mac_data_t *)hash_map_get_first(app->data.u.csi.csi_sounding_mac_map); + while(mac_data != NULL) { + if (memcmp(mac_data->mac_addr, mac_addr, sizeof(mac_addr_t)) == 0) { + to_mac_str((unsigned char *)mac_data->link_addr, mac_str); + break; + } + mac_data = hash_map_get_next(app->data.u.csi.csi_sounding_mac_map, mac_data); + } + + if (mac_data == NULL) { + wifi_util_info_print(WIFI_APPS, "%s:%d Rogue Disable Request from app %d\n", __func__, __LINE__, sounding_app); + return 0; + } } + //Check if the mac is currently sounding by more apps. if (mac_data->subscribed_apps & ~sounding_app) { wifi_util_info_print(WIFI_APPS, "%s:%d MAC is being sounded by more than one apps not disabling sounding\n", __func__, __LINE__); diff --git a/source/apps/em/wifi_em.c b/source/apps/em/wifi_em.c index 5320aad9f..b88447c9c 100644 --- a/source/apps/em/wifi_em.c +++ b/source/apps/em/wifi_em.c @@ -37,6 +37,8 @@ #define EM_SCAN_TYPE_ACTIVE 1 static bool is_monitor_done = false; +static bool g_btm_pending_valid = false; +static em_btm_req_ctrl_msg_t g_pending_btm; typedef struct { em_policy_req_type_t policy_type; @@ -907,6 +909,93 @@ static int em_stop_neighbor_scan(wifi_provider_response_t *provider_response) } } +static inline bool ssid_in_local_list(const char *ssid, + char ssid_list[][MAX_SSID_LEN], + int ssid_count) +{ + if (!ssid || ssid[0] == '\0') { + return false; + } + + for (int i = 0; i < ssid_count; i++) { + if (strcmp(ssid, ssid_list[i]) == 0) { + return true; + } + } + return false; +} + +static int get_vap_ssid_list(char ssid_list[MAX_LOCAL_SSIDS][MAX_SSID_LEN]) +{ + unsigned int num_of_radios = getNumberRadios(); + wifi_vap_info_map_t *vap_map; + int count = 0; + + for (unsigned int r = 0; r < num_of_radios && count < MAX_LOCAL_SSIDS; r++) { + vap_map = (wifi_vap_info_map_t *)get_wifidb_vap_map(r); + if (!vap_map) { + continue; + } + + for (unsigned int v = 0; + v < vap_map->num_vaps && count < MAX_LOCAL_SSIDS; + v++) { + + const char *ssid = get_vap_ssid(&vap_map->vap_array[v]); + if (!ssid || ssid[0] == '\0') { + continue; + } + + // Avoid duplicates + if (!ssid_in_local_list(ssid, ssid_list, count)) { + snprintf(ssid_list[count++], MAX_SSID_LEN, "%s", ssid); + wifi_util_dbg_print(WIFI_EM, "%s:%d Cached local SSID: %s\n", __func__, __LINE__, ssid); + } + } + } + + return count; +} + +static int calculate_preference(const wifi_neighbor_ap2_t *src) +{ + int pref_score = 0; + + // Reject very weak APs + if (src->ap_SignalStrength < -80) + return 0; + + // RSSI + pref_score += (src->ap_SignalStrength + 100); + + // Prefer 5GHz only if signal is decent + if (src->ap_freq >= 5000 && src->ap_SignalStrength > -70) + pref_score += 20; + + // Channel utilization + pref_score -= (src->ap_ChannelUtilization / 2); + + // Noise handling + if (src->ap_Noise < 0) + pref_score -= (src->ap_Noise + 100) / 5; + + // Clamp + if (pref_score > 255) pref_score = 255; + if (pref_score < 0) pref_score = 0; + + return pref_score; +} + +static int compare_pref(const void *a, const void *b) +{ + const neighbor_with_opclass_t *e1 = a; + const neighbor_with_opclass_t *e2 = b; + + if (e2->score > e1->score) return 1; + if (e2->score < e1->score) return -1; + return 0; +} + static int em_process_neighbour_data(wifi_provider_response_t *provider_response) { channel_scan_response_t scan_response; @@ -923,9 +1012,80 @@ static int em_process_neighbour_data(wifi_provider_response_t *provider_response if (em_prepare_scan_response_data(provider_response, &scan_response) != RETURN_OK) { wifi_util_error_print(WIFI_EM, "%s:%d Prepare neighbour scan response failed\r\n", __func__, __LINE__); + + // If BTM is pending, send empty BTM request + if (g_btm_pending_valid) { + em_btm_req_ctrl_msg_t *btm = &g_pending_btm; + btm->num_neighbors = 0; + btm->neighbor_list_present = false; + + push_event_to_ctrl_queue(btm, sizeof(em_btm_req_ctrl_msg_t), wifi_event_type_command, wifi_event_type_send_btm_req, NULL); + + wifi_util_info_print(WIFI_EM, "%s:%d BTM Request sent with empty neighbor list (scan failed)\n",__func__, __LINE__); + + g_btm_pending_valid = false; + return RETURN_OK; + } return RETURN_ERR; } + if (g_btm_pending_valid) { + em_btm_req_ctrl_msg_t *btm = &g_pending_btm; + char local_ssids[MAX_LOCAL_SSIDS][MAX_SSID_LEN]; + int local_ssid_count = get_vap_ssid_list(local_ssids); + + // Populate neighbors[] + for (uint32_t i = 0; i < scan_response.num_results && btm->num_neighbors < EM_MAX_NEIGHBORS; i++) { + channel_scan_result_t *res = &scan_response.results[i]; + + for (UINT n_idx = 0; n_idx < res->num_neighbors && btm->num_neighbors < EM_MAX_NEIGHBORS; n_idx++) { + neighbor_bss_t *bss = &res->neighbors[n_idx]; + + if (!ssid_in_local_list(bss->ssid, local_ssids, local_ssid_count)) { + continue; + } + + neighbor_with_opclass_t n_local; + memset(&n_local, 0, sizeof(n_local)); + + wifi_neighbor_ap2_t *n = &n_local.base; + to_mac_str(bss->bssid, n->ap_BSSID); + snprintf(n->ap_SSID, sizeof(n->ap_SSID), "%s", bss->ssid); + n->ap_Channel = res->channel; + n->ap_Noise = res->noise; + n->ap_SignalStrength = bss->signal_strength; + n->ap_ChannelUtilization = res->utilization; + n_local.opClass = res->operating_class; + snprintf(n->ap_OperatingChannelBandwidth, sizeof(n->ap_OperatingChannelBandwidth), "%s", bss->channel_bandwidth); + n_local.score = calculate_preference(&n_local.base); + btm->neighbors[btm->num_neighbors] = n_local; + btm->num_neighbors++; + } + } + + btm->neighbor_list_present = (btm->num_neighbors > 0); + + if (btm->num_neighbors > 0) { + g_pending_btm.request_mode = 0x01; + } + + if (btm->num_neighbors > 0) { + qsort(btm->neighbors, btm->num_neighbors, sizeof(neighbor_with_opclass_t), compare_pref); + } + + // Push only the BTM request event + push_event_to_ctrl_queue(btm, sizeof(em_btm_req_ctrl_msg_t), wifi_event_type_command, wifi_event_type_send_btm_req, NULL); + + wifi_util_info_print(WIFI_EM, "%s:%d BTM Request sent with %u neighbors\n", __func__, __LINE__, btm->num_neighbors); + + // Clear BTM pending state + g_btm_pending_valid = false; + + // Stop scan explicitly if needed + em_stop_neighbor_scan(provider_response); + return RETURN_OK; + } + if (em_publish_stats_data(&scan_response) != RETURN_OK) { wifi_util_error_print(WIFI_EM, "%s:%d Publishing neighbour stats data failed\r\n", __func__, __LINE__); @@ -2236,6 +2396,210 @@ static void em_config_channel_scan(void *data, unsigned int len) } } } + +static int em_start_btm_neighbor_scan(frame_data_t *mgmt) +{ + mac_addr_str_t mac_str; + unsigned int radio_index; + channel_scan_request_t scan_req; + wifi_vap_info_t *vap_info = NULL; + + memset(&scan_req, 0, sizeof(scan_req)); + + vap_info = getVapInfo(mgmt->frame.ap_index); + if (vap_info == NULL) { + wifi_util_dbg_print(WIFI_EM, "%s:%d Failed to get VAP info for ap_index %d; clearing pending BTM state\n", + __func__, __LINE__, mgmt->frame.ap_index); + g_btm_pending_valid = false; + memset(&g_pending_btm, 0, sizeof(g_pending_btm)); + return RETURN_ERR; + } + radio_index = vap_info->radio_index; + + // num_operating_classes = 0 → FULL scan + scan_req.num_operating_classes = 0; + + return em_process_scan_init_command(radio_index, &scan_req); +} + +static void em_parse_btm_query_neighbor_ies(uint8_t *ies, uint32_t ies_len, em_btm_req_ctrl_msg_t *btm) +{ + while (ies_len >= 2 && btm->num_neighbors < EM_MAX_NEIGHBORS) { + uint8_t ie_id = ies[0]; + uint8_t ie_len = ies[1]; + + if (2 + ie_len > ies_len) { + break; + } + + if (ie_id == IEEE80211_EID_NEIGHBOR && ie_len >= IEEE80211_NEIGHBOR_REPORT_MIN_LEN) { + uint8_t *ie_data = &ies[2]; + + neighbor_with_opclass_t n_local; + neighbor_with_opclass_t *n_ext = &n_local; + wifi_neighbor_ap2_t *n = &n_ext->base; + + memset(&n_local, 0, sizeof(n_local)); + + + to_mac_str(ie_data, n->ap_BSSID); + n_ext->opClass = ie_data[10]; + n->ap_Channel = ie_data[11]; + + // SSID is optional in Neighbor IE, leave empty + n->ap_SSID[0] = '\0'; + + btm->neighbors[btm->num_neighbors] = n_local; + btm->num_neighbors++; + } + + ies += 2 + ie_len; + ies_len -= 2 + ie_len; + } + + btm->neighbor_list_present = (btm->num_neighbors > 0); +} + +static int em_handle_btm_query_frame(wifi_app_t *app, void *data) +{ + uint8_t *frame; + uint8_t *ies; + uint32_t len, ies_len; + uint8_t category, action; + uint8_t dialog_token, query_reason; + bool neighbor_list_present = false; + + frame_data_t *mgmt = (frame_data_t *)data; + if (!mgmt || mgmt->frame.len < IEEE80211_HDRLEN + 4) { + wifi_util_error_print(WIFI_EM, "%s:%d Invalid mgmt frame: mgmt=%p len=%zu, required_min=%d\n", + __func__, __LINE__, mgmt, mgmt ? mgmt->frame.len : 0, IEEE80211_HDRLEN + 4); + return RETURN_ERR; + } + + frame = mgmt->data; + len = mgmt->frame.len; + + // BTM Query fixed fields: + // [Category] (1) + // [Action = 6] (1) + // [Dialog Token] (1) + // [Query Reason] (1) + + // Parse fixed BTM Query fields + category = frame[IEEE80211_HDRLEN]; + action = frame[IEEE80211_HDRLEN + 1]; + dialog_token = frame[IEEE80211_HDRLEN + 2]; + query_reason = frame[IEEE80211_HDRLEN + 3]; + + if (category != WNM_CATEGORY || action != WNM_EM_WNM_BTM_QUERY) { + wifi_util_error_print(WIFI_EM, "%s:%d unsupported Category or action received for BTM query," + "category: %d, action: %d\n", __func__, __LINE__, category, action); + return RETURN_ERR; + } + + // Parse optional IEs + ies = &frame[IEEE80211_HDRLEN + 4]; + ies_len = len - (IEEE80211_HDRLEN + 4); + + uint8_t *ies_start = ies; + uint32_t ies_start_len = ies_len; + + while (ies_len >= 2) { + uint8_t ie_id = ies[0]; + uint8_t ie_len = ies[1]; + + if (2 + ie_len > ies_len) { + break; + } + + if (ie_id == IEEE80211_EID_NEIGHBOR) { + neighbor_list_present = true; + break; + } + + ies += 2 + ie_len; + ies_len -= 2 + ie_len; + } + + em_btm_req_ctrl_msg_t btm_req; + memset(&btm_req, 0, sizeof(btm_req)); + btm_req.ap_index = mgmt->frame.ap_index; + memcpy(btm_req.sta_mac, mgmt->frame.sta_mac, sizeof(mac_address_t)); + btm_req.dialog_token = dialog_token; + btm_req.query_reason = query_reason; + btm_req.request_mode = 0; + + // Neighbor list present in BTM Query + if (neighbor_list_present) { + em_parse_btm_query_neighbor_ies(ies_start, ies_start_len, &btm_req); + if (btm_req.num_neighbors > 0) { + btm_req.request_mode = 0x01; + } + + push_event_to_ctrl_queue(&btm_req, sizeof(em_btm_req_ctrl_msg_t), wifi_event_type_command, wifi_event_type_send_btm_req, NULL); + + wifi_util_info_print(WIFI_EM, "%s:%d BTM Query with STA suggested neighbor list (%u neighbors)\n", + __func__, __LINE__, btm_req.num_neighbors); + + return RETURN_OK; + } + + // No neighbor list in query, trigger scan. Reject concurrent scan-based requests so the single + // global pending state is not overwritten. + if (g_btm_pending_valid) { + wifi_util_error_print( WIFI_EM, "%s:%d BTM Query already pending; rejecting concurrent request\n", __func__, __LINE__); + return RETURN_ERR; + } + + // Save pending request globally for scan completion + memset(&g_pending_btm, 0, sizeof(g_pending_btm)); + memcpy(&g_pending_btm, &btm_req, sizeof(g_pending_btm)); + g_btm_pending_valid = true; + + if (em_start_btm_neighbor_scan(mgmt) != RETURN_OK) { + wifi_util_error_print(WIFI_EM, "%s:%d Failed to start neighbor scan\n", __func__, __LINE__); + g_btm_pending_valid = false; + memset(&g_pending_btm, 0, sizeof(g_pending_btm)); + return RETURN_ERR; + } + + return RETURN_OK; + +} + +static int em_handle_wnm_action_frame(wifi_app_t *app, void *data) { + uint8_t *frame; + uint8_t category, action; + + frame_data_t *mgmt = (frame_data_t *)data; + + if (!mgmt || mgmt->frame.len < IEEE80211_HDRLEN + 2) { + return RETURN_ERR; + } + + frame = mgmt->data; + + // Minimum length: 24 (802.11 hdr) + 1 (category) + 1 (action) + 1 (dialog token) + 1 (query reason) + category = frame[IEEE80211_HDRLEN]; + action = frame[IEEE80211_HDRLEN + 1]; + + // Return if category is not WNM + if (category != WNM_CATEGORY) { + return RETURN_OK; + } + + switch (action) { + case WNM_EM_WNM_BTM_QUERY: + return em_handle_btm_query_frame(app, data); + + default: + wifi_util_dbg_print(WIFI_EM,"%s:%d Unsupported WNM action=%u\n",__func__, __LINE__, action); + break; + } + + return RETURN_OK; +} + static void em_toggle_disconn_steady_state(void *data, unsigned int len) { @@ -2433,6 +2797,10 @@ int handle_em_hal_event(wifi_app_t *app, wifi_event_subtype_t sub_type, void *da em_handle_sta_conn_status(app, data); break; + case wifi_event_hal_wnm_action_frame: + em_handle_wnm_action_frame(app, data); + break; + default: wifi_util_dbg_print(WIFI_EM, "%s:%d app sub_event:%s not handled\r\n", __func__, __LINE__, wifi_event_subtype_to_string(sub_type)); diff --git a/source/apps/em/wifi_em.h b/source/apps/em/wifi_em.h index 1598b8510..c1d68dd70 100644 --- a/source/apps/em/wifi_em.h +++ b/source/apps/em/wifi_em.h @@ -34,6 +34,17 @@ extern "C" { #define WIFI_SET_DISCONN_SCAN_NONE_STATE "Device.WiFi.EM.SetDisconnScanNoneState" #define WIFI_EM_CLIENT_ASSOC_CTRL_REQ "Device.WiFi.EM.ClientAssocCtrlRequest" +#define WNM_CATEGORY 10 +#define IEEE80211_HDRLEN 24 +#define IEEE80211_EID_NEIGHBOR 52 +#define IEEE80211_NEIGHBOR_REPORT_MIN_LEN 13 + +#define WNM_EM_WNM_BTM_QUERY 6 +#define WNM_EM_WNM_BTM_REQ 7 + +#define MAX_LOCAL_SSIDS 16 +#define MAX_SSID_LEN 33 + typedef struct wifi_app wifi_app_t; typedef char short_string[32]; diff --git a/source/apps/linkquality/wifi_linkquality.c b/source/apps/linkquality/wifi_linkquality.c index b712996d6..462c7df72 100644 --- a/source/apps/linkquality/wifi_linkquality.c +++ b/source/apps/linkquality/wifi_linkquality.c @@ -32,10 +32,11 @@ #include "wifi_monitor.h" #include "scheduler.h" -#define MAX_STR_LEN 128 #define MAX_BUFF_LEN 1048 #define IGNITE_SCORE_LOG_INTERVAL_MS 900000 // 15 mins #define IGNITE_INITIAL_PUBLISH_ITERATIONS 5 +#define MAX_STR_LEN 128 +#define IGNITE_SCORE_THRESHOLD_BUFF 64 static char *wifi_health_log = "/rdklogs/logs/wifihealth.txt"; @@ -103,12 +104,12 @@ static int ignite_score_log_timer(void *args) } ignite_lq_state_t *ignite = &wifi_app->data.u.linkquality.ignite; - char tmp[128] = { 0 }; + char tmp[MAX_STR_LEN] = { 0 }; char buff[MAX_BUFF_LEN] = { 0 }; get_formatted_time(tmp); - snprintf(buff, sizeof(buff), "%s WIFI_IGNITE_LINKQUALITY:%f %f\n", tmp, ignite->last_score, - ignite->last_threshold); + snprintf(buff, sizeof(buff), "%s WIFI_IGNITE_LINKQUALITY:%f %f %s\n", tmp, ignite->last_score, + ignite->last_threshold, ignite->ignite_service_status); wifi_util_info_print(WIFI_APPS, "%s:%d: %s\n", __func__, __LINE__, buff); write_to_file(wifi_health_log, buff); return RETURN_OK; @@ -116,10 +117,13 @@ static int ignite_score_log_timer(void *args) void publish_station_score(const char *input_str, double score, double threshold) { - char str[MAX_STR_LEN] = { '\0' }; int current_state = -1; bus_error_t status; raw_data_t rdata; + char str[MAX_STR_LEN] = { '\0' }; + char tmp[MAX_STR_LEN] = { 0 }; + char buff[MAX_BUFF_LEN] = { 0 }; + char telemetry_val[IGNITE_SCORE_THRESHOLD_BUFF] = {0}; wifi_ctrl_t *ctrl = (wifi_ctrl_t *)get_wifictrl_obj(); wifi_app_t *wifi_app = get_app_by_inst(&ctrl->apps_mgr, wifi_app_inst_link_quality); @@ -156,9 +160,11 @@ void publish_station_score(const char *input_str, double score, double threshold if (score < threshold) { current_state = 0; snprintf(str, MAX_STR_LEN, "Non-Serviceable"); + snprintf(ignite->ignite_service_status, MAX_IGNITE_STR_LEN, "Manageable"); } else if (score >= threshold) { current_state = 1; snprintf(str, MAX_STR_LEN, "Serviceable"); + snprintf(ignite->ignite_service_status, MAX_IGNITE_STR_LEN, "Serviceable"); } if (current_state != -1 && current_state != ignite->last_service_state) { @@ -175,15 +181,28 @@ void publish_station_score(const char *input_str, double score, double threshold wifi_util_error_print(WIFI_CTRL, "%s:%d: bus: bus_event_publish_fn Event failed %d\n", __func__, __LINE__, status); } + get_formatted_time(tmp); if (ignite->last_service_state == -1) { - char tmp[128] = { 0 }; - char buff[MAX_BUFF_LEN] = { 0 }; - get_formatted_time(tmp); - snprintf(buff, sizeof(buff), "%s WIFI_IGNITE_LINKQUALITY:%f %f\n", tmp, - ignite->last_score, ignite->last_threshold); - wifi_util_info_print(WIFI_APPS, "%s:%d: Score at first RBUS publish after connection: %s\n", __func__, - __LINE__, buff); + snprintf(buff, sizeof(buff), "%s WIFI_IGNITE_LINKQUALITY_FIRST_PUBLISH:%f %f %s\n", tmp, + ignite->last_score, ignite->last_threshold, ignite->ignite_service_status); + wifi_util_info_print(WIFI_APPS, + "%s:%d: Score at first RBUS publish after connection: %s\n", __func__, __LINE__, + buff); + write_to_file(wifi_health_log, buff); + snprintf(telemetry_val, IGNITE_SCORE_THRESHOLD_BUFF, "%f %f %s", ignite->last_score, + ignite->last_threshold, ignite->ignite_service_status); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_LINKQUALITY_FIRST_PUBLISH", + telemetry_val); + } else { + snprintf(buff, sizeof(buff), "%s WIFI_IGNITE_LINKQUALITY_STATE_CHANGE:%f %f %s\n", tmp, + ignite->last_score, ignite->last_threshold, ignite->ignite_service_status); + wifi_util_info_print(WIFI_APPS, "%s:%d: State change score: %s\n", __func__, __LINE__, + buff); write_to_file(wifi_health_log, buff); + snprintf(telemetry_val, IGNITE_SCORE_THRESHOLD_BUFF, "%f %f %s", ignite->last_score, + ignite->last_threshold, ignite->ignite_service_status); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_LINKQUALITY_STATE_CHANGE", + telemetry_val); } ignite->last_service_state = current_state; } diff --git a/source/apps/linkquality/wifi_linkquality.h b/source/apps/linkquality/wifi_linkquality.h index 91d39a4d5..51e4155af 100644 --- a/source/apps/linkquality/wifi_linkquality.h +++ b/source/apps/linkquality/wifi_linkquality.h @@ -20,6 +20,8 @@ #ifndef WIFI_LINKQUALITY_H #define WIFI_LINKQUALITY_H +#define MAX_IGNITE_STR_LEN 32 + #ifdef __cplusplus extern "C" { #endif @@ -33,6 +35,7 @@ typedef struct { int score_log_timer_id; int last_service_state; int iteration_count; + char ignite_service_status[MAX_IGNITE_STR_LEN]; } ignite_lq_state_t; typedef struct { diff --git a/source/core/services/vap_svc_mesh_ext.c b/source/core/services/vap_svc_mesh_ext.c index 58ec0dc2b..8cbb36312 100644 --- a/source/core/services/vap_svc_mesh_ext.c +++ b/source/core/services/vap_svc_mesh_ext.c @@ -54,6 +54,28 @@ #define EXT_DISCONNECTION_DISCONNECT 1 #define EXT_DISCONNECTION_DISCONNECT_AND_IGNORE_RADIO 2 +#define MAX_STATUS_LEN 5 +#define MAX_STR_LEN 128 +#define MAC_ADDR_STR_LEN 18 +#define MAX_IFACE_LEN 32 +#define MAX_BUFF_LEN 256 +#define MAX_TELEMETRY_BUFF_LEN 1024 + +//safe_strcat defined locally to accomodate the contents in the existing destination and +//incoming source buffer to avoid overflow +#define safe_strcat(dst, max, src) \ + do { \ + if ((src) == NULL) { \ + wifi_util_error_print(WIFI_CTRL, "%s:%d NULL src\n", __func__, __LINE__); \ + } else if ((strlen(dst) + strlen(src) + 1) > (max)) { \ + wifi_util_error_print(WIFI_CTRL, "%s:%d overflow prevented dst_len=%zu src_len=%zu max=%zu\n", \ + __func__, __LINE__, strlen(dst), strlen(src), (size_t)(max)); \ + } else { \ + strcat(dst, src); \ + } \ + } while(0) + +static const char *wifi_health_log = "/rdklogs/logs/wifihealth.txt"; /** * @brief Temporary structure for sorting with computed scores */ @@ -720,15 +742,23 @@ int process_udhcp_ip_check(vap_svc_t *svc) } else { if ((ip_check_count < EXT_UDHCP_IP_CHECK_NUM) && (ext->conn_state == connection_state_connected)) { - char iface[32] = "brww0"; + char iface[MAX_IFACE_LEN] = "brww0"; + char tmp[MAX_STR_LEN] = { 0 }; + get_formatted_time(tmp); if (has_valid_ip(iface)) { - wifi_util_info_print(WIFI_CTRL, "IGNITE_RF_DOWN: Received Valid IP address on brww0 interface\n"); + write_to_file(wifi_health_log, "%s WIFI_IGNITE_VALID_IP_BRWW0:True\n", tmp); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_VALID_IP_BRWW0", "True"); + wifi_util_info_print(WIFI_CTRL, + "IGNITE_RF_DOWN: Received Valid IP address on brww0 interface\n"); scheduler_cancel_timer_task(ctrl->sched, ext->ext_udhcp_ip_check_id); ext->ext_udhcp_ip_check_id = 0; ip_check_count = 0; return 0; } else { - wifi_util_error_print(WIFI_CTRL, "IGNITE_RF_DOWN: Invalid IP address detected on brww0 interface\n"); + write_to_file(wifi_health_log, "\n%s WIFI_IGNITE_VALID_IP_BRWW0:False\n", tmp); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_VALID_IP_BRWW0", "False"); + wifi_util_error_print(WIFI_CTRL, + "IGNITE_RF_DOWN: Invalid IP address detected on brww0 interface\n"); } } } @@ -1139,7 +1169,9 @@ void ext_try_connecting(vap_svc_t *svc) return; } vap_index = get_sta_vap_index_for_radio(svc->prop, radio_index); - + if (ctrl->rf_status_down == true) { + hotspot_timing_target_detected(); + } wifi_util_info_print(WIFI_CTRL,"%s:%d connecting to ssid:%s bssid:%s rssi:%d frequency:%d on vap:%d radio:%d\n", __func__, __LINE__, candidate->external_ap.ssid, to_mac_str(candidate->external_ap.bssid, bssid_str), candidate->external_ap.rssi, @@ -1733,6 +1765,10 @@ int process_ext_scan_results(vap_svc_t *svc, void *arg) vap_svc_ext_t *ext; wifi_ctrl_t *ctrl; ssid_t sta_ssid; + char tmp[MAX_STR_LEN] = { 0 }; + char buff[MAX_BUFF_LEN] = { 0 }; + char target_metrics_buf[MAX_TELEMETRY_BUFF_LEN] = {0}; + char telemetry_buf[MAX_TELEMETRY_BUFF_LEN] = {0}; ctrl = svc->ctrl; ext = &svc->u.ext; @@ -1780,6 +1816,28 @@ int process_ext_scan_results(vap_svc_t *svc, void *arg) " connection state:%s\n", __FUNCTION__,__LINE__, results->radio_index, num, ext_conn_state_to_str(ext->conn_state)); + if (ctrl->rf_status_down == true) { + static char *event_names[] = { + "WIFI_IGNITE_ELIGIBLE_TARGET_2G", + "WIFI_IGNITE_ELIGIBLE_TARGET_5G", + "WIFI_IGNITE_ELIGIBLE_TARGET_6G" + }; + get_formatted_time(tmp); + if (results->radio_index < MAX_NUM_RADIOS) { + snprintf(buff, MAX_BUFF_LEN, "%s %s:%u\n", tmp, event_names[results->radio_index], num); + write_to_file(wifi_health_log,buff); + wifi_util_info_print(WIFI_CTRL, "%s:%d telemetry val : %s\n", __func__, __LINE__, buff); + get_stubs_descriptor()->t2_event_d_fn(event_names[results->radio_index], num); + } else { + wifi_util_error_print(WIFI_CTRL, "%s %d Unsupported Radio index %u\n", __func__, __LINE__, results->radio_index); + } + if (num != 0 ) { + memset(tmp, '\0', sizeof(tmp)); + get_formatted_time(tmp); + snprintf(target_metrics_buf, MAX_TELEMETRY_BUFF_LEN, "%s WIFI_IGNITE_ELIGIBLE_TARGET_METRICS:", tmp); + } + } + if ((ext->candidates_list.scan_list == NULL) && num) { ext->candidates_list.scan_list = (bss_candidate_t *) malloc(num * sizeof(bss_candidate_t)); scan_list = ext->candidates_list.scan_list; @@ -1796,23 +1854,45 @@ int process_ext_scan_results(vap_svc_t *svc, void *arg) scan_list->conn_attempt = connection_attempt_wait; scan_list->conn_retry_attempt = 0; scan_list->radio_freq_band = band; - wifi_util_dbg_print(WIFI_CTRL, "%s:%d: AP with ssid:%s, bssid:%s, rssi:%d, freq:%d\n", - __func__, __LINE__, tmp_bss->ssid, to_mac_str(tmp_bss->bssid, bssid_str), tmp_bss->rssi, tmp_bss->freq); + if (ctrl->rf_status_down == true) { + char delimiter = (i + 1) < num ? ';' : ' '; + + snprintf(buff, MAX_BUFF_LEN, "%s,%d,%d,%d,%d%c", + to_mac_str(tmp_bss->bssid, bssid_str), + tmp_bss->freq, + tmp_bss->rssi, + tmp_bss->snr, + tmp_bss->chan_utilization, + delimiter); + + safe_strcat(telemetry_buf, MAX_TELEMETRY_BUFF_LEN, buff); + } + wifi_util_info_print(WIFI_CTRL, "%s:%d: AP with ssid:%s, bssid:%s, rssi:%d, freq:%d\n", - __func__, __LINE__, scan_list->external_ap.ssid, to_mac_str(scan_list->external_ap.bssid, bssid_str), scan_list->external_ap.rssi, scan_list->external_ap.freq); + __func__, __LINE__, scan_list->external_ap.ssid, + to_mac_str(scan_list->external_ap.bssid, bssid_str), scan_list->external_ap.rssi, + scan_list->external_ap.freq); tmp_bss++; scan_list++; } + if ((ctrl->rf_status_down == true) && (num != 0)) { + safe_strcat(telemetry_buf, MAX_TELEMETRY_BUFF_LEN, "\n"); + safe_strcat(target_metrics_buf, MAX_TELEMETRY_BUFF_LEN, telemetry_buf); + write_to_file(wifi_health_log, target_metrics_buf); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_ELIGIBLE_TARGET_METRICS", telemetry_buf); + } + if (ext->candidates_list.scan_list && (ext->candidates_list.scan_count > 0)) { if (ctrl->rf_status_down == false) { - sort_bss_results_by_rssi(ext->candidates_list.scan_list, 0, ext->candidates_list.scan_count - 1); + sort_bss_results_by_rssi(ext->candidates_list.scan_list, 0, + ext->candidates_list.scan_count - 1); } else { - ext->ranked_count = sort_bss_results_by_ranking( - ext->candidates_list.scan_list, - ext->candidates_list.scan_count); + ext->ranked_count = sort_bss_results_by_ranking(ext->candidates_list.scan_list, + ext->candidates_list.scan_count); ext->candidates_list.scan_count = ext->ranked_count; - wifi_util_dbg_print(WIFI_CTRL, "%s:%d: rank-count : %d scan-count : %d\n", __func__, __LINE__, ext->ranked_count, ext->candidates_list.scan_count); + wifi_util_dbg_print(WIFI_CTRL, "%s:%d: rank-count : %d scan-count : %d\n", __func__, + __LINE__, ext->ranked_count, ext->candidates_list.scan_count); } } @@ -1923,10 +2003,6 @@ static int apply_pending_channel_change(vap_svc_t *svc, int vap_index) return RETURN_OK; } -#define MAX_STATUS_LEN 5 -#define MAX_STR_LEN 128 -#define MAC_ADDR_STR_LEN 18 - int process_ext_sta_conn_status(vap_svc_t *svc, void *arg) { wifi_mgr_t *mgr = (wifi_mgr_t *)get_wifimgr_obj(); @@ -1949,7 +2025,7 @@ int process_ext_sta_conn_status(vap_svc_t *svc, void *arg) char *bridge_name = "brww0"; char *bssid_mac_str = NULL; int ret = 0; - + char tmp[MAX_STR_LEN] = {0}; ctrl = svc->ctrl; ext = &svc->u.ext; @@ -2022,9 +2098,11 @@ int process_ext_sta_conn_status(vap_svc_t *svc, void *arg) // change the state ext_set_conn_state(ext, connection_state_connected, __func__, __LINE__); - if (ctrl->rf_status_down == true) { - char mac_str[32] = {'\0'}; + if (ctrl->rf_status_down == true) { + char mac_str[32] = { '\0' }; + char bssid_str[MAC_ADDR_STR_LEN] = {'\0'}; uint8_mac_to_string_mac(temp_vap_info->u.sta_info.mac, mac_str); + uint8_mac_to_string_mac(temp_vap_info->u.sta_info.bssid, bssid_str); wifi_util_dbg_print(WIFI_CTRL, "%s:%d Bridge:%s Using MAC-Str:%s MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", __func__, __LINE__, bridge_name, mac_str, temp_vap_info->u.sta_info.mac[0], @@ -2045,12 +2123,20 @@ int process_ext_sta_conn_status(vap_svc_t *svc, void *arg) snprintf(cmd, sizeof(cmd), "ip link set dev %s up", bridge_name); wifi_util_dbg_print(WIFI_CTRL,"%s:%d cmd : %s\n",__func__,__LINE__, cmd); get_stubs_descriptor()->v_secure_system_fn(cmd); - + hotspot_timing_connected(ext->connected_vap_index, bssid_str); rc = publish_endpoint_status(ctrl, sta_data->stats.connect_status); + memset(tmp, 0, sizeof(tmp)); + get_formatted_time(tmp); if (rc != bus_error_success) { - wifi_util_error_print(WIFI_CTRL,"IGNITE_RF_DOWN: Failed to publish connect status to WM\n"); + write_to_file(wifi_health_log, "\n%s WIFI_IGNITE_CONN_PUBLISH:False\n", tmp); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_CONN_PUBLISH", "False"); + wifi_util_error_print(WIFI_CTRL, + "IGNITE_RF_DOWN: Failed to publish connect status to WM\n"); } else { - wifi_util_info_print(WIFI_CTRL,"IGNITE_RF_DOWN: Connect status sent successfully to the WM\n"); + write_to_file(wifi_health_log, "\n%s WIFI_IGNITE_CONN_PUBLISH:True\n", tmp); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_CONN_PUBLISH", "True"); + wifi_util_info_print(WIFI_CTRL, + "IGNITE_RF_DOWN: Connect status sent successfully to the WM\n"); } bssid_mac_str = (char *)malloc(MAC_ADDR_STR_LEN); if (bssid_mac_str != NULL) { @@ -2176,12 +2262,20 @@ int process_ext_sta_conn_status(vap_svc_t *svc, void *arg) if (ctrl->rf_status_down == true) { rc = 0; - rc = publish_endpoint_status(ctrl, sta_data->stats.connect_status); - + hotspot_timing_disconnected(); + rc = publish_endpoint_status(ctrl, sta_data->stats.connect_status); + memset(tmp, 0, sizeof(tmp)); + get_formatted_time(tmp); if (rc != bus_error_success) { - wifi_util_error_print(WIFI_CTRL, "IGNITE_RF_DOWN: Failed to publish disconnect status to WM\n"); + write_to_file(wifi_health_log, "\n%s WIFI_IGNITE_DISCONN_PUBLISH:False\n", tmp); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_DISCONN_PUBLISH", "False"); + wifi_util_error_print(WIFI_CTRL, + "IGNITE_RF_DOWN: Failed to publish disconnect status to WM\n"); } else { - wifi_util_info_print(WIFI_CTRL, "IGNITE_RF_DOWN: Disconnect status sent successfully to the WM\n"); + write_to_file(wifi_health_log, "\n%s WIFI_IGNITE_DISCONN_PUBLISH:True\n", tmp); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_DISCONN_PUBLISH", "True"); + wifi_util_info_print(WIFI_CTRL, + "IGNITE_RF_DOWN: Disconnect status sent successfully to the WM\n"); } } if (ext->conn_state == connection_state_connection_to_nb_in_progress) { diff --git a/source/core/wifi_ctrl.c b/source/core/wifi_ctrl.c index 960d445d6..ee66639c3 100644 --- a/source/core/wifi_ctrl.c +++ b/source/core/wifi_ctrl.c @@ -1231,9 +1231,14 @@ int mgmt_wifi_frame_recv(int ap_index, mac_address_t sta_mac, uint8_t *frame, ui mgmt_frame.frame.len = len; evt_subtype = wifi_event_hal_reassoc_rsp_frame; } else if (type == WIFI_MGMT_FRAME_TYPE_ACTION) { + // Validate minimum ACTION frame length before proceeding + if (len < sizeof(struct ieee80211_frame) + 1) { + wifi_util_dbg_print(WIFI_CTRL,"%s:%d: Dropping short ACTION frame (len=%u)\n", __func__, __LINE__, len); + return RETURN_ERR; + } + memcpy(mgmt_frame.data, frame, len); mgmt_frame.frame.len = len; - evt_subtype = wifi_event_hal_dpp_public_action_frame; data = (wifi_monitor_data_t *)malloc(sizeof(wifi_monitor_data_t)); if (data == NULL) { @@ -1255,11 +1260,18 @@ int mgmt_wifi_frame_recv(int ap_index, mac_address_t sta_mac, uint8_t *frame, ui data->u.msg.frame.recv_freq = recv_freq; memcpy(&data->u.msg.data, frame, len); + + paction = (wifi_actionFrameHdr_t *)(frame + sizeof(struct ieee80211_frame)); + if (paction->cat == wifi_action_frame_wnm) { + evt_subtype = wifi_event_hal_wnm_action_frame; + } else { + evt_subtype = wifi_event_hal_dpp_public_action_frame; + } + push_event_to_monitor_queue(data, wifi_event_monitor_action_frame, NULL); free(data); data = NULL; - paction = (wifi_actionFrameHdr_t *)(frame + sizeof(struct ieee80211_frame)); switch (paction->cat) { case wifi_action_frame_type_public: get_action_frame_evt_params(frame, len, &mgmt_frame, &evt_subtype); diff --git a/source/core/wifi_ctrl.h b/source/core/wifi_ctrl.h index aae8ec9ea..ac3001b79 100644 --- a/source/core/wifi_ctrl.h +++ b/source/core/wifi_ctrl.h @@ -177,6 +177,15 @@ typedef struct kick_details { bool filter_mode_changed; }kick_details_t; +typedef struct { + struct timespec start_time; + struct timespec target_detection_time; + struct timespec end_time; + struct timespec disconnection_time; +} hotspot_timing_t; + +extern hotspot_timing_t g_hotspot_timing; + typedef struct { wifi_connection_status_t connect_status; bssid_t bssid; diff --git a/source/core/wifi_ctrl_queue_handlers.c b/source/core/wifi_ctrl_queue_handlers.c index 035abf553..1a8d06743 100644 --- a/source/core/wifi_ctrl_queue_handlers.c +++ b/source/core/wifi_ctrl_queue_handlers.c @@ -147,6 +147,60 @@ void process_csa_beacon_frame_event(frame_data_t *msg, uint32_t msg_length, wifi } } +void process_btm_request_send_event(void *data, uint32_t len) { + int ret; + wifi_BTMRequest_t btmReq; + + if (!data || len < sizeof(em_btm_req_ctrl_msg_t)) { + wifi_util_error_print(WIFI_CTRL, "%s:%d Invalid BTM req data\n",__func__, __LINE__); + return; + } + + em_btm_req_ctrl_msg_t *msg = (em_btm_req_ctrl_msg_t *)data; + + wifi_util_info_print(WIFI_CTRL, "%s:%d BTM req send event received\n", __func__, __LINE__); + + memset(&btmReq, 0, sizeof(btmReq)); + + // Fill HAL BTM Request + btmReq.token = msg->dialog_token; + btmReq.requestMode = msg->request_mode; + + if (msg->neighbor_list_present && msg->num_neighbors > 0) { + uint32_t neighbors_count = msg->num_neighbors; + if (neighbors_count > MAX_CANDIDATES) { + neighbors_count = MAX_CANDIDATES; + } + + btmReq.numCandidates = neighbors_count; + + for (uint32_t i = 0; i < btmReq.numCandidates; i++) { + neighbor_with_opclass_t *src_ext = &msg->neighbors[i]; + wifi_neighbor_ap2_t *src = &src_ext->base; + wifi_NeighborReport_t *dst = &btmReq.candidates[i]; + + str_to_mac_bytes(src->ap_BSSID, dst->bssid); + dst->channel = (UCHAR)src->ap_Channel; + dst->opClass = src_ext->opClass; + snprintf(dst->target_ssid, sizeof(dst->target_ssid), "%s", src->ap_SSID); + dst->bssTransitionCandidatePreferencePresent = TRUE; + dst->bssTransitionCandidatePreference.preference = (UCHAR)src_ext->score; + + wifi_util_dbg_print(WIFI_CTRL,"BTM[%d]: BSSID: %s Channel: %u opClass: %u RSSI: %d Pref: %d\n", + i, src->ap_BSSID, src->ap_Channel, src_ext->opClass, src->ap_SignalStrength, dst->bssTransitionCandidatePreference.preference); + + } + wifi_util_info_print(WIFI_CTRL,"%s:%d BTM neighbor list filled, candidates=%u\n", __func__, __LINE__, btmReq.numCandidates); + } else { + btmReq.numCandidates = 0; + } + + ret = wifi_hal_setBTMRequest(msg->ap_index, msg->sta_mac, &btmReq); + if (ret != RETURN_OK) { + wifi_util_error_print(WIFI_CTRL, "%s:%d wifi_hal_setBTMRequest failed (ret=%d)\n",__func__, __LINE__, ret); + } +} + const char* wifi_hotspot_action_to_string(wifi_hotspot_action_t action) { switch (action) { case hotspot_vap_disable: @@ -274,7 +328,19 @@ void process_assoc_rsp_frame_event(frame_data_t *msg, uint32_t msg_length) void process_reassoc_req_frame_event(frame_data_t *msg, uint32_t msg_length) { - wifi_util_dbg_print(WIFI_CTRL,"%s:%d wifi mgmt frame message: ap_index:%d length:%d type:%d dir:%d rssi:%d\r\n", __FUNCTION__, __LINE__, msg->frame.ap_index, msg->frame.len, msg->frame.type, msg->frame.dir, msg->frame.sig_dbm); + wifi_monitor_data_t *data = NULL; + data = (wifi_monitor_data_t *)malloc(sizeof(wifi_monitor_data_t)); + if (data == NULL) { + wifi_util_error_print(WIFI_CTRL,"%s:%d: Failed to allocate memory\n", __func__, __LINE__); + return; + } + memset(data, 0, sizeof(wifi_monitor_data_t)); + memcpy(&data->u.msg, msg, sizeof(frame_data_t)); + data->id = msg_id++; + push_event_to_monitor_queue(data, wifi_event_monitor_reassoc_req, NULL); + free(data); + data = NULL; + wifi_util_dbg_print(WIFI_CTRL,"%s:%d wifi mgmt frame message: ap_index:%d length:%d type:%d dir:%d rssi:%d phy_rate:%d\r\n", __FUNCTION__, __LINE__, msg->frame.ap_index, msg->frame.len, msg->frame.type, msg->frame.dir, msg->frame.sig_dbm, msg->frame.phy_rate); } void process_reassoc_rsp_frame_event(frame_data_t *msg, uint32_t msg_length) @@ -3008,8 +3074,14 @@ void process_tcm_rfc(bool type) type); wifi_rfc_dml_parameters_t *rfc_param = (wifi_rfc_dml_parameters_t *)get_ctrl_rfc_parameters(); rfc_param->tcm_enabled_rfc = type; + rfc_param->tcm_open_2g_rfc = type; + rfc_param->tcm_open_5g_rfc = type; + rfc_param->tcm_open_6g_rfc = type; + rfc_param->tcm_secure_2g_rfc = type; + rfc_param->tcm_secure_5g_rfc = type; + rfc_param->tcm_secure_6g_rfc = type; get_wifidb_obj()->desc.update_rfc_config_fn(0, rfc_param); - wifi_util_dbg_print(WIFI_DB, "Exit func %s: %d : Tcm RFC: %d\n", __FUNCTION__, __LINE__, + wifi_util_dbg_print(WIFI_DB, "Exit func %s: %d : Tcm RFC: %d, all VAP-specific RFCs updated\n", __FUNCTION__, __LINE__, type); } @@ -4350,6 +4422,9 @@ void handle_command_event(wifi_ctrl_t *ctrl, void *data, unsigned int len, case wifi_event_type_xfi_tel_enable_rfc: process_xfi_tel_enable_rfc(*(bool *)data); break; + case wifi_event_type_send_btm_req: + process_btm_request_send_event(data, len); + break; case wifi_event_type_multiap_rfc: process_multiap_rfc(*(bool *)data); break; @@ -4452,6 +4527,9 @@ void handle_hal_indication(wifi_ctrl_t *ctrl, void *data, unsigned int len, process_wps_results_event(data); break; + case wifi_event_hal_wnm_action_frame: + break; + default: wifi_util_error_print(WIFI_CTRL, "[%s]:WIFI hal handler not supported this event %s\r\n", diff --git a/source/core/wifi_ctrl_rbus_handlers.c b/source/core/wifi_ctrl_rbus_handlers.c index e5b5457de..52b15e76f 100644 --- a/source/core/wifi_ctrl_rbus_handlers.c +++ b/source/core/wifi_ctrl_rbus_handlers.c @@ -27,18 +27,25 @@ #include "wifi_monitor.h" #include "wifi_webconfig.h" #include "run_qmgr.h" +#include "wifi_stubs.h" #include #include #include #include #include + #define MAX_EVENT_NAME_SIZE 200 #define MAX_STR_LEN 128 +#define MAX_BUFF_LEN 256 +#define MAX_TELEMETRY_BUFF_LEN 64 #define MAX_STATUS_LEN 5 #define STA_STATUS_DISCONNECTED 1 +hotspot_timing_t g_hotspot_timing; apply_ignite_config_t g_apply_ignite_config; +static const char *wifi_health_log = "/rdklogs/logs/wifihealth.txt"; + static int get_subdoc_type(wifi_provider_response_t *response, webconfig_subdoc_type_t *subdoc, char *eventName) { @@ -144,6 +151,209 @@ static void mask_to_quality_flags(uint32_t mask, quality_flags_t* f) f->int_reconn = mask & LINKQ_INT_RECONN; } +static inline double hotspot_timing_elapsed_sec(const struct timespec *start, + const struct timespec *end) +{ + if (start->tv_sec == 0 || end->tv_sec == 0) { + wifi_util_error_print(WIFI_CTRL, + "HOTSPOT_TIMING: [elapsed_sec] invalid timestamp " + "Time_1=%ld Time_2=%ld\n", + (long)start->tv_sec, (long)end->tv_sec); + return 0.0; + } + + long sec = (long)(end->tv_sec - start->tv_sec); + long nsec = (long)(end->tv_nsec - start->tv_nsec); + + if (nsec < 0) { + sec -= 1; + nsec += 1000000000L; + } + + double elapsed = (double)sec + (double)nsec / 1000000000.0; + + wifi_util_dbg_print(WIFI_CTRL, + "HOTSPOT_TIMING: [elapsed_sec] " + "start=%ld.%09ld end=%ld.%09ld elapsed=%.3f sec\n", + (long)start->tv_sec, (long)start->tv_nsec, + (long)end->tv_sec, (long)end->tv_nsec, + elapsed); + + return elapsed; +} + +/* ------------------------------------------------------------------ */ +/* hotspot_timing_start() */ +/* Called : start_station_vaps() when rf_status == true */ +/* ------------------------------------------------------------------ */ +void hotspot_timing_start(void) +{ + clock_gettime(CLOCK_MONOTONIC, &g_hotspot_timing.start_time); + + memset(&g_hotspot_timing.target_detection_time, 0, sizeof(struct timespec)); + memset(&g_hotspot_timing.end_time, 0, sizeof(struct timespec)); + memset(&g_hotspot_timing.disconnection_time, 0, sizeof(struct timespec)); + + wifi_util_dbg_print(WIFI_CTRL, + "HOTSPOT_TIMING: [start] start_time = %ld sec %ld nsec\n", + (long)g_hotspot_timing.start_time.tv_sec, + (long)g_hotspot_timing.start_time.tv_nsec); +} + +/* ------------------------------------------------------------------ */ +/* hotspot_timing_stop() */ +/* Called : start_station_vaps() when rf_status == false */ +/* ------------------------------------------------------------------ */ +void hotspot_timing_stop(void) +{ + wifi_util_info_print(WIFI_CTRL, + "HOTSPOT_TIMING: [stop] RF restored – clearing all timestamps\n"); + + memset(&g_hotspot_timing, 0, sizeof(hotspot_timing_t)); +} + +/* ------------------------------------------------------------------ */ +/* hotspot_timing_target_detected() */ +/* Called : ext_try_connecting() when target candidate is found */ +/* ------------------------------------------------------------------ */ +void hotspot_timing_target_detected(void) +{ + char tmp[MAX_STR_LEN] = {0}; + double target_detection_duration = 0.00; + char buff[MAX_BUFF_LEN] = {0}; + char telemetry_buf[MAX_TELEMETRY_BUFF_LEN] = {0}; + + /* Already recorded for this attempt — skip */ + if (g_hotspot_timing.target_detection_time.tv_sec != 0) { + wifi_util_info_print(WIFI_CTRL, + "HOTSPOT_TIMING: [target_detected] already recorded " + "(%ld sec) – skip\n", + (long)g_hotspot_timing.target_detection_time.tv_sec); + return; + } + + clock_gettime(CLOCK_MONOTONIC, &g_hotspot_timing.target_detection_time); + get_formatted_time(tmp); + target_detection_duration = hotspot_timing_elapsed_sec(&g_hotspot_timing.start_time, + &g_hotspot_timing.target_detection_time); + + snprintf(buff, MAX_BUFF_LEN, "%s WIFI_IGNITE_HOTSPOT_TARGET_DETECTION_TIME:%.3f\n", tmp, target_detection_duration); + write_to_file(wifi_health_log, buff); + snprintf(telemetry_buf, MAX_TELEMETRY_BUFF_LEN, "%.3f", target_detection_duration); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_HOTSPOT_TARGET_DETECTION_TIME", telemetry_buf); + wifi_util_dbg_print(WIFI_CTRL, + "HOTSPOT_TIMING: [target_detected] target_detection_time = " + "%ld sec %ld nsec\n", + (long)g_hotspot_timing.target_detection_time.tv_sec, + (long)g_hotspot_timing.target_detection_time.tv_nsec); +} + +/* ------------------------------------------------------------------ */ +/* hotspot_timing_connected() */ +/* Called : process_ext_sta_conn_status() on connected event */ +/* Note : end_time preserved for disconnected() check */ +/* Only target_detection_time is reset here */ +/* ------------------------------------------------------------------ */ +void hotspot_timing_connected(unsigned int vap_index, char *bssid_str) +{ + char tmp[MAX_STR_LEN] = {0}; + double connection_duration = 0.00; + char buff[MAX_BUFF_LEN] = {0}; + char telemetry_buf[MAX_TELEMETRY_BUFF_LEN] = {0}; + clock_gettime(CLOCK_MONOTONIC, &g_hotspot_timing.end_time); + + wifi_util_dbg_print(WIFI_CTRL, + "HOTSPOT_TIMING: [connected] end_time = %ld sec %ld nsec\n", + (long)g_hotspot_timing.end_time.tv_sec, + (long)g_hotspot_timing.end_time.tv_nsec); + + connection_duration = hotspot_timing_elapsed_sec(&g_hotspot_timing.start_time, + &g_hotspot_timing.end_time); + + wifi_util_info_print(WIFI_CTRL, + "HOTSPOT_TIMING: [connected] Duration of RF failure = %.3f sec\n", connection_duration); + + get_formatted_time(tmp); + snprintf(buff, MAX_BUFF_LEN, "%s WIFI_IGNITE_HOTSPOT_CONN_INFO: %u %s %.3f\n", tmp, vap_index, bssid_str, connection_duration); + write_to_file(wifi_health_log, buff); + memset(telemetry_buf, 0, MAX_TELEMETRY_BUFF_LEN); + snprintf(telemetry_buf, MAX_TELEMETRY_BUFF_LEN, "%u %s %.3f", vap_index, bssid_str, connection_duration); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_HOTSPOT_CONN_INFO", telemetry_buf); + + //Reset the target detection time once the enrollee connection established to hotspot + memset(&g_hotspot_timing.target_detection_time, 0, sizeof(struct timespec)); +} + +/* ------------------------------------------------------------------ */ +/* hotspot_timing_disconnected() */ +/* Called : process_ext_sta_conn_status() on disconnected event */ +/* ------------------------------------------------------------------ */ +void hotspot_timing_disconnected(void) +{ + char tmp[MAX_STR_LEN] = { 0 }; + double session_duration = 0.00; + char buff[MAX_BUFF_LEN] = { 0 }; + char telemetry_buf[MAX_TELEMETRY_BUFF_LEN] = { 0 }; + + if (g_hotspot_timing.end_time.tv_sec != 0) { + clock_gettime(CLOCK_MONOTONIC, &g_hotspot_timing.disconnection_time); + + wifi_util_dbg_print(WIFI_CTRL, + "HOTSPOT_TIMING: [disconnected] disconnection_time = " + "%ld sec %ld nsec\n", + (long)g_hotspot_timing.disconnection_time.tv_sec, + (long)g_hotspot_timing.disconnection_time.tv_nsec); + + get_formatted_time(tmp); + session_duration = hotspot_timing_elapsed_sec(&g_hotspot_timing.end_time, + &g_hotspot_timing.disconnection_time); + wifi_util_info_print(WIFI_CTRL, + "HOTSPOT_TIMING: [disconnected] " + "Connection held for = %.3f sec\n", + session_duration); + snprintf(buff, sizeof(buff), "%s WIFI_IGNITE_HOTSPOT_SESSION_DURATION_SEC:%.3f\n", tmp, + session_duration); + write_to_file(wifi_health_log, buff); + memset(telemetry_buf, 0, sizeof(telemetry_buf)); + snprintf(telemetry_buf, sizeof(telemetry_buf), "%.3f", session_duration); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_HOTSPOT_SESSION_DURATION_SEC", + telemetry_buf); + /* Assign before clearing disconnection_time */ + g_hotspot_timing.start_time = g_hotspot_timing.disconnection_time; + + wifi_util_dbg_print(WIFI_CTRL, + "HOTSPOT_TIMING: [disconnected] was connected – " + "start_time reset to %ld sec for next attempt\n", + (long)g_hotspot_timing.start_time.tv_sec); + + memset(&g_hotspot_timing.target_detection_time, 0, sizeof(struct timespec)); + memset(&g_hotspot_timing.end_time, 0, sizeof(struct timespec)); + memset(&g_hotspot_timing.disconnection_time, 0, sizeof(struct timespec)); + + } else { + /* + * end_time == 0 → device never connected this attempt. + * Log elapsed from current start_time. + * Preserve start_time and target_detection_time for next attempt. + */ + clock_gettime(CLOCK_MONOTONIC, &g_hotspot_timing.disconnection_time); + + wifi_util_info_print(WIFI_CTRL, + "HOTSPOT_TIMING: [disconnected] disconnection_time = " + "%ld sec %ld nsec\n", + (long)g_hotspot_timing.disconnection_time.tv_sec, + (long)g_hotspot_timing.disconnection_time.tv_nsec); + + wifi_util_info_print(WIFI_CTRL, + "HOTSPOT_TIMING: [disconnected] " + "Disconnected before connecting – elapsed = %.3f sec\n", + hotspot_timing_elapsed_sec(&g_hotspot_timing.start_time, + &g_hotspot_timing.disconnection_time)); + + memset(&g_hotspot_timing.disconnection_time, 0, sizeof(struct timespec)); + } +} + bus_error_t get_endpoint_enable(char *name, raw_data_t *p_data, bus_user_data_t *user_data) { (void)user_data; @@ -163,6 +373,7 @@ bus_error_t set_endpoint_enable(char *name, raw_data_t *p_data, bus_user_data_t (void)user_data; bus_error_t rc = bus_error_success; bool rf_status = false; + char tmp[MAX_STR_LEN] = {0}; wifi_ctrl_t *ctrl = (wifi_ctrl_t *)get_wifictrl_obj(); wifi_rfc_dml_parameters_t *rfc_param = get_ctrl_rfc_parameters(); if (ctrl == NULL) { @@ -182,9 +393,13 @@ bus_error_t set_endpoint_enable(char *name, raw_data_t *p_data, bus_user_data_t ctrl->rf_status_down = rf_status; wifi_util_info_print(WIFI_CTRL, "%s:%d RF-Status : %d\n", __func__, __LINE__, ctrl->rf_status_down); start_station_vaps(false, rf_status); + get_formatted_time(tmp); if (rf_status) { - wifi_util_info_print(WIFI_CTRL, "IGNITE_RF_DOWN: Docsis disabled. Starting Station Vaps\n"); - apps_mgr_link_quality_event(&ctrl->apps_mgr, wifi_event_type_exec, wifi_event_exec_start, NULL, 0); + write_to_file(wifi_health_log, "\n%s WIFI_IGNITE_ENABLED:True\n", tmp); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_ENABLED", "True"); + wifi_util_info_print(WIFI_CTRL, "IGNITE_RF_DOWN: Docsis disabled. Starting Station Vaps\n"); + apps_mgr_link_quality_event(&ctrl->apps_mgr, wifi_event_type_exec, wifi_event_exec_start, + NULL, 0); wifi_global_config_t *global_cfg = get_wifidb_wifi_global_config(); if (global_cfg != NULL && @@ -207,10 +422,12 @@ bus_error_t set_endpoint_enable(char *name, raw_data_t *p_data, bus_user_data_t } } } else { - wifi_util_info_print(WIFI_CTRL, "IGNITE_RF_DOWN: Docsis enabled. Stoping Station Vaps\n"); - apps_mgr_link_quality_event(&ctrl->apps_mgr, wifi_event_type_exec, wifi_event_exec_stop, NULL, 0); - //Stop station vaps - stop_extender_vaps(WIFI_ALL_RADIO_INDICES); + write_to_file(wifi_health_log, "\n%s WIFI_IGNITE_ENABLED:False\n", tmp); + get_stubs_descriptor()->t2_event_s_fn("WIFI_IGNITE_ENABLED", "False"); + wifi_util_info_print(WIFI_CTRL, "IGNITE_RF_DOWN: Docsis enabled. Stoping Station Vaps\n"); + apps_mgr_link_quality_event(&ctrl->apps_mgr, wifi_event_type_exec, wifi_event_exec_stop, NULL, 0); + //Stop station vaps + stop_extender_vaps(WIFI_ALL_RADIO_INDICES); if (rfc_param->multiap_rfc) { apps_mgr_multiap_event(&ctrl->apps_mgr, wifi_event_type_exec, wifi_event_exec_start, NULL, 0); } @@ -2432,8 +2649,8 @@ void bus_subscribe_events(wifi_ctrl_t *ctrl) if(!ctrl->hotspot_client_dhcp_failure_subscribed) { if (bus_desc->bus_event_subs_fn(&ctrl->handle, HOTSPOT_CLIENT_DHCP_FAILURE_DISCONNECTED, hotspot_client_dhcp_failure_disconnect, NULL, 0) != bus_error_success) { - wifi_util_error_print(WIFI_CTRL, "%s:%d bus: bus event:%s subscribe fail\n", - __FUNCTION__, __LINE__, HOTSPOT_CLIENT_DHCP_FAILURE_DISCONNECTED); + // wifi_util_dbg_print(WIFI_CTRL, "%s:%d bus: bus event:%s subscribe fail\n", + // __FUNCTION__, __LINE__, HOTSPOT_CLIENT_DHCP_FAILURE_DISCONNECTED); } else { ctrl->hotspot_client_dhcp_failure_subscribed = true; wifi_util_info_print(WIFI_CTRL, "%s:%d bus: bus event:%s subscribe success\n", diff --git a/source/core/wifi_ctrl_webconfig.c b/source/core/wifi_ctrl_webconfig.c index 8dfbfdaf2..d0b26feeb 100644 --- a/source/core/wifi_ctrl_webconfig.c +++ b/source/core/wifi_ctrl_webconfig.c @@ -36,6 +36,8 @@ #include "wifi_webconfig_consumer.h" #endif #define OW_CONF_BARRIER_TIMEOUT_MSEC (60 * 1000) +#define SSID_MAX_LEN (64) +#define KEY_MAX_LEN (256) bool is_sta_set = false; struct ow_conf_vif_config_cb_arg { @@ -3214,6 +3216,8 @@ static void create_station_with_private_credentials(webconfig_subdoc_data_t *dat int private_vap_index = 0, radio_index = 0, vap_index = 0, band = 0; int status = RETURN_OK; int vap_array_index = 0, private_vap_array_index = 0; + char tmp_ssid[SSID_MAX_LEN + 1] = {0}; + char tmp_key[KEY_MAX_LEN + 1] = {0}; for (int i = 0; i < num_vaps || i < private_num_vaps; i++) { vap_index = convert_vap_name_to_index(&data->u.decoded.hal_cap.wifi_prop, vap_names[i]); @@ -3237,16 +3241,17 @@ static void create_station_with_private_credentials(webconfig_subdoc_data_t *dat else { wifi_util_info_print(WIFI_CTRL, "%s:%d pvt_ssid= %s\n", __func__, __LINE__, data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[private_vap_array_index].u.bss_info.ssid); + snprintf(tmp_ssid, sizeof(tmp_ssid), "%s", + data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[private_vap_array_index].u.bss_info.ssid); snprintf(data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[vap_array_index].u.sta_info.ssid, sizeof(data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[vap_array_index].u.sta_info.ssid), - "%s", data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[private_vap_array_index].u.bss_info.ssid); - + "%s", tmp_ssid); + snprintf(tmp_key, sizeof(tmp_key), "%s", + data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[private_vap_array_index].u.bss_info.security.u.key.key); snprintf(data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[vap_array_index].u.sta_info.security.u.key.key, sizeof(data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[vap_array_index].u.sta_info.security.u.key.key), - "%s", data->u.decoded.radios[radio_index].vaps.vap_map.vap_array[private_vap_array_index].u.bss_info.security.u.key.key); - + "%s", tmp_key); convert_radio_index_to_freq_band(&data->u.decoded.hal_cap.wifi_prop, radio_index,&band); - if (band == WIFI_FREQUENCY_6_BAND) { data->u.decoded.radios[radio_index] .vaps.vap_map.vap_array[vap_array_index] @@ -3352,19 +3357,25 @@ void start_station_vaps(bool is_private, bool rf_status) webconfig_init_subdoc_data(data); unsigned int num_vaps = get_list_of_mesh_sta(&data->u.decoded.hal_cap.wifi_prop, MAX_NUM_RADIOS, - &vap_names[0]); + &vap_names[0]); if (rf_status && !is_private) { - wifi_util_info_print(WIFI_CTRL, "%s:%d RF is down creating station with Hotspot credentials\n", __func__, __LINE__); - create_station_with_xfinity_credentials(data, num_vaps, vap_names); - } - else if (rf_status) { + wifi_util_info_print(WIFI_CTRL, + "%s:%d RF is down creating station with Hotspot credentials\n", __func__, __LINE__); + hotspot_timing_start(); + create_station_with_xfinity_credentials(data, num_vaps, vap_names); + } else if (rf_status) { wifi_util_info_print(WIFI_CTRL, "%s:%d Creating station with Private credentials\n", __func__, __LINE__); private_num_vaps = get_list_of_private_ssid(&data->u.decoded.hal_cap.wifi_prop, MAX_NUM_RADIOS, &private_vap_names[0]); create_station_with_private_credentials(data, num_vaps, private_num_vaps, private_vap_names, vap_names); - } - else { - wifi_util_info_print(WIFI_CTRL, "%s:%d Station vaps going back to Default case\n", __func__, __LINE__); + } else { + wifi_util_info_print(WIFI_CTRL, "%s:%d Station vaps going back to Default case\n", __func__, + __LINE__); (void)create_station_with_default_credentials(data, num_vaps, vap_names); + if ((rf_status == 0) && (!is_private)) { + wifi_util_info_print(WIFI_CTRL, + "%s:%d Docsis enabled and no private vap config detected\n", __func__, __LINE__); + hotspot_timing_stop(); + } } if (webconfig_encode(&ctrl->webconfig, data, webconfig_subdoc_type_mesh_sta) == webconfig_error_none) { wifi_util_info_print(WIFI_CTRL, "%s:%d webconfig_encode success\n", __func__, __LINE__); diff --git a/source/core/wifi_events.c b/source/core/wifi_events.c index 99733b6cd..043365361 100644 --- a/source/core/wifi_events.c +++ b/source/core/wifi_events.c @@ -106,6 +106,7 @@ const char *wifi_event_subtype_to_string(wifi_event_subtype_t type) DOC2S(wifi_event_radius_fallback_and_failover) DOC2S(wifi_event_type_csi_data) DOC2S(wifi_event_hal_wps_results) + DOC2S(wifi_event_hal_wnm_action_frame) DOC2S(wifi_event_hal_max) DOC2S(wifi_event_type_active_gw_check) DOC2S(wifi_event_type_command_factory_reset) @@ -154,6 +155,7 @@ const char *wifi_event_subtype_to_string(wifi_event_subtype_t type) DOC2S(wifi_event_type_rsn_override_rfc) DOC2S(wifi_event_type_sta_client_info) DOC2S(wifi_event_type_sm_app_enable) + DOC2S(wifi_event_type_send_btm_req) DOC2S(wifi_event_command_max) DOC2S(wifi_event_monitor_diagnostics) DOC2S(wifi_event_monitor_connect) @@ -175,6 +177,7 @@ const char *wifi_event_subtype_to_string(wifi_event_subtype_t type) DOC2S(wifi_event_monitor_provider_response) DOC2S(wifi_event_monitor_auth_req) DOC2S(wifi_event_monitor_assoc_req) + DOC2S(wifi_event_monitor_reassoc_req) DOC2S(wifi_event_monitor_clear_sta_counters) DOC2S(wifi_event_monitor_get_radiostats_onchan) DOC2S(wifi_event_monitor_get_radiostats_offchan) diff --git a/source/dml/tr_181/ml/cosa_wifi_dml.c b/source/dml/tr_181/ml/cosa_wifi_dml.c index e5746370f..b13a19e04 100755 --- a/source/dml/tr_181/ml/cosa_wifi_dml.c +++ b/source/dml/tr_181/ml/cosa_wifi_dml.c @@ -1255,7 +1255,6 @@ WiFi_SetParamBoolValue push_rfc_dml_cache_to_one_wifidb(bValue, wifi_event_type_tcm_rfc); wifi_util_dbg_print(WIFI_DMCLI,"%s:%d Tcm rfc value set bvalue is %d \n", __FUNCTION__,__LINE__,bValue); } - wifi_util_dbg_print(WIFI_DMCLI,"%s:%d Tcm started\n", __FUNCTION__,__LINE__); return TRUE; } diff --git a/source/platform/common/bus_common.c b/source/platform/common/bus_common.c index da974e7eb..64533a1cd 100644 --- a/source/platform/common/bus_common.c +++ b/source/platform/common/bus_common.c @@ -231,7 +231,7 @@ elem_node_map_t* bus_insert_elem_node(elem_node_map_t* root, bus_mux_data_elem_t elem_node_map_t* current_node = root; elem_node_map_t* temp_node = NULL; elem_node_map_t* next_node = NULL; - int ret = 0, create_child = 0; + int create_child = 0; char buff[256]; if(current_node == NULL || elem == NULL) @@ -242,7 +242,7 @@ elem_node_map_t* bus_insert_elem_node(elem_node_map_t* root, bus_mux_data_elem_t next_node = current_node->child; create_child = 1; - wifi_util_info_print(WIFI_BUS,"Request to insert element [%s]!!\r\n", elem->full_name); + wifi_util_dbg_print(WIFI_BUS,"Request to insert element [%s]!!\r\n", elem->full_name); strncpy(name, elem->full_name, strlen(elem->full_name) + 1); @@ -343,16 +343,21 @@ elem_node_map_t* bus_insert_elem_node(elem_node_map_t* root, bus_mux_data_elem_t } token = strtok_r(NULL, ".", &saveptr); } - if(ret != 0) - { - - BUS_MUX_UNLOCK(get_bus_mux_mutex()); - return NULL; - } current_node->type = elem->type; current_node->node_data_type = elem->node_data_type; - current_node->node_elem_data = malloc(elem->cfg_data_len); + + if (current_node->node_elem_data_len != elem->cfg_data_len) { + if (current_node->node_elem_data != NULL) { + wifi_util_info_print(WIFI_BUS, "%s:%d Updated node [%s] data len from %d to %d\n", + __func__, __LINE__, current_node->full_name, current_node->node_elem_data_len, + elem->cfg_data_len); + free(current_node->node_elem_data); + current_node->node_elem_data = NULL; + current_node->node_elem_data_len = 0; + } + current_node->node_elem_data = malloc(elem->cfg_data_len); + } if(current_node->node_elem_data == NULL) { wifi_util_error_print(WIFI_BUS, "Failed to create node [%s]\n", elem->full_name); @@ -362,7 +367,7 @@ elem_node_map_t* bus_insert_elem_node(elem_node_map_t* root, bus_mux_data_elem_t memcpy(current_node->node_elem_data, elem->cfg_data, elem->cfg_data_len); current_node->node_elem_data_len = elem->cfg_data_len; - if(elem->type == bus_element_type_table) + if(elem->type == bus_element_type_table && current_node->child == NULL) { elem_node_map_t* rowTemplate = get_empty_elem_node(); if(rowTemplate == NULL) diff --git a/source/platform/rdkb/bus.c b/source/platform/rdkb/bus.c index a69ba86f3..9e7f587c0 100644 --- a/source/platform/rdkb/bus.c +++ b/source/platform/rdkb/bus.c @@ -1183,7 +1183,7 @@ static void bus_sub_cb_registration(char *event_name, rbus_sub_callback_table_t user_cb_set = true; } - wifi_util_info_print(WIFI_BUS,"%s:%d sub_user_cb_set:%d event_name:%s\n", __func__, __LINE__, user_cb_set, event_name); + wifi_util_dbg_print(WIFI_BUS,"%s:%d sub_user_cb_set:%d event_name:%s\n", __func__, __LINE__, user_cb_set, event_name); if (user_cb_set == true) { elem_node_map_t *sub_cb_mux_map = get_bus_mux_sub_cb_map(); diff --git a/source/stats/wifi_monitor.c b/source/stats/wifi_monitor.c index 5176beff2..50a7d30b4 100644 --- a/source/stats/wifi_monitor.c +++ b/source/stats/wifi_monitor.c @@ -426,6 +426,124 @@ hash_map_t *get_interop_sta_data_map(unsigned int vap_index) { return g_monitor_module.bssid_data[vap_array_index].interop_sta_map; } +int interop_reassoc_frame_data(frame_data_t *msg) { + + hash_map_t *sta_map; + interop_data_t *sta; + struct ieee80211_mgmt *frame; + mac_addr_str_t mac_str = { 0 }; + char *str; + int ipstat,sta_map_count; + bool ipenable; + frame = (struct ieee80211_mgmt *)msg->data; + if (frame == NULL) { + wifi_util_error_print(WIFI_MON, "%s:%d frame details are null \r\n", __func__, __LINE__); + return RETURN_ERR; + } + str = to_mac_str(frame->sa, mac_str); + if (str == NULL) { + wifi_util_error_print(WIFI_MON, "%s:%d mac str convert failure\r\n", __func__, __LINE__); + return RETURN_ERR; + } + wifi_util_dbg_print(WIFI_MON, "%s:%d wifi mgmt frame message: ap_index:%d length:%d type:%d dir:%d src mac:%s rssi:%d\r\n", __func__, __LINE__, msg->frame.ap_index, msg->frame.len, msg->frame.type, msg->frame.dir, str, msg->frame.sig_dbm); + wifi_front_haul_bss_t *vap_bss_info = Get_wifi_object_bss_parameter(msg->frame.ap_index); + if (vap_bss_info == NULL) { + wifi_util_dbg_print(WIFI_MON, "%s:%d vap_bss_info is null for vap_idex:%d \r\n", __func__, __LINE__, msg->frame.ap_index); + return RETURN_ERR; + } + ipstat = vap_bss_info->inum_sta; + ipenable = vap_bss_info->interop_ctrl; + wifi_util_dbg_print(WIFI_MON, "%s:%d Ipstat:%d ipenable:%d ipstat:%d,ipenable:%d \r\n", __func__, __LINE__,vap_bss_info->inum_sta,vap_bss_info->interop_ctrl,ipstat,ipenable); + if (ipenable == 0) { + // wifi_util_dbg_print(WIFI_MON, "%s:%d interopctrl is disabled, ipstat:%d ipenable:%d \r\n", __func__, __LINE__,ipstat,ipenable); + return RETURN_OK; + } + if (!isVapPrivate(msg->frame.ap_index) && !(isVapHotspotSecure5g(msg->frame.ap_index) || isVapHotspotSecure6g(msg->frame.ap_index) || isVapHotspotOpen5g(msg->frame.ap_index) || isVapHotspotOpen6g(msg->frame.ap_index))){ + //wifi_util_dbg_print(WIFI_MON, "%s:%d It's not a private vap or hotspot vap \r\n", __func__, __LINE__); + return RETURN_OK; + } + sta_map = get_interop_sta_data_map(msg->frame.ap_index); + if (sta_map == NULL) { + wifi_util_error_print(WIFI_MON, "%s:%d sta_data map not found for vap_index:%d\r\n", __func__, __LINE__, msg->frame.ap_index); + return RETURN_ERR; + } + sta_map_count = (int)hash_map_count(sta_map); + if (ipstat <= sta_map_count) { + wifi_util_dbg_print(WIFI_MON, "%s:%d ipstat:%d less than or equal to stamap count:%d are \r\n", __func__, __LINE__,ipstat,sta_map_count); + return RETURN_OK; + } + sta = (interop_data_t *)hash_map_get(sta_map, mac_str); + if (sta == NULL) { + sta = create_interop_sta_data_hash_map(sta_map, frame->sa, frame->da); + wifi_util_dbg_print(WIFI_MON, "%s:%d created STA MAC:%s count:%d \n", __func__, __LINE__, str,sta_map_count); + if (sta == NULL) { + wifi_util_error_print(WIFI_MON, "%s:%d sta is null as creation of station is failed and returning null \r\n", __func__, __LINE__); + return RETURN_ERR; + } + } + sta->eapol_frame_type = EAPOL_FRAME_REASSOC; + return RETURN_OK; +} + +int interop_assoc_frame_data(frame_data_t *msg) { + + hash_map_t *sta_map; + interop_data_t *sta; + struct ieee80211_mgmt *frame; + mac_addr_str_t mac_str = { 0 }; + char *str; + int ipstat,sta_map_count; + bool ipenable; + frame = (struct ieee80211_mgmt *)msg->data; + if (frame == NULL) { + wifi_util_error_print(WIFI_MON, "%s:%d frame details are null \r\n", __func__, __LINE__); + return RETURN_ERR; + } + str = to_mac_str(frame->sa, mac_str); + if (str == NULL) { + wifi_util_error_print(WIFI_MON, "%s:%d mac str convert failure\r\n", __func__, __LINE__); + return RETURN_ERR; + } + wifi_util_dbg_print(WIFI_MON, "%s:%d wifi mgmt frame message: ap_index:%d length:%d type:%d dir:%d src mac:%s rssi:%d\r\n", __func__, __LINE__, msg->frame.ap_index, msg->frame.len, msg->frame.type, msg->frame.dir, str, msg->frame.sig_dbm); + wifi_front_haul_bss_t *vap_bss_info = Get_wifi_object_bss_parameter(msg->frame.ap_index); + if (vap_bss_info == NULL) { + wifi_util_dbg_print(WIFI_MON, "%s:%d vap_bss_info is null for vap_idex:%d \r\n", __func__, __LINE__, msg->frame.ap_index); + return RETURN_ERR; + } + ipstat = vap_bss_info->inum_sta; + ipenable = vap_bss_info->interop_ctrl; + wifi_util_dbg_print(WIFI_MON, "%s:%d Ipstat:%d ipenable:%d ipstat:%d,ipenable:%d \r\n", __func__, __LINE__,vap_bss_info->inum_sta,vap_bss_info->interop_ctrl,ipstat,ipenable); + if (ipenable == 0) { + // wifi_util_dbg_print(WIFI_MON, "%s:%d interopctrl is disabled, ipstat:%d ipenable:%d \r\n", __func__, __LINE__,ipstat,ipenable); + return RETURN_OK; + } + if (!isVapPrivate(msg->frame.ap_index) && !(isVapHotspotSecure5g(msg->frame.ap_index) || isVapHotspotSecure6g(msg->frame.ap_index) || isVapHotspotOpen5g(msg->frame.ap_index) || isVapHotspotOpen6g(msg->frame.ap_index))){ + //wifi_util_dbg_print(WIFI_MON, "%s:%d It's not a private vap or hotspot vap \r\n", __func__, __LINE__); + return RETURN_OK; + } + sta_map = get_interop_sta_data_map(msg->frame.ap_index); + if (sta_map == NULL) { + wifi_util_error_print(WIFI_MON, "%s:%d sta_data map not found for vap_index:%d\r\n", __func__, __LINE__, msg->frame.ap_index); + return RETURN_ERR; + } + sta_map_count = (int)hash_map_count(sta_map); + if (ipstat <= sta_map_count) { + wifi_util_dbg_print(WIFI_MON, "%s:%d ipstat:%d less than or equal to stamap count:%d are \r\n", __func__, __LINE__,ipstat,sta_map_count); + return RETURN_OK; + } + sta = (interop_data_t *)hash_map_get(sta_map, mac_str); + if (sta == NULL) { + sta = create_interop_sta_data_hash_map(sta_map, frame->sa, frame->da); + wifi_util_dbg_print(WIFI_MON, "%s:%d created STA MAC:%s count:%d \n", __func__, __LINE__, str,sta_map_count); + if (sta == NULL) { + wifi_util_error_print(WIFI_MON, "%s:%d sta is null as creation of station is failed and returning null \r\n", __func__, __LINE__); + return RETURN_ERR; + } + } + sta->eapol_frame_type = EAPOL_FRAME_ASSOC; + return RETURN_OK; +} + int set_auth_req_frame_data(frame_data_t *msg) { hash_map_t *sta_map; @@ -481,7 +599,7 @@ int set_auth_req_frame_data(frame_data_t *msg) { wifi_util_error_print(WIFI_MON, "%s:%d sta is null as creation of station is failed and returning null \r\n", __func__, __LINE__); return RETURN_ERR; } - } + } unsigned int radioIndex = getRadioIndexFromAp(msg->frame.ap_index); wifi_radio_operationParam_t* radioOperation = getRadioOperationParam(radioIndex); @@ -646,6 +764,7 @@ static void telemetry_event_common(const char *event_name, int count, int vapind write_to_file(wifi_health_log, buff); get_stubs_descriptor()->t2_event_s_fn(telemetry_buff, telemetry_val); } + void telemetry_event_handshake_count(interop_data_t *sta1, int vapindex, char *mac, char *ap) { telemetry_event_common("EAPOL_HANDSHAKE_STATUS", sta1->status, vapindex, mac, ap); } @@ -812,7 +931,9 @@ static void telemetry_event_sta_ap_code_counts(interop_data_t *sta1, get_stubs_descriptor()->t2_event_s_fn(telemetry_buff, telemetry_val); } } - +void interop_log_eapol_reason_15(interop_data_t *sta, + char *client_mac, + int vapindex); void telemetry_event_code_count(interop_data_t *sta1, int vapindex, char *mac, char *ap) { bool xfi_enable; wifi_front_haul_bss_t *vap_bss_info = Get_wifi_object_bss_parameter(vapindex); @@ -823,16 +944,18 @@ void telemetry_event_code_count(interop_data_t *sta1, int vapindex, char *mac, c return; } wifi_util_info_print(WIFI_MON, "%s:%d station found for mac :%s vap index:%d ,rssi:%d, noise:%d snr:%d channel_util:%d \n", __func__, __LINE__, mac, vapindex, sta1->rssi, sta1->noise_floor, sta1->snr, sta1->channel_util); + wifi_util_dbg_print(WIFI_MON, "%s:%d station found for mac :%s vap index:%d , eapol_msg_type:%d, eapol_frame_type:%d eapol_0:%d eapol_1:%d eapol_2:%d eapol_3:%d eapol_4:%d eapol_5:%d \n", __func__, __LINE__, mac, vapindex, sta1->eapol_msg_type, sta1->eapol_frame_type, sta1->eapol_status_type_counts[0], sta1->eapol_status_type_counts[1], sta1->eapol_status_type_counts[2], sta1->eapol_status_type_counts[3], sta1->eapol_status_type_counts[4], sta1->eapol_status_type_counts[5]); if (xfi_enable && (isVapHotspot(vapindex))) { wifi_util_info_print(WIFI_MON, "xfi_enable_rfc is enabled\n"); telemetry_event_access_accept_count(sta1, vapindex, mac, ap); telemetry_event_eap_success_count(sta1, vapindex, mac, ap); telemetry_event_eap_failure_count(sta1, vapindex, mac, ap); - telemetry_event_eap_reason_count(sta1, vapindex, mac, ap); - telemetry_event_eap_ap_reason_count(sta1, vapindex, mac, ap); - telemetry_event_handshake_count(sta1, vapindex, mac, ap); - telemetry_event_interop_extra_details(sta1, vapindex, mac, ap); } + telemetry_event_eap_reason_count(sta1, vapindex, mac, ap); + telemetry_event_eap_ap_reason_count(sta1, vapindex, mac, ap); + telemetry_event_handshake_count(sta1, vapindex, mac, ap); + telemetry_event_interop_extra_details(sta1, vapindex, mac, ap); + interop_log_eapol_reason_15(sta1, mac, vapindex); if (vap_bss_info == NULL) { wifi_util_dbg_print(WIFI_MON, "%s:%d vap_bss_info is null for vap_idex:%d \r\n", __func__, __LINE__, vapindex); return; @@ -1520,6 +1643,9 @@ hash_map_t *get_sta_data_map(unsigned int vap_index) return g_monitor_module.bssid_data[vap_array_index].sta_map; } + + + int set_assoc_req_frame_data(frame_data_t *msg) { hash_map_t *sta_map; @@ -1554,6 +1680,7 @@ int set_assoc_req_frame_data(frame_data_t *msg) } } wpa3_enhanced_assoc_frame_data(msg); + interop_assoc_frame_data(msg); (void)memset(&sta->assoc_frame_data, 0, sizeof(assoc_req_elem_t)); (void)memcpy(&sta->assoc_frame_data.msg_data, msg, sizeof(frame_data_t)); (void)time(&frame_timestamp); @@ -1562,6 +1689,13 @@ int set_assoc_req_frame_data(frame_data_t *msg) return RETURN_OK; } +int set_reassoc_req_frame_data(frame_data_t *msg) +{ + interop_reassoc_frame_data(msg); + return RETURN_OK; + +} + int update_assoc_frame_data_entry(unsigned int vap_index) { hash_map_t *sta_map; @@ -1712,6 +1846,25 @@ int handle_handshake_status(int ap_index, char *mac, int status) return RETURN_OK; } +int eapol_timeout_type(int ap_index, char *mac, int type) +{ + hash_map_t *sta_map; + interop_data_t *sta; + sta_map = get_interop_sta_data_map(ap_index); + if (sta_map == NULL) { + wifi_util_dbg_print(WIFI_MON, "%s:%d sta_data map not found for vap_index:%d\r\n", __func__, __LINE__, ap_index); + return RETURN_ERR; + } + sta = (interop_data_t *)hash_map_get(sta_map, mac); + if (NULL == sta) { + wifi_util_dbg_print(WIFI_MON, "%s:%d station is not found for vap_index:%d station :%s \r\n", __func__, __LINE__, ap_index, mac); + return RETURN_ERR; + } + sta->eapol_msg_type= type; + wifi_util_dbg_print(WIFI_MON, "%s:%s-%d for idx-%d exit and done\n", __func__, mac, type, ap_index); + return RETURN_OK; +} + int set_sta_client_mode(int ap_index, char *mac, int key_mgmt, frame_type_t frame_type, int band, int mode) { hash_map_t *sta_map; telemetry_data_t *sta; @@ -2251,6 +2404,9 @@ void *monitor_function (void *data) case wifi_event_monitor_assoc_req: set_assoc_req_frame_data(&event_data->u.msg); break; + case wifi_event_monitor_reassoc_req: + set_reassoc_req_frame_data(&event_data->u.msg); + break; case wifi_event_monitor_start_inst_msmt: g_monitor_module.inst_msmt_id = 1; scheduler_telemetry_tasks(); @@ -3347,6 +3503,158 @@ int ap_status_code(int ap_index, char *src_mac, char *dest_mac, int type, int st return 0; } +void interop_update_eapol_status_counts(interop_data_t *sta) +{ + int base_idx; + int msg_idx; + if (!sta) { + return; + } + /* Validate message type */ + if (sta->eapol_msg_type < EAPOL_MSG_M1 || + sta->eapol_msg_type > EAPOL_MSG_M3) { + wifi_util_dbg_print(WIFI_MON, " exit %s:%d return as not m1,m3\n", __func__, __LINE__); + return; + } + /* Determine assoc / reassoc offset */ + if (sta->eapol_frame_type == EAPOL_FRAME_ASSOC) { + base_idx = 0; + } else if (sta->eapol_frame_type == EAPOL_FRAME_REASSOC) { + base_idx = 1; + } else { + wifi_util_dbg_print(WIFI_MON, " exit %s:%d return as not frametype\n", __func__, __LINE__); + return; + } + /* + * Convert message type to array index: + * M1 -> 0 + * M2 -> 2 + * M3 -> 4 + */ + msg_idx = (sta->eapol_msg_type - EAPOL_MSG_M1) * 2; + sta->eapol_status_type_counts[msg_idx + base_idx]++; +} + +static const char *eapol_msg_str[] = { + "UNKNOWN", + "M1", + "M2", + "M3" +}; + +static const char *eapol_frame_str[] = { + "unknown", + "association", + "reassociation" +}; + +char *interop_get_band_str_from_radio_index(unsigned int radioIndex) +{ + switch (radioIndex) { + case 0: + return "2G"; + case 1: + return "5G"; + case 2: + return "6G"; + default: + return "Unknown"; + } +} + + +void interop_decode_eapol_index(int idx, + eapol_msg_type_t *msg, + eapol_frame_type_t *frame) +{ + if (!msg || !frame) { + return; + } + + /* + * Index mapping: + * 0 -> M1 ASSOC + * 1 -> M1 REASSOC + * 2 -> M2 ASSOC + * 3 -> M2 REASSOC + * 4 -> M3 ASSOC + * 5 -> M3 REASSOC + */ + + *msg = (idx / 2) + EAPOL_MSG_M1; + *frame = (idx % 2 == 0) ? + EAPOL_FRAME_ASSOC : + EAPOL_FRAME_REASSOC; +} + +void interop_log_eapol_reason_15(interop_data_t *sta, + char *client_mac, + int vapindex) +{ + unsigned int radioIndex; + const char *band_str; + int i; + + if (!sta || !client_mac) { + return; + } + + radioIndex = getRadioIndexFromAp(vapindex); + band_str = interop_get_band_str_from_radio_index(radioIndex); + + /* Iterate over all 6 EAPOL counts */ + for (i = 0; i < 6; i++) { + + unsigned int count = sta->eapol_status_type_counts[i]; + if (count == 0) { + continue; + } + + eapol_msg_type_t msg; + eapol_frame_type_t frame; + + interop_decode_eapol_index(i, &msg, &frame); + char telemetry_buff[64]; + char telemetry_val[128]; + char buff[256]; + char tmp[64]; + + snprintf(telemetry_buff, + sizeof(telemetry_buff), + "EAPOL_HANDSHAKE_TIMEOUT_DESC_%d", + vapindex + 1); + + snprintf(telemetry_val, + sizeof(telemetry_val), + "Reason=15 due to EAPOL %s timeout during %s on %s " + "for client MAC %s occurred %d times", + eapol_msg_str[msg], + eapol_frame_str[frame], + band_str, + client_mac, + (int)count); + + wifi_util_dbg_print(WIFI_MON, + "%s:%s\n", + telemetry_buff, + telemetry_val); + + get_formatted_time(tmp); + snprintf(buff, + sizeof(buff), + "%s:%s:%s\n", + tmp, + telemetry_buff, + telemetry_val); + + write_to_file(wifi_health_log, buff); + + get_stubs_descriptor()->t2_event_s_fn( + telemetry_buff, telemetry_val); + + } +} + int ap_reason_code(int ap_index, char *src_mac, char *dest_mac, int type, int reason_code) { int is_ap = -1; @@ -3377,6 +3685,9 @@ int ap_reason_code(int ap_index, char *src_mac, char *dest_mac, int type, int re is_ap = 0; } wifi_reason_code_t reason = (wifi_reason_code_t)reason_code; + if (reason == WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT) { + interop_update_eapol_status_counts(sta); + } if (increment_reason_count(sta, reason, is_ap) == -1) { wifi_util_dbg_print(WIFI_MON, " exit %s:%d as particular reason is not there\n", __func__, __LINE__); return 0; @@ -4219,6 +4530,7 @@ int init_wifi_monitor() wifi_hal_radiusFallback_failover_callback_register(radius_fallback_and_failover_callback); wifi_hal_stamode_callback_register(set_sta_client_mode); wifi_hal_apStatusCode_callback_register(ap_status_code); + wifi_hal_eapol_timeouts_callback_register(eapol_timeout_type); wifi_hal_handshake_callback_register(handle_handshake_status); scheduler_add_timer_task(g_monitor_module.sched, FALSE, NULL, refresh_assoc_frame_entry, NULL, (MAX_ASSOC_FRAME_REFRESH_PERIOD * 1000), 0, FALSE); scheduler_add_timer_task(g_monitor_module.sched, FALSE, &g_monitor_module.interop_id, reset_interop_sta_data, NULL, (get_chan_util_upload_period() * 1000), 0, FALSE); diff --git a/source/test/gtest_main.cpp b/source/test/gtest_main.cpp index 02a181d1c..39d4a5b10 100644 --- a/source/test/gtest_main.cpp +++ b/source/test/gtest_main.cpp @@ -1,15 +1,15 @@ /************************************************************************************ If not stated otherwise in this file or this component's LICENSE file the following copyright and licenses apply: - + Copyright 2018 RDK Management - + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/source/test/platform_mocks.c b/source/test/platform_mocks.c new file mode 100644 index 000000000..86702b8db --- /dev/null +++ b/source/test/platform_mocks.c @@ -0,0 +1,98 @@ +/************************************************************************************ + If not stated otherwise in this file or this component's LICENSE file the + following copyright and licenses apply: + + Copyright 2025 RDK Management + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + **************************************************************************/ +#include +#include +#include +#include "wifi_hal.h" +#include "wifi_hal_priv.h" + + +#define NULL_CHAR '\0' +#define NEW_LINE '\n' +#define MAX_BUF_SIZE 128 +#define MAX_CMD_SIZE 1024 +#define MOCK_LEN_32 32 +#define MOCK_LEN_16 16 +#define MAX_KEYPASSPHRASE_LEN 129 +#define MAX_SSID_LEN 33 +#define INVALID_KEY "12345678" + + +int wifi_rrm_send_beacon_req(struct wifi_interface_info_t *interface, const u8 *addr, + u16 num_of_repetitions, u8 measurement_request_mode, u8 oper_class, u8 channel, + u16 random_interval, u16 measurement_duration, u8 mode, const u8 *bssid, + struct wpa_ssid_value *ssid, u8 *rep_cond, u8 *rep_cond_threshold, u8 *rep_detail, + const u8 *ap_ch_rep, unsigned int ap_ch_rep_len, const u8 *req_elem, unsigned int req_elem_len, + u8 *ch_width, u8 *ch_center_freq0, u8 *ch_center_freq1, u8 last_indication) +{ + return 0; +} + +/* called by BTM API */ +int wifi_wnm_send_bss_tm_req(struct wifi_interface_info_t *interface, struct sta_info *sta, + u8 dialog_token, u8 req_mode, int disassoc_timer, u8 valid_int, const u8 *bss_term_dur, + const char *url, const u8 *nei_rep, size_t nei_rep_len, const u8 *mbo_attrs, size_t mbo_len) +{ + return 0; +} + +int handle_wnm_action_frame(struct wifi_interface_info_t *interface, const mac_address_t sta, + struct ieee80211_mgmt *mgmt, size_t len) +{ + return 0; +} + +int handle_rrm_action_frame(struct wifi_interface_info_t *interface, const mac_address_t sta, + const struct ieee80211_mgmt *mgmt, size_t len, int ssi_signal) +{ + return 0; +} + +#ifdef CONFIG_IEEE80211BE +int nl80211_drv_mlo_msg(struct nl_msg *msg, struct nl_msg **msg_mlo, void *priv, + struct wpa_driver_ap_params *params) +{ + (void)msg; + (void)msg_mlo; + (void)priv; + (void)params; + + return 0; +} + +int nl80211_send_mlo_msg(struct nl_msg *msg) +{ + (void)msg; + + return 0; +} + +void wifi_drv_get_phy_eht_cap_mac(struct eht_capabilities *eht_capab, struct nlattr **tb) +{ + (void)eht_capab; + (void)tb; +} + +int update_hostap_mlo(wifi_interface_info_t *interface) +{ + (void)interface; + + return 0; +} +#endif /* CONFIG_IEEE80211BE */ diff --git a/source/test/wifi_ctrl_webconfig_test.cpp b/source/test/wifi_ctrl_webconfig_test.cpp new file mode 100644 index 000000000..187053c18 --- /dev/null +++ b/source/test/wifi_ctrl_webconfig_test.cpp @@ -0,0 +1,226 @@ +/************************************************************************************ + If not stated otherwise in this file or this component's LICENSE file the + following copyright and licenses apply: + + Copyright 2025 RDK Management + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + **************************************************************************/ +#include +#include "wifi_webconfig.h" +#include "source/core/wifi_ctrl.h" +#include "source/core/wifi_mgr.h" + + +extern "C" { + int webconfig_vif_neighbors_apply(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_data_t *data); + // note: the ctrl argument is not used in this function +} + +// test covering NULL argument case from RDKBWIFI-201 +TEST(WifiCtrlWebconfig, VifNeighborsApplyNullArguments) +{ + ASSERT_EXIT((webconfig_vif_neighbors_apply(NULL, NULL), exit(0)), ::testing::ExitedWithCode(0), ".*"); + // expected that RETURN_ERR is -1, but use the macro if possible + ASSERT_EQ(webconfig_vif_neighbors_apply(NULL, NULL), RETURN_ERR); +} + +TEST(WifiCtrlWebconfig, VifNeighborsApplyNullNeighborsMap) +{ + webconfig_subdoc_decoded_data_t data = {0}; + data.vif_neighbors_map = NULL; + ASSERT_EXIT((webconfig_vif_neighbors_apply(NULL, &data), exit(0)), ::testing::ExitedWithCode(0), ".*"); + + // expected that RETURN_ERR is -1, but use the macro if possible + ASSERT_EQ(webconfig_vif_neighbors_apply(NULL, &data), RETURN_ERR); +} + +TEST(WifiCtrlWebconfig, VifNeighborsApplyHappyPathEmptyHashMap) +{ + webconfig_subdoc_decoded_data_t data = {0}; + data.vif_neighbors_map = hash_map_create(); + + wifi_mgr_t *mgr = get_wifimgr_obj(); + mgr->vif_neighbors_map = hash_map_create(); + + ASSERT_EQ(webconfig_vif_neighbors_apply(NULL, &data), RETURN_OK); + + hash_map_destroy(mgr->vif_neighbors_map); + mgr->vif_neighbors_map = NULL; +} + +/** + data.vif_neighbors_map is destroyed by webconfig_vif_neighbors_apply, but the + pointer is not set to NULL -- which is dangerous! this test should replace the + above test when this issue is fixed +**/ +TEST(WifiCtrlWebconfig, DISABLED_VifNeighborsApplyHappyPathCheckDestroyedMapPtr) +{ + webconfig_subdoc_decoded_data_t data = {0}; + data.vif_neighbors_map = hash_map_create(); + + wifi_mgr_t *mgr = get_wifimgr_obj(); + mgr->vif_neighbors_map = hash_map_create(); + + ASSERT_EQ(webconfig_vif_neighbors_apply(NULL, &data), RETURN_OK); + + // this should really be null, since it's been destroyed! + ASSERT_EQ(data.vif_neighbors_map, nullptr); + + hash_map_destroy(mgr->vif_neighbors_map); + mgr->vif_neighbors_map = NULL; +} + +extern "C" { + int webconfig_steering_config_apply(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_data_t *data); +} + +// test covering NULL argument case from RDKBWIFI-200 +TEST(WifiCtrlWebconfig, SteeringConfigApplyNullArguments) +{ + ASSERT_EXIT((webconfig_steering_config_apply(NULL, NULL), exit(0)), ::testing::ExitedWithCode(0), ".*"); + // expected that RETURN_ERR is -1, butuse the macro if possible + ASSERT_EQ(webconfig_steering_config_apply(NULL, NULL), RETURN_ERR); +} + +TEST(WifiCtrlWebconfig, SteeringConfigApplyNullSteeringConfigMap) +{ + // expected that RETURN_ERR is -1, butuse the macro if possible + webconfig_subdoc_decoded_data_t data = {0}; + data.steering_config_map = NULL; + + ASSERT_EQ(webconfig_steering_config_apply(NULL, &data), RETURN_ERR); +} + +TEST(WifiCtrlWebconfig, SteeringConfigApplySameSteeringConfigMap) +{ + wifi_mgr_t *mgr = get_wifimgr_obj(); + + webconfig_subdoc_decoded_data_t data = {0}; + data.steering_config_map = hash_map_create(); + mgr->steering_config_map = data.steering_config_map; + + ASSERT_EQ(webconfig_steering_config_apply(NULL, &data), RETURN_OK); + + mgr->steering_config_map = NULL; +} + +TEST(WifiCtrlWebconfig, SteeringConfigApplyEmptySteeringConfigMap) +{ + wifi_mgr_t *mgr = get_wifimgr_obj(); + + webconfig_subdoc_decoded_data_t data = {0}; + data.steering_config_map = hash_map_create(); + mgr->steering_config_map = hash_map_create(); + + ASSERT_EQ(webconfig_steering_config_apply(NULL, &data), RETURN_OK); + + hash_map_destroy(mgr->steering_config_map); + mgr->steering_config_map = NULL; +} + +extern "C" { + int webconfig_steering_clients_apply(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_data_t *data); +} + +// test covering NULL argument case from RDKBWIFI-199 +TEST(WifiCtrlWebconfig, SteeringClientsApplyNullArguments) +{ + ASSERT_EXIT((webconfig_steering_clients_apply(NULL, NULL), exit(0)), ::testing::ExitedWithCode(0), ".*"); + // expected that RETURN_ERR is -1, butuse the macro if possible + ASSERT_EQ(webconfig_steering_clients_apply(NULL, NULL), RETURN_ERR); +} + +TEST(WifiCtrlWebconfig, SteeringClientsApplyNullClientMap) +{ + // expected that RETURN_ERR is -1, butuse the macro if possible + webconfig_subdoc_decoded_data_t data = {0}; + data.steering_client_map = NULL; + + ASSERT_EQ(webconfig_steering_clients_apply(NULL, &data), RETURN_ERR); +} + +TEST(WifiCtrlWebconfig, SteeringClientsApplyEmptyClientMap) +{ + wifi_mgr_t *mgr = get_wifimgr_obj(); + + webconfig_subdoc_decoded_data_t data = {0}; + data.steering_client_map = hash_map_create(); + mgr->steering_client_map = data.steering_client_map; + + ASSERT_EQ(webconfig_steering_clients_apply(NULL, &data), RETURN_OK); + + mgr->steering_client_map = NULL; +} + +TEST(WifiCtrlWebconfig, SteeringClientsSameClientMap) +{ + wifi_mgr_t *mgr = get_wifimgr_obj(); + + webconfig_subdoc_decoded_data_t data = {0}; + data.steering_client_map = hash_map_create(); + mgr->steering_client_map = hash_map_create(); + + ASSERT_EQ(webconfig_steering_clients_apply(NULL, &data), RETURN_OK); + + hash_map_destroy(mgr->steering_client_map); + mgr->steering_client_map = NULL; +} + +extern "C" { + int webconfig_stats_config_apply(wifi_ctrl_t *ctrl, webconfig_subdoc_decoded_data_t *data); +} + +// test covering NULL argument case from RDKBWIFI-198 +TEST(WifiCtrlWebconfig, StatsConfigApplyNullArguments) +{ + ASSERT_EXIT((webconfig_stats_config_apply(NULL, NULL), exit(0)), ::testing::ExitedWithCode(0), ".*"); + // expected that RETURN_ERR is -1, butuse the macro if possible + ASSERT_EQ(webconfig_stats_config_apply(NULL, NULL), RETURN_ERR); +} + +TEST(WifiCtrlWebconfig, StatsConfigsApplyNullStatsConfigMap) +{ + // expected that RETURN_ERR is -1, butuse the macro if possible + webconfig_subdoc_decoded_data_t data = {0}; + data.stats_config_map = NULL; + + ASSERT_EQ(webconfig_stats_config_apply(NULL, &data), RETURN_ERR); +} + +TEST(WifiCtrlWebconfig, StatsConfigApplyEmptyStatsConfigMap) +{ + wifi_mgr_t *mgr = get_wifimgr_obj(); + + webconfig_subdoc_decoded_data_t data = {0}; + data.stats_config_map = hash_map_create(); + mgr->stats_config_map = data.stats_config_map; + + ASSERT_EQ(webconfig_stats_config_apply(NULL, &data), RETURN_OK); + + mgr->stats_config_map = NULL; +} + +TEST(WifiCtrlWebconfig, StatsConfigSameStatsConfigMap) +{ + wifi_mgr_t *mgr = get_wifimgr_obj(); + + webconfig_subdoc_decoded_data_t data = {0}; + data.stats_config_map = hash_map_create(); + mgr->stats_config_map = hash_map_create(); + + ASSERT_EQ(webconfig_stats_config_apply(NULL, &data), RETURN_OK); + + hash_map_destroy(mgr->stats_config_map); + mgr->stats_config_map = NULL; +} diff --git a/source/webconfig/wifi_decoder.c b/source/webconfig/wifi_decoder.c index 83e43defe..4e4edb34e 100644 --- a/source/webconfig/wifi_decoder.c +++ b/source/webconfig/wifi_decoder.c @@ -4845,6 +4845,13 @@ webconfig_error_t decode_wifiradiocap(wifi_platform_property_t *wifi_prop, cJSON radio_cap->rdk_radio_index = value_object->valuedouble; + /* Mode is optional */ + radio_cap->mode[0] = 0; + value_object = cJSON_GetObjectItem(object, "Mode"); + if ((value_object != NULL) && (cJSON_IsNumber(value_object) == true)) { + radio_cap->mode[0] = value_object->valuedouble; + } + /*allowed_channels*/ allowed_channels = cJSON_GetObjectItem(object, "PossibleChannels"); if (allowed_channels == NULL) { diff --git a/source/webconfig/wifi_easymesh_translator.c b/source/webconfig/wifi_easymesh_translator.c index a75e3039d..401acc32f 100644 --- a/source/webconfig/wifi_easymesh_translator.c +++ b/source/webconfig/wifi_easymesh_translator.c @@ -428,7 +428,7 @@ static webconfig_error_t translate_radio_capability_to_easymesh(wifi_platform_pr memcpy(em_ht_cap->ruid, cap_info->ruid.mac, sizeof(mac_address_t)); memcpy(em_vht_cap->ruid, cap_info->ruid.mac, sizeof(mac_address_t)); memcpy(em_he_cap->ruid, cap_info->ruid.mac, sizeof(mac_address_t)); - + cap_info->mode = radio_cap->mode[0]; // HT capabilities em_ht_cap->ht_sprt_40mhz = (radio_cap->ht_capab & (1 << 1)) ? 1 : 0; em_ht_cap->gi_sprt_40mhz = (radio_cap->ht_capab & (1 << 6)) ? 1 : 0; diff --git a/source/webconfig/wifi_encoder.c b/source/webconfig/wifi_encoder.c index 587e1a3eb..4ea6981f2 100644 --- a/source/webconfig/wifi_encoder.c +++ b/source/webconfig/wifi_encoder.c @@ -2210,6 +2210,7 @@ webconfig_error_t encode_wifiradiocap(wifi_platform_property_t *wifi_prop, cJSON cJSON_AddItemToArray(radio_obj, object); cJSON_AddNumberToObject(object, "PhyIndex", radiocap->index); cJSON_AddNumberToObject(object, "RadioIndex", radiocap->rdk_radio_index); + cJSON_AddNumberToObject(object, "Mode", radiocap->mode[0]); for (freq_band_count = 0; freq_band_count < radiocap->numSupportedFreqBand; freq_band_count++) { (void)memcpy(channels_list, radiocap->channel_list[freq_band_count].channels_list, sizeof(*channels_list) * radiocap->channel_list[freq_band_count].num_channels);