WPA_CLI="wpa_cli -p /run/wpa_supplicant" # Uses wpa_supplicant to check for association to a network # wpa_check interface [timeout] wpa_check() { local timeout=0 INTERFACE="$1" TIMEOUT="${2:-15}" CONDITION="${3:-COMPLETED}" # CONDITION is required as wired connections are ready at ASSOCIATED not COMPLETED FS#20150 while [[ $timeout -lt "$TIMEOUT" ]]; do ( # Sometimes wpa_supplicant isn't ready so silence errors for 2s only to avoid hiding real errors if [[ $timeout -lt 2 ]]; then eval $($WPA_CLI -i "$INTERFACE" status 2> /dev/null | fgrep "wpa_state=") else eval $($WPA_CLI -i "$INTERFACE" status | fgrep "wpa_state=") fi [[ "$wpa_state" = "$CONDITION" ]] ) && return 0 sleep 1 let timeout++ done echo "$wpa_state" # wpa_cli -i "$INTERFACE" terminate >/dev/null 2>&1 # callers sometimes called stop_wpa, which does more but seems redundant # termination should either be handled properly here, or by callers stop_wpa "$INTERFACE" return 1 } start_wpa() { local INTERFACE="$1" WPA_CONF="$2" WPA_DRIVER="$3" shift 3 local WPA_OPTS="$*" wpa_supplicant -B -P "/run/wpa_supplicant_${INTERFACE}.pid" -i "$INTERFACE" -D "$WPA_DRIVER" -c "$WPA_CONF" $WPA_OPTS sleep 1 if [[ ! -f "/run/wpa_supplicant_${INTERFACE}.pid" ]]; then return 1 fi } stop_wpa() { $WPA_CLI -i "$1" terminate &> /dev/null sleep 1 # JP: need this else the file tends to disappear after [[ -f ... ]] but before cat... # see if [[ -f "/run/wpa_supplicant_$1.pid" ]]; then kill "$(cat "/run/wpa_supplicant_$1.pid")" &>/dev/null & fi } wpa_reconfigure() { local INTERFACE=$1 $WPA_CLI -i "$INTERFACE" reconfigure return $? } wpa_check_current_essid() { # usage: wpa_check_current_essid $interface $essid # check that wpa_supplicant is connected to the right essid local INTERFACE=$1 ESSID=$2 status status=$($WPA_CLI -i "$INTERFACE" status | grep "^ssid=") if (( $? == 0 )) && [[ "$status" == "ssid=$ESSID" ]]; then return 0 else return 1 fi } wpa_find_essid() { # usage: wpa_find_essid $INTERFACE $ESSID # look for existence of a given essid. Assumes wpa_supplicant is # running result=$(wpa_supplicant_scan_and_find "$1" 5 "$2") ret=$? echo $result report_debug wpa_find_essid "\"$result\"" return $ret } wpa_find_ap() { # usage: wpa_find_essid $INTERFACE $ESSID # look for existence of a given essid. Assumes wpa_supplicant is # running bssid=${2,,} # set to lowercase result=$(wpa_supplicant_scan_and_find "$1" 1 "$bssid") ret=$? echo $result report_debug wpa_find_ap "\"$result\"" return $ret } wpa_supplicant_scan_and_find() { #usage: wpa_supplicant_scan_and_find $INTERFACE $FIELD $ITEM # field = 1 for bssid, 5 for essid # item = string to lookup local INTERFACE="$1" FIELD="$2" ITEM="$3" RETRIES=5 try scan_ok scan_ok=0 $WPA_CLI -i "$INTERFACE" scan &> /dev/null for ((try=0; try < $RETRIES; try++)); do local found sleep 2 found=$($WPA_CLI -i "$INTERFACE" scan_results | tail -n+2 | cut -f ${FIELD} | grep -F -x -m 1 "${ITEM}") (( $? == 0 )) && scan_ok=1 # ITEM has been found, echo it if [[ -n "$found" ]]; then echo "$found" return 0 fi $WPA_CLI -i "$INTERFACE" scan &> /dev/null done if (( $scan_ok != 1 )); then report_debug wpa_supplicant_scan_and_find "unable to retrieve scan results" fi return 1 } # Return a filename containing a list of network APs and ESSIDs found (sorted by decreasing signal strength) # list_networks interface list_networks() { wpa_supplicant_scan_info "$1" 1,5 } wpa_supplicant_scan_info() { local INTERFACE="$1" fields="$2" essids # temp file used, as keeping ESSID's with spaces in their name in arrays # is hard, obscure and kinda nasty. This is simpler and clearer. [[ -z "$INTERFACE" ]] && return 1 essids=$(mktemp --tmpdir essid.XXXXXXXX) wpa_supplicant -B -i"$INTERFACE" -Dnl80211,wext -C/run/wpa_supplicant -P/run/wpa_supplicant.pid || return 1 $WPA_CLI -i "$INTERFACE" scan &> /dev/null sleep 2.5 $WPA_CLI -i "$INTERFACE" scan_results | grep -v "^Selected" | grep -v "^bssid" | sort -rn -k3 | sort -u -k5 | sort -rn -k3 | cut -f"$fields" > "$essids" # Fields are tab delimited # Remove extraneous output from wpa_cli # Sort by strength # Remove duplicates # Re-sort by strength as the removal disorders the list # Cut to the AP/essid fields only kill "$(cat /run/wpa_supplicant.pid)" # File of 0 length, ie. no ssid's. if [[ ! -s "$essids" ]]; then rm -f "$essids" return 1 fi echo $essids return 0 } # Requires already loaded profile make_wpa_config_file() { local interface=$1 local WPA_CONF="$STATE_DIR/wpa.${interface}" # substitute spaces out # make empty tmp dir with correct permissions, rename it check_make_state_dir rm -rf "$WPA_CONF" mv -f "$(mktemp -d --tmpdir=$STATE_DIR)" "$WPA_CONF" || return 1 echo "ctrl_interface=/run/wpa_supplicant" >> "$WPA_CONF/wpa.conf" # we know $WPA_CONF now has no spaces, but it may have other nasty chars, so still needs to be quoted echo "ctrl_interface_group=${WPA_GROUP:-wheel}" >> "$WPA_CONF/wpa.conf" [[ $WPA_COUNTRY ]] && echo "country=$WPA_COUNTRY" >> "$WPA_CONF/wpa.conf" [[ -n "$ADHOC" ]] && echo "ap_scan=2" >> "$WPA_CONF/wpa.conf" echo "$WPA_CONF/wpa.conf" } # Requires already loaded profile make_wpa_config() { case $SECURITY in wep|wep-old|wpa|none|none-old) echo "ssid=\"$ESSID\"" if [[ -n "$AP" ]]; then echo "bssid=$AP" fi [[ -n "$ADHOC" ]] && echo "mode=1" ;; wpa-configsection) echo "$CONFIGSECTION" ;; *) return 1 ;; esac # Key management case $SECURITY in wep|wep-old) echo "key_mgmt=NONE" echo "wep_tx_idx=0" if [[ ${KEY:0:2} == "s:" ]]; then # TODO: does wpa_supplicant handle this as expected? echo "wep_key0=\"${KEY:2}\"" else echo "wep_key0=$KEY" fi ;; none|none-old) echo "key_mgmt=NONE" ;; wpa) if [[ "${#KEY}" -eq 64 ]]; then echo "proto=RSN WPA\npsk=$KEY" else echo "proto=RSN WPA\npsk=\"$KEY\"" fi ;; esac # Hidden SSID if checkyesno ${HIDDEN:-no}; then echo "scan_ssid=1" fi } # vim: ft=sh ts=4 et sw=4 tw=0: