diff --git a/wifi-services/Makefile b/wifi-services/Makefile index 3c806fad3..b57f7b86a 100644 --- a/wifi-services/Makefile +++ b/wifi-services/Makefile @@ -23,7 +23,6 @@ PKG_CONFIG_DEPENDS := \ PKG_BUILD_DEPENDS := libwifi include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/iopsys/bbfdm/bbfdm.mk MAKE_FLAGS += \ CFLAGS="$(TARGET_CFLAGS) -Wall" @@ -49,7 +48,6 @@ endef define Package/wifi-services/install $(INSTALL_DIR) $(1)/usr/lib $(CP) $(PKG_BUILD_DIR)/sta-ratings/libwifi-sta-ratings.so $(1)/usr/lib/ - $(BBFDM_INSTALL_MS_PLUGIN) ./files/QoERating_Extension.json $(1) wifidmd endef $(eval $(call BuildPackage,wifi-services)) diff --git a/wifi-services/files/QoERating_Extension.json b/wifi-services/files/QoERating_Extension.json deleted file mode 100644 index 6e6238b4f..000000000 --- a/wifi-services/files/QoERating_Extension.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "json_plugin_version": 2, - "Device.WiFi.AccessPoint.{i}.AssociatedDevice.{i}.": { - "type": "object", - "protocols": [ - "cwmp", - "usp" - ], - "access": false, - "array": true, - "{BBF_VENDOR_PREFIX}QoERating": { - "type": "string", - "read": true, - "write": false, - "protocols": [ - "cwmp", - "usp" - ], - "default": "-1.0", - "datatype": "string", - "mapping": [ - { - "data": "@Parent", - "type": "json", - "key": "rating" - } - ] - } - } -} - diff --git a/wifimngr/Config.in b/wifimngr/Config.in index 6a9477b68..d03f23d70 100644 --- a/wifimngr/Config.in +++ b/wifimngr/Config.in @@ -6,5 +6,18 @@ config WIFIMNGR_CACHE_SCANRESULTS bool "Cache scan results" default y +config WIFIMNGR_BUILD_TR181_PLUGIN + bool "Build TR-181 plugin module (responsible for Device.WiFi.{Radio,SSID,AccessPoint,EndPoint})" + default y + +config WIFIMNGR_VENDOR_EXTENSIONS + bool "Enable vendor extensions for WiFi legacy datamodel" + default y + +config WIFIMNGR_VENDOR_PREFIX + depends on WIFIMNGR_VENDOR_EXTENSIONS + string "Vendor Prefix for WiFi legacy datamodel extensions" + default "" + endmenu endif diff --git a/wifimngr/Makefile b/wifimngr/Makefile index 72a58b5b4..0384b4e8f 100644 --- a/wifimngr/Makefile +++ b/wifimngr/Makefile @@ -30,12 +30,14 @@ PKG_BUILD_DEPENDS := libwifi include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/cmake.mk +include $(TOPDIR)/feeds/iopsys/bbfdm/bbfdm.mk define Package/wifimngr SECTION:=utils CATEGORY:=Utilities TITLE:=WiFi status and configration utility DEPENDS:=+libwifiutils +libwifi +libuci +libubox +ubus +libnl-genl + DEPENDS+=+libbbfdm-api +libbbfdm-ubus endef define Package/wifimngr/description @@ -55,10 +57,29 @@ ifeq ($(CONFIG_WIFIMNGR_CACHE_SCANRESULTS),y) TARGET_CFLAGS += -DWIFI_CACHE_SCANRESULTS endif +ifeq ($(CONFIG_WIFIMNGR_BUILD_TR181_PLUGIN),y) +CMAKE_OPTIONS += -DWIFIMNGR_BUILD_TR181_PLUGIN=ON +ifeq ($(CONFIG_WIFIMNGR_VENDOR_EXTENSIONS),y) +TARGET_CFLAGS += -DWIFIMNGR_VENDOR_EXTENSIONS +endif +endif + +ifeq ($(CONFIG_WIFIMNGR_VENDOR_PREFIX),"") +CMAKE_OPTIONS += -DBBF_VENDOR_PREFIX:String="$(CONFIG_BBF_VENDOR_PREFIX)" +else +CMAKE_OPTIONS += -DBBF_VENDOR_PREFIX:String="$(CONFIG_WIFIMNGR_VENDOR_PREFIX)" +endif + define Package/wifimngr/install - $(CP) ./files/* $(1)/ + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/etc/init.d/wifimngr $(1)/etc/init.d $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) $(PKG_BUILD_DIR)/wifimngr $(1)/usr/sbin/ +ifeq ($(CONFIG_WIFIMNGR_BUILD_TR181_PLUGIN),y) + $(INSTALL_DIR) $(1)/etc/wifimngr + $(INSTALL_BIN) ./files/etc/wifimngr/bbf_config_reload.sh $(1)/etc/wifimngr + $(BBFDM_REGISTER_SERVICES) ./bbfdm_service.json $(1) $(PKG_NAME) +endif endef define Package/wifimngr/config diff --git a/wifimngr/bbfdm_service.json b/wifimngr/bbfdm_service.json new file mode 100644 index 000000000..a99ee12bb --- /dev/null +++ b/wifimngr/bbfdm_service.json @@ -0,0 +1,47 @@ +{ + "daemon": { + "enable": "1", + "service_name": "wifimngr", + "unified_daemon": true, + "services": [ + { + "parent_dm": "Device.WiFi.", + "object": "Radio" + }, + { + "parent_dm": "Device.WiFi.", + "object": "SSID" + }, + { + "parent_dm": "Device.WiFi.", + "object": "AccessPoint" + }, + { + "parent_dm": "Device.WiFi.", + "object": "NeighboringWiFiDiagnostic" + }, + { + "parent_dm": "Device.WiFi.", + "object": "EndPoint" + }, + { + "parent_dm": "Device.WiFi.", + "object": "Reset()" + } + ], + "config": { + "loglevel": "3" + }, + "apply_handler": { + "uci": [ + { + "file": [ + "wireless", + "mapcontroller" + ], + "external_handler": "/etc/wifimngr/bbf_config_reload.sh" + } + ] + } + } +} diff --git a/wifimngr/files/etc/wifimngr/bbf_config_reload.sh b/wifimngr/files/etc/wifimngr/bbf_config_reload.sh new file mode 100755 index 000000000..39208db30 --- /dev/null +++ b/wifimngr/files/etc/wifimngr/bbf_config_reload.sh @@ -0,0 +1,325 @@ +#!/bin/sh + +# Script: bbf_config_reload.sh +# Description: +# Reloads WiFi configurations based on provided arguments. +# +# Usage: +# sh bbf_config_reload.sh [wireless] [mapcontroller] +# +# Input arguments: +# wireless Reload only wireless configuration +# mapcontroller Reload only mapcontroller configuration +# +# Actions: +# - If both "wireless" and "mapcontroller" are specified: +# -> Reload mapcontroller (send SIGHUP) +# - If only "wireless" is specified: +# -> Commit wireless configuration via ubus +# - If only "mapcontroller" is specified: +# -> Reload mapcontroller (send SIGHUP) +# - If no valid arguments are provided: +# -> Do nothing + +. /lib/functions.sh +. /usr/share/libubox/jshn.sh + +MAPCONTROLLER=0 +WIRELESS=0 +MAX_RETRIES=15 + +info() { + echo "${@}" | logger -t bbf.config.wifi.reload -p info +} + +debug() { + echo "${@}" +} + +json_add_aps() { + json_add_object + json_add_string ssid "$1" + json_add_string band "$2" + json_add_string encryption "$3" + json_add_string key "$4" + json_add_string ifname "$5" + json_close_object +} + +parse_mapcontroller_ap() { + local section="$1" + + config_get type "$section" type "fronthaul" + [ "$type" = "fronthaul" ] || return 0 + + config_get enabled "$section" enabled 1 + [ "$enabled" = "1" ] || return 0 + + config_get ssid "$section" ssid + [ -n "$ssid" ] || return 0 + + config_get band "$section" band + [ -n "$band" ] || return 0 + + case "$band" in + 2|5|6) ;; + *) return 0 ;; + esac + + config_get encryption "$section" encryption "none" + config_get key "$section" key + + json_add_aps "$ssid" "$band" "$encryption" "$key" "" + debug "mapcontroller AP added: ssid=|$ssid| band=|$band| encryption=|$encryption| key=|$key|" +} + +parse_wireless_ap() { + local section="$1" + + config_get disabled "$section" disabled 0 + [ "$disabled" = "1" ] && return 0 + + config_get multi_ap "$section" multi_ap 0 + case "$multi_ap" in + 1|2) return 0 ;; + esac + + config_get ssid "$section" ssid + [ -n "$ssid" ] || return 0 + + config_get device "$section" device + [ -n "$device" ] || return 0 + + config_get band "$device" band + case "$band" in + 2g) band="2" ;; + 5g) band="5" ;; + 6g) band="6" ;; + *) return 0 ;; + esac + + config_get radio_disabled "$device" disabled 0 + [ "$radio_disabled" = "1" ] && return 0 + + config_get encryption "$section" encryption "none" + config_get key "$section" key + + for try in $(seq 1 "$MAX_RETRIES"); do + config_get ifname "$section" ifname + [ -n "$ifname" ] && break + debug "FAIL: no ifname found for ssid=|$ssid| band=|$band| (try $try/$MAX_RETRIES)" + sleep 1 + config_load wireless + done + + if [ -z "$ifname" ]; then + info "FAIL: could not match wireless AP with ssid=|$ssid| band=|$band| after $MAX_RETRIES tries" + return O + fi + + json_add_aps "$ssid" "$band" "$encryption" "$key" "$ifname" + debug "wireless AP added: ssid=|$ssid| band=|$band| ifname=|$ifname|" +} + +match_ap_to_wireless_interface() { + local section="$1" + + config_get disabled "$section" disabled 0 + [ "$disabled" = "1" ] && return 0 + + config_get multi_ap "$section" multi_ap 0 + [ "$multi_ap" = "2" ] || return 0 + + config_get ssid "$section" ssid + [ "$ssid" = "$SSID" ] || return 0 + + config_get device "$section" device + [ -n "$device" ] || return 0 + + config_get band "$device" band + case "$band" in + 2g) band="2" ;; + 5g) band="5" ;; + 6g) band="6" ;; + *) return 0 ;; + esac + [ "$band" = "$BAND" ] || return 0 + + config_get radio_disabled "$device" disabled 0 + [ "$radio_disabled" = "1" ] && RADIO_DISABLED=1 && return 0 + + config_get key "$section" key + [ -n "$KEY" ] && [ "$key" != "$KEY" ] && return 0 + + config_get encryption "$section" encryption "none" + [ -n "$ENCRYPTION" ] && [ "$encryption" != "$ENCRYPTION" ] && return 0 + + config_get MATCHED_IFNAME "$section" ifname +} + +match_aps_to_wireless_interfaces() { + config_load wireless + + json_get_keys indices + + for i in $indices; do + json_select "$i" + + json_get_var SSID ssid + json_get_var BAND band + json_get_var ENCRYPTION encryption + json_get_var KEY key + + debug "matching AP[$i]: ssid=|$SSID| band=|$BAND| encryption=|$ENCRYPTION| key=|$KEY|" + + MATCHED_IFNAME="" + RADIO_DISABLED=0 + + for try in $(seq 1 "$MAX_RETRIES"); do + config_foreach match_ap_to_wireless_interface wifi-iface + + if [ -n "$MATCHED_IFNAME" ]; then + json_add_string ifname "$MATCHED_IFNAME" + debug "matched AP[$i]: ssid=|$SSID| band=|$BAND| -> ifname=|$MATCHED_IFNAME|" + break + fi + + [ "$RADIO_DISABLED" = "1" ] && break + + sleep 1 + config_load wireless + done + + if [ -z "$MATCHED_IFNAME" ] && [ "$RADIO_DISABLED" != "1" ]; then + info "FAIL: no match for AP[$i]: ssid=|$SSID| band=|$BAND| after $MAX_RETRIES tries" + fi + + json_select .. + done +} + +verify_aps_runtime_state() { + json_get_keys indices + + for i in $indices; do + json_select "$i" + + json_get_var ifname ifname + json_get_var ssid ssid + json_get_var band band + + [ -z "$ifname" ] && json_select .. && continue + + debug "validating runtime AP[$i]: ssid=|$ssid| band=|$band| ifname=|$ifname|" + + case "$band" in + 2) bandstr="2.4GHz" ;; + 5) bandstr="5GHz" ;; + 6) bandstr="6GHz" ;; + *) json_select .. && continue ;; + esac + + ok=0 + for try in $(seq 1 "$MAX_RETRIES"); do + json="$(ubus call wifi.ap."$ifname" status 2>/dev/null)" + + if [ -z "$json" ]; then + debug "FAIL: empty ubus response for wifi.ap.$ifname status (try $try/$MAX_RETRIES)" + sleep 2 + continue + fi + + ubus_ssid="$(echo "$json" | jsonfilter -q -e '@.ssid')" + ubus_band="$(echo "$json" | jsonfilter -q -e '@.band')" + + [ "$ubus_ssid" = "$ssid" -a "$ubus_band" = "$bandstr" ] && { + ok=1 + break + } + + sleep 2 + done + + [ "$ok" -ne 1 ] && info "FAIL: runtime validation failed for AP[$i]: ssid=|$ssid| band=|$band| ifname=|$ifname|" + json_select .. + debug "runtime validation completed for AP[$i]: ssid=|$ssid| band=|$band| ifname=|$ifname|" + done +} + +validate_mapcontroller_changes() { + json_init + json_add_array aps + config_load mapcontroller + config_foreach parse_mapcontroller_ap ap + match_aps_to_wireless_interfaces + verify_aps_runtime_state + json_cleanup +} + +validate_wireless_changes() { + json_init + json_add_array aps + config_load wireless + config_foreach parse_wireless_ap wifi-iface + verify_aps_runtime_state + json_cleanup +} + +reload_mapcontroller() { + pid="$(pidof mapcontroller)" + if [ -n "$pid" ]; then + info "Reloading mapcontroller (PID: $pid)..." + kill -SIGHUP "$pid" + sleep 5 + validate_mapcontroller_changes + else + info "Warning: mapcontroller process not found" + fi +} + +reload_wireless() { + info "Reloading wireless config..." + ubus call uci commit '{"config":"wireless"}' + sleep 5 + validate_wireless_changes +} + +dmmap_commit_new_aps() { + DMAP_PATH="uci -q -c /etc/bbfdm/dmmap" + for sec in $($DMAP_PATH show WiFi | grep "=AccessPoint" | cut -d. -f2 | cut -d= -f1); do + is_new=$($DMAP_PATH get WiFi.${sec}.__is_new__) + [ "$is_new" = "1" ] || continue + + sec_name=$($DMAP_PATH get WiFi.${sec}.__section_name__) + case "$sec_name" in + wireless.*) MAPCONTROLLER=0 ;; + esac + $DMAP_PATH delete WiFi.${sec}.__is_new__ + done + + $DMAP_PATH commit WiFi +} + +for arg in "$@"; do + case "$arg" in + wireless) WIRELESS=1 ;; + mapcontroller) MAPCONTROLLER=1 ;; + *) + info "Unknown option: $arg" + exit 1 + ;; + esac +done + +dmmap_commit_new_aps + +if [ "$MAPCONTROLLER" -eq 1 ]; then + reload_mapcontroller +elif [ "$WIRELESS" -eq 1 ]; then + reload_wireless +else + info "No valid arguments provided." + exit 1 +fi + +exit 0