You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

949 lines
36 KiB
Bash

#!/bin/sh
# Copyright (c) 2015-2018 Qualcomm Technologies, Inc.
#
# All Rights Reserved.
# Confidential and Proprietary - Qualcomm Technologies, Inc.
#
# 2015-2016 Qualcomm Atheros, Inc.
#
# All Rights Reserved.
# Qualcomm Atheros Confidential and Proprietary.
WIFIMON_DEBUG_OUTOUT=0
# Set this to a filename to log all commands executed.
# The output of relevant commands will be appended to the file.
WIFIMON_DEBUG_COMMAND_FILE=
WIFIMON_STATE_NOT_ASSOCIATED='NotAssociated'
WIFIMON_STATE_AUTOCONFIG_IN_PROGRESS='AutoConfigInProgress'
WIFIMON_STATE_MEASURING='Measuring'
WIFIMON_STATE_WPS_TIMEOUT='WPSTimeout'
WIFIMON_STATE_ASSOC_TIMEOUT='AssocTimeout'
WIFIMON_STATE_RE_BACKHAUL_GOOD='RE_BackhaulGood'
WIFIMON_STATE_RE_BACKHAUL_FAIR='RE_BackhaulFair'
WIFIMON_STATE_RE_BACKHAUL_POOR='RE_BackhaulPoor'
WIFIMON_STATE_RE_SWITCH_BSTA='RE_SwitchingBSTA'
WIFIMON_PIPE_NAME='/var/run/repacd.pipe'
. /lib/functions.sh
. /lib/functions/whc-network.sh
# State information
sta_iface_24g='' sta_iface_24g_config_name=''
sta_iface_5g='' sta_iface_5g_config_name='' unknown_ifaces=0
assoc_timeout_logged=0 wps_timeout_logged=0
wps_in_progress=0 wps_start_time=''
wps_stabilization=0 wps_assoc_count=0
assoc_start_time='' last_assoc_state=0
ping_running=0 last_ping_gw_ip=
rssi_num=0 rssi_filename=
bsta_max_preference=
# Config parameters
rssi_samples=''
backhaul_rssi_2='' backhaul_rssi_5='' backhaul_rssi_offset=''
min_wps_assoc=
assoc_timeout='' wps_timeout=''
measuring_cnt=0 measuring_attempts=0
force_bsses_down_on_all_bsta_switches=0
cnt_5g_attempts=0 max_5g_attempts=0
# Emit a message at debug level.
# input: $1 - the message to log
__repacd_wifimon_debug() {
local stderr=''
if [ "$WIFIMON_DEBUG_OUTOUT" -gt 0 ]; then
stderr='-s'
fi
logger $stderr -t repacd.wifimon -p user.debug "$1"
}
# Log the output of a command to a file (when enabled).
# This is a nop unless WIFIMON_DEBUG_COMMAND_FILE is set.
# input: $1 - command output to log
__repacd_wifimon_dump_cmd() {
if [ -n "$WIFIMON_DEBUG_COMMAND_FILE" ]; then
touch $WIFIMON_DEBUG_COMMAND_FILE
{ date; echo "$1"; echo; } >> $WIFIMON_DEBUG_COMMAND_FILE
fi
}
# Emit a message at info level.
__repacd_wifimon_info() {
local stderr=''
if [ "$WIFIMON_DEBUG_OUTOUT" -gt 0 ]; then
stderr='-s'
fi
logger $stderr -t repacd.wifimon -p user.info "$1"
}
# Obtain a timestamp from the system.
#
# These timestamps will be monontonically increasing and be unaffected by
# any time skew (eg. via NTP or manual date commands).
#
# output: $1 - the timestamp as an integer (with any fractional time truncated)
__repacd_wifimon_get_timestamp() {
timestamp=$(cut -d' ' -f1 < /proc/uptime | cut -d. -f 1)
eval "$1=$timestamp"
}
# Terminate any background ping that may be running.
# If no background pings are running, this will be a nop.
__repacd_stop_ping() {
if [ "$ping_running" -gt 0 ]; then
kill "$(jobs -p)"
ping_running=0
__repacd_wifimon_debug "Stopped ping to GW IP $last_ping_gw_ip"
fi
if [ -n "$rssi_filename" ]; then
# Clean up the temporary file
rm -f $rssi_filename
rssi_filename=
fi
}
# Start a background ping to the gateway address (if it can be resolved).
# This helps ensure the RSSI values are updated (as firmware will not report
# updates if only beacons are being received on the STA interface).
# input: $1 - network: the name of the network being managed
# return: 0 if the ping was started or is already running; otherwise 1
__repacd_start_ping() {
gw_ip=$(route -n | grep ^0.0.0.0 | grep "br-$1" | awk '{print $2}')
if [ -n "$gw_ip" ]; then
if [ ! "$gw_ip" = "$last_ping_gw_ip" ]; then
# First need to kill the existing one due to the IP change.
__repacd_stop_ping
# This will leave ping_running set to 0.
fi
if [ "$ping_running" -eq 0 ]; then
__repacd_wifimon_debug "Pinging GW IP $gw_ip"
# Unfortunately the busybox ping command does not support an
# interval. Thus, we can only ping once per second so there will
# only be a handful of measurements over the course of our RSSI
# sampling.
ping "$gw_ip" > /dev/null &
ping_running=1
last_ping_gw_ip=$gw_ip
fi
# Ping is running now or was started.
return 0
fi
__repacd_wifimon_info "Failed to resolve GW when starting ping; will re-attempt"
return 1
}
# Determine if the gateway is reachable.
#
# Ideally this would be limited to only the 5 GHz STA interface, but there
# is no good way to do this (since packets would need to be received on the
# bridge interface).
#
# return: 0 if the gateway is reachable; otherwise 1
__repacd_is_gw_reachable() {
if [ -n "$last_ping_gw_ip" ]; then
if ping -c 1 -W 1 "${last_ping_gw_ip}" > /dev/null; then
return 0
fi
fi
# Gateway is unknown or is not reachable
return 1
}
# Determine if the STA interface named is current associated and active.
#
# input: $1 - sta_iface: the name of the interface (eg. ath01)
# return: 0 if associated; 1 if not associated or empty interface name
__repacd_wifimon_is_active_assoc() {
local sta_iface=$1
if [ -n "$sta_iface" ]; then
local assoc_str=
assoc_str=$(iwconfig "$sta_iface")
__repacd_wifimon_dump_cmd "State of $sta_iface: $assoc_str"
if echo "$assoc_str" | grep 'Access Point: ' | grep -v 'Not-Associated' > /dev/null; then
return 0
else
return 1
fi
else
# An unknown STA interface is considered not associated.
return 1
fi
}
# Determine if the STA interface named is current associated.
#
# Note that for the purposes of this function, an empty interface name is
# considered associated. This is done because in some configurations, only
# one interface is enabled.
#
# input: $1 - sta_iface: the name of the interface (eg. ath01)
# return: 0 if associated or if the interface name is empty; otherwise 1
__repacd_wifimon_is_assoc() {
local sta_iface=$1
if [ -n "$sta_iface" ];
then
if __repacd_wifimon_is_active_assoc "$sta_iface"; then
return 0
else
return 1
fi
else
# An unknown STA interface is considered associated.
return 0
fi
}
# Determine if the STA association is stable enough to be able to start
# the next step of the process.
# return: 0 if the association is stable; non-zero if it is not yet deemed
# stable
__repacd_wifimon_is_assoc_stable() {
if [ "$wps_stabilization" -gt 0 ]; then
if [ "$wps_assoc_count" -ge "$min_wps_assoc" ]; then
return 0
else
return 1
fi
else
# No stabilization in progress
return 0
fi
}
# Determine if the STA is associated and update the state accordingly.
# input: $1 - network: the name of the network being managed
# input: $2 - cur_re_mode: the currently configured range extender mode
# input: $3 - cur_re_submode: the currently configured range extender sub-mode
# input: $4 - whether this is a check during init for a restart triggered
# by mode switching
# output: $5 - state: the variable to update with the new state name (if there
# was a change)
# output: $6 - re_mode: the desired range extender mode
# output: $7 - re_submode: the desired range extender sub-mode
# return: 0 if associated; otherwise 1
__repacd_wifimon_check_associated() {
local network=$1
local associated=0
if __repacd_wifimon_is_assoc $sta_iface_24g \
&& __repacd_wifimon_is_assoc $sta_iface_5g; then
associated=1
fi
if [ "$associated" -gt 0 ]; then
# Only update the LED state if we transitioned from not associated
# to associated.
if [ "$last_assoc_state" -eq 0 ]; then
if [ "$wps_in_progress" -gt 0 ]; then
# If WPS was triggered, it could take some time for the
# interfaces to settle into their final state. Thus, update
# the start time for the measurement to the point at which
# the WPS button was pressed.
assoc_start_time=$wps_start_time
# Clear this as we only want to extend the association time
# for this one instance. All subsequent ones should be based
# on the time we detect a disassociation (unless WPS is
# triggered again).
wps_start_time=''
# Clear this flag so that we now use the association timer
# instead of the WPS one.
wps_in_progress=0
wps_stabilization=1
fi
if [ "$wps_stabilization" -gt 0 ]; then
wps_assoc_count=$((wps_assoc_count + 1))
__repacd_wifimon_debug "Assoc post WPS (#$wps_assoc_count)"
fi
if __repacd_wifimon_is_assoc_stable; then
# Assume we are going into the measuring state. This may be
# overruled if we decide to switch to a different bSTA
# interface.
eval "$5=$WIFIMON_STATE_MEASURING"
assoc_start_time=''
last_assoc_state=1
wps_stabilization=0
# Restart the measurements. We do not remember any past
# ones as they might not reflect the current state (eg.
# if the root AP was moved).
rssi_num=0
if [ "$wps_stabilization" -gt 0 ]; then
# Once WPS completes, switch to the most preferred bSTA.
local sta_iface_config=''
if [ -n "$sta_iface_24g" ]; then
sta_iface_config="$sta_iface_24g_config_name"
else
sta_iface_config="$sta_iface_5g_config_name"
fi
# Be optimistic that the most preferred bSTA will have a
# good link, so don't force the BSSes down.
local force_bsses_down=0
__repacd_wifimon_select_next_bsta "$sta_iface_config" \
$force_bsses_down \
"$WIFIMON_STATE_MEASURING" "$5"
# Although we're stable, since in most cases we're going to
# change the bSTA radio, we don't want to proceed into the
# measuring state below. If it turns out we didn't switch
# to a new radio, we'll pick up the measurements in the
# next iteration.
return 0
fi
else
# Pretend like we are not associated since we need it to be
# stable.
return 1
fi
fi
# Association is considered stable. Measure the link RSSI.
if [ "$rssi_num" -le "$rssi_samples" ] && \
__repacd_start_ping "$network"; then
__repacd_wifimon_measure_link "$network" "$5"
fi
return 0
elif [ "$wps_in_progress" -eq 0 ] && [ "$wps_stabilization" -eq 0 ]; then
# Record the first time we detected ourselves as not being associated.
# This will drive a timer in the check function that will change the
# state if we stay disassociated for too long.
if [ -z "$assoc_start_time" ]; then
__repacd_wifimon_get_timestamp assoc_start_time
fi
last_assoc_state=0
eval "$5=$WIFIMON_STATE_NOT_ASSOCIATED"
elif [ "$wps_in_progress" -gt 0 ]; then
if [ "$wps_timeout_logged" -eq 0 ] && [ "$assoc_timeout_logged" -eq 0 ]; then
# Suppress logs after we've timed out
__repacd_wifimon_debug "Auto config in progress - not assoc"
fi
wps_assoc_count=0
fi
# Not associated and WPS is in progress. No LED update.
return 1
}
# Find the median from the samples file.
# This is a crude way to compute the median when the number of
# samples is odd. It is not strictly correct for an even number
# of samples since it does not compute the average of the two
# samples in the middle and rather just takes the lower one, but
# this should be sufficient for our purposes. The average is not
# performed due to the values being on the logarithmic scale and
# because shell scripts do not directly support floating point
# arithmetic.
# input: $1 - Samples filename
# input: $2 - Number of samples in the samples file
# output: $3 - computed Median
__repacd_wifimon_compute_median() {
local median median_index
local samples_filename="$1"
median_index=$((($2 + 1) / 2))
median=$(sort -n < "$samples_filename" | head -n $median_index | tail -n 1)
eval "$3=$median"
}
# Measure the RSSI to the serving AP and update the state accordingly.
# input: $1 - network: the name of the network being monitored
# output: $2 - state: the variable to update with the new state name (if there
# was a change)
__repacd_wifimon_measure_link() {
local rssi
if ! __repacd_is_gw_reachable; then
if [ -n "$last_ping_gw_ip" ]; then
__repacd_wifimon_debug "GW ${last_ping_gw_ip} not reachable"
else
__repacd_wifimon_debug "GW unknown"
fi
return
fi
if [ "$rssi_num" -eq 0 ]; then
if [ "$measuring_cnt" -gt 0 ]; then
__repacd_wifimon_debug "Measurement failed attempt # $measuring_cnt"
fi
measuring_cnt=$((measuring_cnt + 1))
fi
if [ "$measuring_cnt" -gt "$measuring_attempts" ]; then
# Could not complete measurements with this interface as a bSTA.
#
# Try switching to the next most preferred interface.
# Since this interface was so flaky, the next one might be too, so
# tell the fronthaul manager to force the BSSes down at the next
# startup.
local force_bsses_down=1
__repacd_wifimon_select_next_bsta "$sta_iface_config_name" \
$force_bsses_down "$WIFIMON_STATE_RE_BACKHAUL_POOR" "$2"
return
fi
# Currently only one STA interface is allocated at a time. Determine the
# active one so that it can be used to check the RSSI.
local sta_iface=''
local rssi_threshold=''
local rssi_led_state='' # state of LEDs if above RSSI threshold
if [ -n "$sta_iface_5g" ]; then
sta_iface="$sta_iface_5g"
sta_iface_config_name="$sta_iface_5g_config_name"
rssi_threshold="$backhaul_rssi_5"
rssi_led_state="$WIFIMON_STATE_RE_BACKHAUL_GOOD"
else
sta_iface="$sta_iface_24g"
sta_iface_config_name="$sta_iface_24g_config_name"
rssi_threshold="$backhaul_rssi_2"
rssi_led_state="$WIFIMON_STATE_RE_BACKHAUL_FAIR"
fi
rssi=$(iwconfig $sta_iface | grep 'Signal level' | awk -F'=' '{print $3}' | awk '{print $1}')
# We explicitly ignore clearly bogus values. -95 dBm has been seen in
# some instances where the STA is not associated by the time the RSSI
# check is done. The check against 0 tries to guard against scenarios
# where the firmware has yet to report an RSSI value (although this may
# never happen if the RSSI gets primed through the association messaging).
if [ "$rssi" -gt -95 ] && [ "$rssi" -lt 0 ]; then
if [ "$rssi_num" -lt "$rssi_samples" ]; then
__repacd_wifimon_debug "RSSI sample #$rssi_num = $rssi dBm"
# Ignore the very first sample since it is taken at the same time
# the ping is started (and thus the RSSI might not have been
# updated).
if [ "$rssi_num" -eq 0 ]; then
rssi_filename=$(mktemp /tmp/repacd-rssi.XXXXXX)
else
# Not the first sample
echo "$rssi" >> "$rssi_filename"
fi
rssi_num=$((rssi_num + 1))
elif [ "$rssi_num" -eq "$rssi_samples" ]; then
__repacd_wifimon_debug "RSSI sample #$rssi_num = $rssi dBm"
# We will take one more sample and then draw the conclusion.
# No further measurements will be taken (although this may be
# changed in the future).
echo "$rssi" >> "$rssi_filename"
# We got the required number of samples, now derive the median rssi.
local rssi_median
__repacd_wifimon_compute_median "$rssi_filename" $rssi_num rssi_median
__repacd_wifimon_debug "Median RSSI = $rssi_median dBm"
__repacd_wifimon_debug "RSSI threshold = $rssi_threshold dBm"
measuring_cnt=0
rssi_num=$((rssi_num + 1)) # to prevent future samples
# We have our measurement, so the ping is no longer needed.
__repacd_stop_ping
# In case we disassociate after this, we will want to start the
# association timer again, so clear our state of the last time we
# started it so that it can be started afresh upon disassociation.
assoc_start_time=''
if [ "$rssi_median" -gt "$rssi_threshold" ]; then
local keep_24g_bsta_threshold=$((rssi_threshold + backhaul_rssi_offset))
if [ "$sta_iface" = "$sta_iface_24g" ]; then
if [ "$cnt_5g_attempts" -ge "$max_5g_attempts" ] ||
[ "$rssi_median" -lt "$keep_24g_bsta_threshold" ]; then
eval "$2=$rssi_led_state"
else
# 2.4 GHz is good enough that 5 GHz might be viable. Try it again.
__repacd_wifimon_debug "2.4 GHz good; considering 5 GHz"
# Let's be optimistic that 5 GHz will be good enough
# and thus we should leave the BSSes up at startup.
local force_bsses_down=0
__repacd_wifimon_select_next_bsta "$sta_iface_config_name" \
$force_bsses_down "$rssi_led_state" "$2"
return
fi
else
# 5 GHz bSTA with sufficient; we are done
eval "$2=$rssi_led_state"
fi
elif [ "$sta_iface" = "$sta_iface_24g" ]; then
__repacd_wifimon_debug "2.4 GHz bSTA weak; not re-attempting 5 GHz"
eval "$2=$WIFIMON_STATE_RE_BACKHAUL_POOR"
else
# Try next best bSTA radio
__repacd_wifimon_debug "5 GHz bSTA too weak; trying next radio"
# Until we know we can get a good bSTA link, let's be
# conservative and bring the BSSes down at startup.
local force_bsses_down=1
__repacd_wifimon_select_next_bsta "$sta_iface_config_name" \
$force_bsses_down "$WIFIMON_STATE_RE_BACKHAUL_POOR" "$2"
return
fi
fi
fi
}
# Determine the radio that is next most preferred radio.
#
# If the current radio's preference value is not set, pick the highest
# preference radio.
#
# input: $1 config: section name
# input: $2 cur_pref: the preference level for the current bSTA
# output: $3 preferred_radio: the radio with the highest preference, but below
# the cur_pref value if it is set
__repacd_wifimon_resolve_next_bsta_radio() {
local config="$1"
local cur_pref="$2"
local bsta_preference=''
config_get bsta_preference "$config" repacd_map_bsta_preference 0
# Skip radios that have no preference set. Maybe the OEM never wants
# to use that radio.
if [ -n "$bsta_preference" ]; then
if [ -n "$cur_pref" ]; then
if [ "$bsta_preference" -lt "$cur_pref" ] &&
[ "$bsta_preference" -gt "$bsta_max_preference" ]; then
eval "$3=$config"
bsta_max_preference="$bsta_preference"
fi
else
if [ "$bsta_preference" -gt "$bsta_max_preference" ]; then
eval "$3=$config"
bsta_max_preference="$bsta_preference"
fi
fi
fi
}
# Mark the desired radio as selected for the bSTA.
#
# If a radio is marked as selected (using the repacd_map_bsta_selected config
# option), it will be used. If instead none is marked, the radio with the
# highest repacd_map_bsta_pref value will be used.
#
# input: $1 config: section name
# input: $2 selected_radio: the radio that should be selected
__repacd_wifimon_select_bsta_radio() {
local config="$1"
local selected_radio="$2"
if [ "$config" = "$selected_radio" ]; then
uci_set wireless "$config" repacd_map_bsta_selected '1'
else
uci_set wireless "$config" repacd_map_bsta_selected '0'
fi
}
# Update the radio on which to instantiate the bSTA.
#
# If the currently selected bSTA is 2.4 GHz, select the highest priority radio.
# Otherwise, select the highest priority radio that is less than the current
# priority.
#
# input: $1 - config: the name of the config section for the bSTA
# input: $2 - force_bsses_down: whether to force the BSSes down on the next
# startup
# input: $3 - state_no_bsta_radios: the state to transition into if there are
# no other bSTA radios to switch to
# output: $4 - state: the variable to update with the new state name (if there
# was a change)
__repacd_wifimon_select_next_bsta() {
local config="$1"
local force_bsses_down="$2"
local state_no_bsta_radios="$3"
# Resolve the current preference value
local device
config_load wireless
config_get device "$config" device
local cur_pref
config_get cur_pref "$device" repacd_map_bsta_preference
if [ -n "$sta_iface_24g" ]; then
# We want to take the maximum one
cur_pref=''
fi
local preferred_radio=''
bsta_max_preference=0
config_foreach __repacd_wifimon_resolve_next_bsta_radio wifi-device \
"$cur_pref" preferred_radio
if [ "$device" != "$preferred_radio" ]; then
__repacd_wifimon_debug "Selected $preferred_radio as next bSTA"
# If switching from 5 GHz to 2.4 GHz, increment the count to record we
# have tried all 5 GHz bSTAs. The assumption here is that 2.4 GHz will
# always come after 5 GHz in the preference order.
if [ -n "$sta_iface_5g" ] && ! whc_is_5g_radio "$preferred_radio"; then
cnt_5g_attempts=$((cnt_5g_attempts + 1))
uci_set repacd MAPWiFiLink '5gAttemptsCount' "$cnt_5g_attempts"
uci_commit repacd
__repacd_wifimon_debug "Completed 5 GHz bSTA attempt #$cnt_5g_attempts"
fi
config_foreach __repacd_wifimon_select_bsta_radio wifi-device \
"$preferred_radio"
uci_commit wireless
if [ "$force_bsses_down_on_all_bsta_switches" -gt 0 ]; then
force_bsses_down=1
fi
__repacd_wifimon_debug "Updating ForceDownOnStart to $force_bsses_down"
uci_set repacd FrontHaulMgr ForceDownOnStart "$force_bsses_down"
uci_commit repacd
eval "$4=$WIFIMON_STATE_RE_SWITCH_BSTA"
else
__repacd_wifimon_debug "No other bSTA radios available"
eval "$4=$state_no_bsta_radios"
fi
}
# Determine if a provided amount of time has elapsed.
# input: $1 - start_time: the timestamp (in seconds)
# input: $2 - duration: the amount of time to check against (in seconds)
# return: 0 on timeout; non-zero if no timeout
__repacd_wifimon_is_timeout() {
local start_time=$1
local duration=$2
# Check if the amount of elapsed time exceeds the timeout duration.
local cur_time
__repacd_wifimon_get_timestamp cur_time
local elapsed_time=$((cur_time - start_time))
if [ "$elapsed_time" -gt "$duration" ]; then
return 0
fi
return 1
}
# Check whether the given interface is the STA interface on the desired
# network and the desired band.
#
# input: $1 - config: the name of the interface config section
# input: $2 - network: the name of the network to which the STA interface
# must belong to be matched
# output: $3 - iface: the resolved STA interface name on 2.4 GHz (if found)
# output: $4 - iface_config_name: the resolved name of the config section
# for the STA interface on 2.4 GHz (if found)
# output: $5 - iface: the resolved STA interface name on 5 GHz (if found)
# output: $6 - iface_config_name: the resolved name of the config section
# for the STA interface on 5 GHz (if found)
# output: $7 - unknown_ifaces: whether any Wi-Fi interfaces are as yet
# unknown (in terms of their interface name)
__repacd_wifimon_is_sta_iface() {
local config="$1"
local network_to_match="$2"
local iface disabled mode device hwmode
config_get network "$config" network
config_get iface "$config" ifname
config_get disabled "$config" disabled '0'
config_get mode "$config" mode
config_get device "$config" device
config_get hwmode "$device" hwmode
if [ "$hwmode" != "11ad" ]; then
if [ "$network" = "$network_to_match" ] && [ -n "$iface" ] && [ "$mode" = "sta" ] && \
[ "$disabled" -eq 0 ]; then
if whc_is_5g_vap "$config"; then
eval "$5=$iface"
eval "$6=$config"
else
eval "$3=$iface"
eval "$4=$config"
fi
elif [ -z "$iface" ] && [ "$disabled" -eq 0 ]; then
# If an interface is showing as enabled but no name is known for it,
# mark it as such. Without doing this, we can resolve the interface
# names improperly.
eval "$7=1"
fi
fi
}
# Initialize the sta_iface_5g variable with the STA interface that is enabled
# on the specified network (if any).
# input: $1 - network: the name of the network being managed
__repacd_wifimon_get_sta_iface() {
unknown_ifaces=0
config_load wireless
config_foreach __repacd_wifimon_is_sta_iface wifi-iface "$1" \
sta_iface_24g sta_iface_24g_config_name \
sta_iface_5g sta_iface_5g_config_name unknown_ifaces
if [ "$unknown_ifaces" -gt 0 ]; then
# Clear out everything because we cannot be certain we have the
# right names (eg. interfaces may not all be up yet).
sta_iface_24g=
sta_iface_24g_config_name=
sta_iface_5g=
sta_iface_5g_config_name=
fi
}
# Initialize the Wi-Fi monitoring logic with the name of the network being
# monitored.
# input: $1 - network: the name of the network being managed
# input: $2 - cur_re_mode: the current operating range extender mode
# input: $3 - cur_re_submode: the current operating range extender submode
# input: $4 - autoconfig: whether it was an auto-config restart
# output: $5 - state: the name of the initial state
# output: $6 - new_re_mode: the resolved range extender mode
# output: $7 - new_re_submode: the resolved range extender submode
repacd_wifimon_init() {
# Resolve the STA interfaces.
# Here we assume that if we have the 5 GHz interface, that is sufficient,
# as not all modes will have a 2.4 GHz interface.
__repacd_wifimon_get_sta_iface "$1"
if [ -n "$sta_iface_5g" ] || [ -n "$sta_iface_24g" ]; then
if [ -n "$sta_iface_24g" ]; then
__repacd_wifimon_debug "Resolved 2.4 GHz STA interface to $sta_iface_24g"
__repacd_wifimon_debug "2.4 GHz STA interface section $sta_iface_24g_config_name"
fi
if [ -n "$sta_iface_5g" ]; then
__repacd_wifimon_debug "Resolved 5 GHz STA interface to $sta_iface_5g"
__repacd_wifimon_debug "5 GHz STA interface section $sta_iface_5g_config_name"
fi
# First resolve the config parameters.
config_load repacd
config_get min_wps_assoc 'MAPWiFiLink' 'MinAssocCheckPostWPS' '5'
config_get wps_timeout 'MAPWiFiLink' 'WPSTimeout' '120'
config_get assoc_timeout 'MAPWiFiLink' 'AssociationTimeout' '300'
config_get rssi_samples 'MAPWiFiLink' 'RSSINumMeasurements' '5'
config_get backhaul_rssi_2 'MAPWiFiLink' 'BackhaulRSSIThreshold_2' '-78'
config_get backhaul_rssi_5 'MAPWiFiLink' 'BackhaulRSSIThreshold_5' '-78'
config_get backhaul_rssi_offset 'MAPWiFiLink' 'BackhaulRSSIThreshold_offset' '10'
config_get max_5g_attempts 'MAPWiFiLink' 'Max5gAttempts' '3'
config_get cnt_5g_attempts 'MAPWiFiLink' '5gAttemptsCount' '0'
config_get measuring_attempts 'MAPWiFiLink' 'MaxMeasuringStateAttempts' '3'
config_get force_bsses_down_on_all_bsta_switches 'MAPWiFiLink' \
'ForceBSSesDownOnAllBSTASwitches' '0'
# Create ourselves a named pipe so we can be informed of WPS push
# button events.
if [ -e $WIFIMON_PIPE_NAME ]; then
rm -f $WIFIMON_PIPE_NAME
fi
mkfifo $WIFIMON_PIPE_NAME
# If already associated, go to the InProgress state.
__repacd_wifimon_check_associated "$1" "$2" "$3" "$4" "$5" "$6" "$7"
fi
# Otherwise, must be operating in CAP mode.
}
# Check the status of the Wi-Fi link (WPS, association, and RSSI).
# input: $1 - network: the name of the network being managed
# input: $2 - cur_re_mode: the currently configured range extender mode
# input: $3 - cur_re_submode: the currently configured range extender sub-mode
# output: $4 - state: the name of the new state (only set upon a change)
# output: $5 - re_mode: the desired range extender mode (updated only once
# the link to the AP is considered stable)
# output: $6 - re_submode: the desired range extender submode (updated only once
# the link to the AP is considered stable)
repacd_wifimon_check() {
local wps_pressed=0
if [ -n "$sta_iface_24g" ] || [ -n "$sta_iface_5g" ]; then
local wps_pbc
if read -r -t 1 wps_pbc <>$WIFIMON_PIPE_NAME; then
__repacd_wifimon_debug "Received $wps_pbc on wifimon pipe"
eval "$4=$WIFIMON_STATE_AUTOCONFIG_IN_PROGRESS"
wps_in_progress=1
__repacd_wifimon_get_timestamp wps_start_time
fi
if __repacd_wifimon_check_associated "$1" "$2" "$3" 0 "$4" "$5" "$6"; then
assoc_timeout_logged=0
wps_timeout_logged=0
else # not associated
# If the WPS button was pressed, do not proceed to checking the
# association timeouts. That will happen in subsequent checks.
if [ "$wps_pressed" -gt 0 ]; then
return 1
fi
if [ "$wps_in_progress" -gt 0 ]; then
if __repacd_wifimon_is_timeout $wps_start_time $wps_timeout; then
if [ "$wps_timeout_logged" -eq 0 ]; then
__repacd_wifimon_debug "WPS timeout"
wps_timeout_logged=1
fi
eval "$4=$WIFIMON_STATE_WPS_TIMEOUT"
fi
else
if __repacd_wifimon_is_timeout $assoc_start_time $assoc_timeout; then
if [ "$assoc_timeout_logged" -eq 0 ]; then
__repacd_wifimon_debug "Association timeout"
assoc_timeout_logged=1
fi
if [ -n "$sta_iface_5g" ]; then
# Try falling back to another interface
__repacd_wifimon_debug "Trying next bSTA radio"
# Since this bSTA could not associate, assume the next
# one might not be able to either. Thus, tell the
# fronthaul manager to force the BSSes down at startup.
local force_bsses_down=1
__repacd_wifimon_select_next_bsta "$sta_iface_5g_config_name" \
$force_bsses_down \
"$WIFIMON_STATE_AUTOCONFIG_IN_PROGRESS" "$4"
else
# Already on 2.4 GHz. If we cannot associate here, we
# probably cannot associate on 5 GHz.
eval "$4=$WIFIMON_STATE_ASSOC_TIMEOUT"
fi
fi
fi
fi
fi
}
# Hook function that, in SON mode, would determine whether to bring up/down the
# 2.4 GHz backhaul. In Multi-AP SIG mode, this is not currently relevant
# (given the 1 backhaul link assumption).
repacd_wifimon_independent_channel_check() {
/bin/true
}
# Terminate the Wi-Fi link monitoring, cleaning up any state in preparation
# for shutdown.
repacd_wifimon_fini() {
/bin/true
}
# Resolve the credentials for any VAP that has bBSS support.
#
# input: $1 - config: the name of the interface config section
# input: $2 - network: the name of the network to which the AP interface
# must belong to be matched
# output: $3 - ssid: the backhaul SSID
# output: $4 - key: the backhaul key (aka. passphrase)
# output: $5 - enc: the backhaul encryption mode
__repacd_wifimon_resolve_bbss_creds() {
local config="$1"
local network_to_match="$2"
local network mode device hwmode disabled
local ssid key enc map map_type
config_get network "$config" network
config_get mode "$config" mode
config_get device "$config" device
config_get hwmode "$device" hwmode
config_get disabled "$config" disabled '0'
config_get ssid "$config" ssid
config_get key "$config" key
config_get enc "$config" encryption
config_get map "$config" map '0'
config_get map_type "$config" MapBSSType
if [ "$hwmode" != "11ad" ]; then
if [ "$network" = "$network_to_match" ] && [ "$mode" = "ap" ] && \
[ "$disabled" -eq 0 ] && [ "$map" -gt 0 ]; then
local bbss=$(( map_type & 64 ))
if [ ${bbss} -eq 64 ]; then
# Has bBSS capabilty, so record the credentials
eval "$3='${ssid}'"
eval "$4='${key}'"
eval "$5='${enc}'"
fi
fi
fi
}
# Set the credentials on the bSTA VAP(s).
#
# input: $1 - config: the name of the interface config section
# input: $2 - network: the name of the network to which the STA interface
# must belong to be matched
# input: $3 - ssid: the backhaul SSID
# input: $4 - key: the backhaul key (aka. passphrase)
# input: $5 - enc: the backhaul encryption mode
__repacd_wifimon_set_bsta_creds() {
local config="$1"
local network_to_match="$2"
local ssid="$3"
local key="$4"
local enc="$5"
local network mode hwmode device disabled
local ssid key enc map map_type
config_get network "$config" network
config_get mode "$config" mode
config_get device "$config" device
config_get hwmode "$device" hwmode
config_get disabled "$config" disabled '0'
config_get map "$config" map '0'
config_get map_type "$config" MapBSSType
if [ "$hwmode" != "11ad" ]; then
if [ "$network" = "$network_to_match" ] && [ "$mode" = "sta" ] && \
[ "$map" -gt 0 ]; then
if [ "$map_type" -eq 128 ]; then # bSTA
uci_set wireless "$config" ssid "$ssid"
uci_set wireless "$config" key "$key"
uci_set wireless "$config" encryption "$enc"
uci_commit wireless
fi
fi
fi
}
# Copy the backhaul credentials from a bBSS interface (or a combined
# fBSS + bBSS) to the bSTA interface. This ensures the credentials obtained
# during Ethernet onboarding can be used when switching into RE mode.
repacd_wifimon_config_bsta() {
bbss_ssid=''
bbss_key=''
bbss_enc=''
# First resolve the SSID, passphrase, and encryption from the bBSS
# capable AP interfaces.
config_load wireless
config_foreach __repacd_wifimon_resolve_bbss_creds wifi-iface "$1" \
bbss_ssid bbss_key bbss_enc
# Now apply these values to the bSTA interface.
config_foreach __repacd_wifimon_set_bsta_creds wifi-iface "$1" \
"${bbss_ssid}" "${bbss_key}" "${bbss_enc}"
}