summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorJouke Witteveen <j.witteveen@gmail.com>2012-12-28 02:43:13 +0100
committerJouke Witteveen <j.witteveen@gmail.com>2012-12-28 02:57:35 +0100
commit27c11787d7c58b02f12d7afd476ea66abfeecaaf (patch)
treee203812a9e6d2a901568ca36de3b1fc7380a369b /src/lib
parent4e457e0efd0e5fd5df24c7e9ed63b02d0196ea8d (diff)
downloadnetctl-27c11787d7c58b02f12d7afd476ea66abfeecaaf.tar.gz
netctl-27c11787d7c58b02f12d7afd476ea66abfeecaaf.tar.xz
Forking netcfg to netctl (2/2)
This commit contains the refactoring and rewriting of code.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/8021x341
-rwxr-xr-xsrc/lib/auto.action85
-rw-r--r--src/lib/connections/bond41
-rw-r--r--src/lib/connections/bridge53
-rw-r--r--src/lib/connections/ethernet276
-rw-r--r--src/lib/connections/pppoe55
-rw-r--r--src/lib/connections/tunnel34
-rw-r--r--src/lib/connections/tuntap32
-rw-r--r--src/lib/connections/vlan34
-rw-r--r--src/lib/connections/wireless137
-rw-r--r--src/lib/globals159
-rw-r--r--src/lib/ip215
-rwxr-xr-x[-rw-r--r--]src/lib/network419
-rw-r--r--src/lib/rfkill85
14 files changed, 798 insertions, 1168 deletions
diff --git a/src/lib/8021x b/src/lib/8021x
index d2ddfe4..60f3552 100644
--- a/src/lib/8021x
+++ b/src/lib/8021x
@@ -1,171 +1,129 @@
-# Usage: wpa_call $interface $call ...
-# Wrapper around wpa_cli to deal with supplicant configurations that set a
-# non-standard control path.
-wpa_call()
-{
- local args=("-i" "$1")
+## /usr/lib/network/globals needs to be sourced before this file
+
+
+## Wrapper around wpa_cli to deal with supplicant configurations that set a
+## non-standard control path.
+# $1: interface name
+# $2...: call to the supplicant
+wpa_call() {
+ local args=( "-i" "$1" )
shift
- if [[ -n "$WPA_CTRL_DIR" ]]; then
+ if [[ $WPA_CTRL_DIR ]]; then
args+=("-p" "$WPA_CTRL_DIR")
- elif [[ -n "$WPA_CONF" ]] && grep -q "^[[:space:]]*ctrl_interface=" "$WPA_CONF"; then
- WPA_CTRL_DIR=$(grep -m 1 "^[[:space:]]*ctrl_interface=" "$WPA_CONF")
+ elif [[ $WPAConfigFile ]] && grep -q "^[[:space:]]*ctrl_interface=" "$WPAConfigFile"; then
+ WPA_CTRL_DIR=$(grep -m1 "^[[:space:]]*ctrl_interface=" "$WPAConfigFile")
WPA_CTRL_DIR=${WPA_CTRL_DIR#*ctrl_interface=}
- if [[ "$WPA_CTRL_DIR" == DIR=* ]]; then
+ if [[ $WPA_CTRL_DIR == DIR=* ]]; then
WPA_CTRL_DIR=${WPA_CTRL_DIR:4}
WPA_CTRL_DIR=${WPA_CTRL_DIR%% GROUP=*}
fi
- args+=("-p" "$WPA_CTRL_DIR")
+ args+=( "-p" "$WPA_CTRL_DIR" )
fi
- report_debug wpa_cli "${args[@]}" "$@"
- wpa_cli "${args[@]}" "$@"
+ do_debug wpa_cli "${args[@]}" "$@"
}
-# 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 < TIMEOUT )); do
- ( # Sometimes wpa_supplicant isn't ready so silence errors for 2s only to avoid hiding real errors
- if (( timeout < 2 )); then
- eval $(wpa_call "$INTERFACE" status 2> /dev/null | grep -F "wpa_state=")
- else
- eval $(wpa_call "$INTERFACE" status | grep -F "wpa_state=")
- fi
- [[ "$wpa_state" = "$CONDITION" ]]
- ) && return 0
- sleep 1
- (( ++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
+## Retrieves the state of an instance of the wpa supplicant
+## Displays one of: DISCONNECTED, INTERFACE_DISABLED, INACTIVE, SCANNING,
+## AUTHENTICATING, ASSOCIATING, ASSOCIATED, 4WAY_HANDSHAKE,
+## GROUP_HANDSHAKE, COMPLETED
+# $1: interface name
+wpa_get_state() {
+ local state
+ state=$(wpa_call $1 status | grep -m1 "^wpa_state=") || return 1
+ echo ${state#wpa_state=}
}
-start_wpa()
-{
- local INTERFACE="$1" WPA_CONF="$2" WPA_DRIVER="$3"
- shift 3
- local WPA_OPTS="$@" PIDFILE="/run/wpa_supplicant_${INTERFACE}.pid"
-
- if [[ -n "$WPA_CONF" ]]; then
- WPA_CONF="-c$WPA_CONF"
- else
- WPA_CTRL_DIR="/run/wpa_supplicant"
- WPA_CONF="-C$WPA_CTRL_DIR"
- fi
-
- wpa_supplicant -B -P "$PIDFILE" -i "$INTERFACE" -D "$WPA_DRIVER" "$WPA_CONF" $WPA_OPTS
-
- # wait up to one second for the pid file to appear
- timeout_wait 1 '[[ -f "$PIDFILE" ]]';
- return $?
+## Waits until the wpa supplicant reaches a listed state
+# $1: timeout
+# $2: interface name
+# $3...: accepted states
+wpa_wait_until_state() {
+ local timeout=$1 interface=$2 states=( "${@:3}" )
+ timeout_wait "$timeout" \
+ 'in_array "$(wpa_get_state "$interface")" "${states[@]}"'
}
-stop_wpa()
-{
- local INTERFACE="$1"
- # we need this as long as wpa_cli has a different default than netcfg
- [[ -z "$WPA_CTRL_DIR" && -z "$WPA_CONF" ]] && WPA_CTRL_DIR="/run/wpa_supplicant"
-
- # done if wpa_supplicant is already terminated for this interface
- [[ -e "$WPA_CTRL_DIR/$INTERFACE" ]] || return
-
- wpa_call "$INTERFACE" terminate > /dev/null
-
- # wait up to one second for the pid file to be removed
- timeout_wait 1 '[[ ! -f "/run/wpa_supplicant_${INTERFACE}.pid" ]]' || \
- kill "$(< "/run/wpa_supplicant_${INTERFACE}.pid")" &> /dev/null &
+## Waits while the wpa supplicant is in a listed state
+# $1: timeout
+# $2: interface name
+# $3...: rejected states
+wpa_wait_while_state() {
+ local timeout=$1 interface=$2 states=( "${@:3}" )
+ timeout_wait "$timeout" \
+ '! in_array "$(wpa_get_state "$interface")" "${states[@]}"'
}
-wpa_reconfigure() {
- wpa_call "$1" reconfigure > /dev/null
- return $?
-}
+## Start an instance of the wpa supplicant
+# $1: interface name
+# $2: interface driver(s)
+# $3: configuration file
+wpa_start() {
+ local interface=$1 driver=$2 configuration=$3
+ local pidfile="/run/wpa_supplicant_$interface.pid"
-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_call "$INTERFACE" status | grep "^ssid=")
- if (( $? == 0 )) && [[ "$status" == "ssid=$ESSID" ]]; then
- return 0
+ if [[ $configuration ]]; then
+ configuration="-c$configuration"
else
+ WPA_CTRL_DIR="/run/wpa_supplicant"
+ configuration="-C$WPA_CTRL_DIR"
+ fi
+
+ do_debug wpa_supplicant -B -P "$pidfile" -i "$interface" -D "$driver" \
+ "$configuration" $WPAOptions
+
+ # Wait up to one second for the pid file to appear
+ if ! timeout_wait 1 '[[ -f "$pidfile" ]]'; then
+ # Remove the configuration file if it was generated
+ configuration="$STATE_DIR/wpa_supplicant_$interface.conf"
+ [[ -f $configuration && -O $configuration ]] && rm -f "$configuration"
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
-}
+## Stop an instance of the wpa supplicant
+# $1: interface name
+wpa_stop() {
+ local interface=$1 config_file="$STATE_DIR/wpa_supplicant_$1.conf"
+ # We need this as long as wpa_cli has a different default than netctl
+ if [[ -z $WPA_CTRL_DIR && -z $WPAConfigFile ]]; then
+ WPA_CTRL_DIR="/run/wpa_supplicant"
+ fi
-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
-}
+ # Done if wpa_supplicant is already terminated for this interface
+ [[ -z $WPA_CTR_DIR || -e "$WPA_CTRL_DIR/$interface" ]] || return
-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 scan_ok=0 try
- for ((try=0; try < $RETRIES; try++)); do
- local found
- wpa_call "$INTERFACE" scan > /dev/null
- sleep 2
- found=$(wpa_call "$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
- done
- if (( $scan_ok != 1 )); then
- report_debug wpa_supplicant_scan_and_find "unable to retrieve scan results"
+ wpa_call "$interface" terminate > /dev/null
+ [[ -f $config_file && -O $config_file ]] && rm -f "$config_file"
+
+ # Wait up to one second for the pid file to be removed
+ if ! timeout_wait 1 '[[ ! -f "/run/wpa_supplicant_$interface.pid" ]]'; then
+ kill "$(< "/run/wpa_supplicant_$interface.pid")" &> /dev/null
fi
- return 1
}
+## Scan for networks within range
+# $1: interface name
+# $2: fields of the wpa_supplicant scan_results
wpa_supplicant_scan() {
- local INTERFACE="$1" fields="$2" spawned_wpa=0 essids
+ local interface=$1 fields=$2 spawned_wpa=0 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
+ [[ $interface ]] || return 1
essids=$(mktemp --tmpdir essid.XXXXXXXX)
- if [[ "$(wpa_call "$INTERFACE" ping 2> /dev/null)" != "PONG" ]]; then
- start_wpa "$INTERFACE" "" "${WPA_DRIVER:-nl80211,wext}" || return 1
+ if [[ "$(wpa_call "$interface" ping 2> /dev/null)" != "PONG" ]]; then
+ wpa_start "$interface" "${WPADriver:-nl80211,wext}" || return 1
spawned_wpa=1
fi
- wpa_call "$INTERFACE" scan > /dev/null
+ wpa_call "$interface" scan > /dev/null
# Wait at least 3 seconds for scan results
sleep 3
- # Sometimes, that is not enough (FS#29946)
- timeout_wait 7 '! wpa_call "$INTERFACE" status | grep -F -q "wpa_state=SCANNING"'
- wpa_call "$INTERFACE" scan_results |
+ # Sometimes, that is not enough
+ wpa_wait_while_state 7 "$interface" "SCANNING"
+ wpa_call "$interface" scan_results |
tail -n+2 |
sort -rn -k3 |
sort -u -k5 |
@@ -179,97 +137,100 @@ wpa_supplicant_scan() {
# Re-sort by strength as the removal disorders the list
# Cut to the AP/essid fields only
- (( $spawned_wpa == 1 )) && stop_wpa "$INTERFACE"
+ (( spawned_wpa == 1 )) && wpa_stop "$interface"
- # File of 0 length, ie. no ssid's.
+ # File of 0 length: 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 WPA_CONFD="$STATE_DIR/wpa.$1"
-
- # make empty tmp dir with correct permissions, rename it
- check_make_state_dir
- mkdir -p /run/wpa_supplicant
- rm -rf "$WPA_CONFD"
- mv -f "$(mktemp -d --tmpdir=$STATE_DIR)" "$WPA_CONFD" || return 1
- echo "ctrl_interface=/run/wpa_supplicant" >> "$WPA_CONFD/wpa.conf"
- echo "ctrl_interface_group=${WPA_GROUP:-wheel}" >> "$WPA_CONFD/wpa.conf"
- [[ $WPA_COUNTRY ]] && echo "country=$WPA_COUNTRY" >> "$WPA_CONFD/wpa.conf"
- [[ -n "$ADHOC" ]] && echo "ap_scan=2" >> "$WPA_CONFD/wpa.conf"
- echo "$WPA_CONFD/wpa.conf"
+## Print a string within quotes, unless it starts with the "-modifier
+## Quoted: string "string" '""string"'
+## Non-quoted: \"string "\"string" '"string'
+# $1: string
+wpa_quote() {
+ local string=$1
+ if [[ $string == \"* ]]; then
+ printf '%s' "${string:1}"
+ else
+ printf '"%s"' "$string"
+ fi
}
-# Requires already loaded profile
-make_wpa_config() {
- case $SECURITY in
- none|wep|wpa)
- case "${ESSID_TYPE:-ascii}" in
- ascii)
- echo "ssid=\"$ESSID\""
- ;;
- hex)
- # Hex ESSID is written unquoted and in lowercase (FS#24333)
- echo "ssid=${ESSID,,}"
- ;;
- *)
- report_fail "ESSID_TYPE must be set to 'ascii' or 'hex'."
- return 1
- ;;
- esac
- if [[ -n "$AP" ]]; then
- echo "bssid=${AP,,}"
- fi
- [[ -n "$ADHOC" ]] && echo "mode=1"
+## Create a configuration file for wpa_supplicant without any network blocks
+# $1: interface name
+wpa_make_config_file() {
+ local config_file="$STATE_DIR/wpa_supplicant_$1.conf"
+
+ if [[ -e $config_file ]]; then
+ report_debug "The anticipated filename '$config_file' is not available"
+ return 1
+ fi
+ mkdir -p "$STATE_DIR" /run/wpa_supplicant
+ if ! : > "$config_file"; then
+ report_debug "Could not create the configuration file '$config_file'"
+ return 1
+ fi
+ chmod 600 "$config_file"
+
+ echo "ctrl_interface=/run/wpa_supplicant" >> "$config_file"
+ echo "ctrl_interface_group=${WPAGroup:-wheel}" >> "$config_file"
+ [[ $Country ]] && echo "country=$Country" >> "$config_file"
+ if is_yes "${AdHoc:-no}"; then
+ echo "ap_scan=2" >> "$config_file"
+ fi
+ echo "$config_file"
+}
+
+## Generate a network block for wpa_supplicant
+# $Security: type of wireless security
+wpa_make_config_block() {
+ case $Security in
+ none|wep|wpa)
+ echo "ssid=$(wpa_quote "$ESSID")"
+ [[ $AP ]] && echo "bssid=${AP,,}"
+ is_yes "${AdHoc:-no}" && echo "mode=1"
;;
- wpa-configsection)
- echo "$CONFIGSECTION"
+ wpa-configsection)
+ printf "%s\n" "${WPAConfigSection[@]}"
+ return
;;
- *)
+ *)
+ report_error "Unsupported security setting: '$Security'"
return 1
;;
esac
# Key management
- case $SECURITY in
- none)
+ case $Security in
+ none)
echo "key_mgmt=NONE"
;;
- wep)
+ wep)
echo "key_mgmt=NONE"
echo "wep_tx_keyidx=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
+ echo "wep_key0=$(wpa_quote "$Key")"
;;
- wpa)
+ wpa)
echo "proto=RSN WPA"
- if [[ "${#KEY}" -eq 64 ]]; then
- echo "psk=$KEY"
+ if [[ "${#Key}" -eq 64 ]]; then
+ echo "psk=$Key"
else
- echo "psk=\"$KEY\""
+ echo "psk=$(wpa_quote "$Key")"
fi
;;
esac
# Hidden SSID
- if checkyesno ${HIDDEN:-no}; then
- echo "scan_ssid=1"
- fi
+ is_yes "${Hidden:-no}" && echo "scan_ssid=1"
# Priority group for the network
- if [[ -n "$PRIORITY" ]]; then
- echo "priority=$PRIORITY"
- fi
+ [[ $Priority ]] && echo "priority=$Priority"
}
-# vim: ft=sh ts=4 et sw=4 tw=0:
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/auto.action b/src/lib/auto.action
index 1f29364..00a4d14 100755
--- a/src/lib/auto.action
+++ b/src/lib/auto.action
@@ -1,56 +1,57 @@
#! /bin/bash
+. /usr/lib/network/globals
+. "$SUBR_DIR/ip"
+
interface="$1"
ssid="$2"
profile="$3"
action="$4"
+PROFILE_FILE="$STATE_DIR/wpa_actiond_$interface.profile"
-. /usr/lib/network/network
+# Is it possible that we don't get a profile?!
[[ "$profile" ]] && load_profile "$profile"
+# TODO: copy some from 'network'
case $action in
- CONNECT)
- if [[ -z $profile ]]; then
- # Load interface specific config
- [[ -f "$IFACE_DIR/$interface" ]] && source "$IFACE_DIR/$interface"
- dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" -K $DHCP_OPTIONS "$interface"
- exit $?
- fi
- if ! DHCPCD_INTERNAL_OPTIONS="-K" $CONN_DIR/ethernet up "$profile"; then
- exit 1 # what to do if fail?
- fi
-
- set_profile up "$profile"
-
- if ! ( eval $POST_UP ); then # JP: sandbox the eval
- # failing POST_UP will take interface down
- "$CONN_DIR/$ethernet" down "$profile"
- exit 1
- fi
- ;;
- DISCONNECT)
- if [[ -z $profile ]]; then
- dhcpcd -k "$interface"
- exit $?
+ CONNECT)
+ if [[ -z $profile ]]; then
+ if [[ -x "$PROFILE_DIR/interfaces/$interface" ]]; then
+ source "$PROFILE_DIR/interfaces/$interface"
fi
- if ! ( eval $PRE_DOWN ); then # JP: sandbox the eval
- exit 1
- fi
- if ! "$CONN_DIR/ethernet" down "$profile"; then
- exit 1
- fi
- if ! ( eval $POST_DOWN ); then # JP: sandbox the eval
- exit 1
- fi
- set_profile down "$profile"
- ;;
- LOST|REESTABLISHED)
- # Not handled.
- exit 0
- ;;
- *)
- # ???
+ dhcpcd -qL -t "${TimeoutDHCP:-10}" $DHCPOptions -K "$interface"
+ exit $?
+ fi
+ DHCPOptions+=" -K"
+ ip_set || exit 1
+ printf "%s" "$profile" > "$PROFILE_FILE"
+ # JP: sandbox the eval
+ if ! ( eval $ExecUpPost ); then
+ # Failing ExecUpPost will take the connection down
+ netctl-auto stop "$interface"
exit 1
- ;;
+ fi
+ ;;
+ DISCONNECT)
+ if [[ -z $profile ]]; then
+ dhcpcd -k "$interface"
+ exit $?
+ fi
+ # JP: sandbox the eval
+ if ! ( eval $ExecDownPre ); then
+ exit 1
+ fi
+ ip_unset && rm -f "$PROFILE_FILE"
+ ;;
+ LOST|REESTABLISHED)
+ # Not handled.
+ exit 0
+ ;;
+ *)
+ # ???
+ exit 1
+ ;;
esac
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/connections/bond b/src/lib/connections/bond
index bc5aa95..09e51c6 100644
--- a/src/lib/connections/bond
+++ b/src/lib/connections/bond
@@ -1,40 +1,35 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Byron Williams <byron@112percent.com>
+
+. "$SUBR_DIR/ip"
+
IFENSLAVE="/sbin/ifenslave"
bond_up() {
- load_profile "$1"
-
- if [[ -e "/sys/class/net/$INTERFACE" ]]; then
- report_fail "Interface $INTERFACE already exists."
- exit 1
+ if is_interface "$Interface"; then
+ report_error "Interface '$Interface' already exists"
+ return 1
else
- ip link add dev $INTERFACE type bond
+ ip link add dev "$Interface" type bond
fi
- bring_interface up "$INTERFACE"
+ bring_interface_up "$Interface"
- for slave in "${SLAVE_INTERFACES[@]}"; do
- bring_interface up "$slave"
- $IFENSLAVE $INTERFACE $slave
+ for slave in "${BindsToInterfaces[@]}"; do
+ bring_interface_up "$slave"
+ $IFENSLAVE "$Interface" "$slave"
done
- "$CONN_DIR/ethernet" up "$1"
- return 0
+ ip_set
}
bond_down() {
- load_profile "$1"
-
- for slave in "${SLAVE_INTERFACES[@]}"; do
- $IFENSLAVE $INTERFACE -d $slave
+ for slave in "${BindsToInterfaces[@]}"; do
+ $IFENSLAVE "$Interface" -d "$slave"
done
- "$CONN_DIR/ethernet" down "$1"
- ip link delete "$INTERFACE"
- return 0
+ ip_unset
+ bring_interface_down "$Interface"
+ ip link delete "$Interface"
}
-bond_$1 "$2"
-exit $?
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/bridge b/src/lib/connections/bridge
index 6b3ab67..929a76b 100644
--- a/src/lib/connections/bridge
+++ b/src/lib/connections/bridge
@@ -1,47 +1,42 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Thomas Bächler <thomas@archlinux.org>
+
+. "$SUBR_DIR/ip"
+
BRCTL="/usr/sbin/brctl"
bridge_up() {
- local bridge_interface
- load_profile "$1"
-
- if [[ -e "/sys/class/net/$INTERFACE" ]]; then
- if [[ ! -d "/sys/class/net/$INTERFACE/brif" ]]; then
- report_fail "Interface $INTERFACE already exists and is not a bridge."
- exit 1
+ if is_interface "$Interface"; then
+ if [[ ! -d "/sys/class/net/$Interface/brif" ]]; then
+ report_error "Interface '$Interface' already exists and is not a bridge"
+ return 1
fi
else
- $BRCTL addbr "$INTERFACE"
+ $BRCTL addbr "$Interface"
fi
- for bridge_client in $BRIDGE_INTERFACES; do
- ip link set "$bridge_client" promisc on up
- ip addr flush dev "$bridge_client"
- $BRCTL addif "$INTERFACE" "$bridge_client"
+ for member in "${BindsToInterfaces[@]}"; do
+ ip link set "$member" promisc on up
+ ip addr flush dev "$member"
+ $BRCTL addif "$Interface" "$member"
done
# Set options
- [[ "$FWD_DELAY" ]] && $BRCTL setfd "$INTERFACE" "$FWD_DELAY"
- [[ "$MAX_AGE" ]] && $BRCTL setmaxage "$INTERFACE" "$MAX_AGE"
+ [[ "$FwdDelay" ]] && $BRCTL setfd "$Interface" "$FwdDelay"
+ [[ "$MaxAge" ]] && $BRCTL setmaxage "$Interface" "$MaxAge"
- "$CONN_DIR/ethernet" up "$1"
- return 0
+ bring_interface_up "$Interface"
+ ip_set
}
bridge_down() {
- local bridge_interface
- load_profile "$1"
-
- for bridge_client in $BRIDGE_INTERFACES; do
- ip link set "$bridge_client" promisc off down
- $BRCTL delif "$INTERFACE" "$bridge_client"
+ for member in "${BindsToInterfaces[@]}"; do
+ ip link set "$member" promisc off down
+ $BRCTL delif "$Interface" "$member"
done
- "$CONN_DIR/ethernet" down "$1"
- $BRCTL delbr "$INTERFACE"
- return 0
+ ip_unset
+ bring_interface_down "$Interface"
+ $BRCTL delbr "$Interface"
}
-bridge_$1 "$2"
-exit $?
+
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/ethernet b/src/lib/connections/ethernet
index 487adf8..0fff668 100644
--- a/src/lib/connections/ethernet
+++ b/src/lib/connections/ethernet
@@ -1,279 +1,75 @@
-#! /bin/bash
-# Source file for the 'ethernet' connection
-# ethernet_up $profile
-# ethernet_down $profile
-# ethernet_status
+# Ethernet connection support for netctl
-. /usr/lib/network/network
+. "$SUBR_DIR/ip"
-report_iproute()
-{
- report_fail "$*"
- bring_interface down "$INTERFACE"
- exit 1
-}
ethernet_up() {
- load_profile "$1"
- SYSCTL_INTERFACE="${INTERFACE/.//}"
-
- if ! is_interface "$INTERFACE"; then
- report_iproute "Interface $INTERFACE does not exist"
+ if ! is_interface "$Interface"; then
+ report_error "Interface '$Interface' does not exist"
+ return 1
fi
# Disable IPv6 before bringing the interface up to prevent SLAAC
- if [[ "$IP6" == "no" ]]; then
- sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.disable_ipv6=1"
+ if [[ $IP6 == "no" ]]; then
+ sysctl -q -w "net.ipv6.conf.${Interface/.//}.disable_ipv6=1"
fi
- report_debug ethernet_up bring_interface up "$INTERFACE"
- bring_interface up "$INTERFACE"
+ if ! bring_interface_up "$Interface"; then
+ report_error "Failed to bring interface '$Interface' up"
+ return 1
+ fi
- if ! checkyesno "${SKIPNOCARRIER:-no}"; then
+ if ! is_yes "${SkipNoCarrier:-no}"; then
# Some cards are plain slow to come up. Don't fail immediately.
- if ! timeout_wait "${CARRIER_TIMEOUT:-5}" '(( $(< "/sys/class/net/$INTERFACE/carrier") ))'; then
- report_iproute "No connection"
+ if ! timeout_wait "${TimeoutCarrier:-5}" '(( $(< "/sys/class/net/$Interface/carrier") ))'; then
+ report_error "No connection on interface '$Interface'"
+ bring_interface_down "$Interface"
+ return 1
fi
fi
- if checkyesno "${AUTH8021X:-no}"; then
+ if is_yes "${Auth8021X:-no}"; then
. "$SUBR_DIR/8021x"
- [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf"
- [[ -z "$WPA_DRIVER" ]] && WPA_DRIVER="wired"
+ : ${WPAConfigFile:=/etc/wpa_supplicant.conf}
+ : ${WPADriver:=wired}
+ : ${TimeoutWPA:=15}
- report_debug ethernet_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"
- if ! start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"; then
- report_fail "wpa_supplicant did not start, possible configuration error"
+ if ! wpa_start "$Interface" "$WPADriver" "$WPAConfigFile"; then
+ report_error "The WPA supplicant did not start for interface '$Interface'"
+ bring_interface_down "$Interface"
return 1
fi
- if ! wpa_check "$INTERFACE" "$TIMEOUT" "ASSOCIATED"; then
- bring_interface down "$INTERFACE"
- report_fail "WPA Authentication/Association Failed"
+ if ! wpa_wait_until_state "$TimeoutWPA" "$Interface" "ASSOCIATED"; then
+ wpa_stop "$Interface"
+ bring_interface_down "$Interface"
+ report_error "WPA Authentication/Association Failed"
return 1
fi
fi
- if [[ -z "$IP" && -z "$IP6" ]]; then
- report_iproute "At least one of IP or IP6 should be specified"
+ if ! ip_set; then
+ stop_80211x
+ bring_interface_down "$Interface"
return 1
fi
-
- case "$IP" in
- dhcp)
- if checkyesno "${DHCLIENT:-no}"; then
- rm -r "/run/dhclient-${INTERFACE}.pid" >/dev/null 2>&1
- report_debug ethernet_up dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf "/run/dhclient-$INTERFACE.pid" "$INTERFACE"
- if ! dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf "/run/dhclient-${INTERFACE}.pid" ${DHCLIENT_OPTIONS} "$INTERFACE"; then
- report_fail "DHCP IP lease attempt failed."
- stop_80211x
- return 1
- fi
- else
- # Clear remaining pid files.
- rm -f "/run/dhcpcd-$INTERFACE".{pid,cache} >/dev/null 2>&1
- # If using own dns, tell dhcpcd to NOT replace resolv.conf
- [[ -n "$DNS" ]] && DHCP_OPTIONS="-C resolv.conf $DHCP_OPTIONS"
- # Start dhcpcd
- report_debug ethernet_up dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCPCD_INTERNAL_OPTIONS $DHCP_OPTIONS "$INTERFACE"
- dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCPCD_INTERNAL_OPTIONS $DHCP_OPTIONS "$INTERFACE" 2>&1 | report_debug "$(cat)"
- if [[ "$PIPESTATUS" -ne 0 ]]; then
- report_fail "DHCP IP lease attempt failed."
- stop_80211x
- return 1
- fi
- fi
- ;;
- static)
- if [[ -n "$ADDR" ]]; then
- [[ -z $NETMASK ]] && NETMASK=24
- report_debug ethernet_up ip addr add "$ADDR/$NETMASK" brd + dev "$INTERFACE"
- if ! ip addr add "$ADDR/$NETMASK" brd + dev "$INTERFACE"; then
- report_iproute "Could not configure interface"
- fi
- fi
- if [[ -n "$GATEWAY" ]]; then
- report_debug ethernet_up ip route add default via "$GATEWAY" dev "$INTERFACE"
- if ! ip route add default via "$GATEWAY" dev "$INTERFACE"; then
- report_iproute "Adding gateway $GATEWAY failed"
- fi
- fi
- ;;
- ""|no)
- ;;
- *)
- report_iproute "IP must be either 'dhcp', 'static' or 'no'"
- ;;
- esac
-
- if [[ -n "$IP" && -n "$ROUTES" ]]; then
- for route in "${ROUTES[@]}"; do
- report_debug ethernet_up ip route add $route dev "$INTERFACE"
- if ! ip route add $route dev "$INTERFACE"; then
- report_iproute "Adding route '$route' failed"
- fi
- done
- fi
-
- # Load ipv6 module if necessary (FS#25530)
- case "$IP6" in
- dhcp*|stateless|static)
- [[ -d "/proc/sys/net/ipv6" ]] || modprobe ipv6
- ;;
- no)
- [[ -d "/proc/sys/net/ipv6" ]] && sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=0"
- ;;
- "") # undefined IP6 does not prevent RA's from being received -> nop
- ;;
- *)
- report_iproute "IP6 must be 'dhcp', 'dhcp-noaddr', 'stateless', 'static' or 'no'"
- ;;
- esac
-
- case "$IP6" in
- dhcp*)
- if ! type dhclient &>/dev/null; then
- report_fail "You need to install dhclient to use DHCPv6."
- stop_80211x
- return 1
- fi
- sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=1"
- if [[ "$IP6" == "dhcp-noaddr" ]]; then
- DHCLIENT6_OPTIONS="-S ${DHCLIENT6_OPTIONS}"
- fi
- _DHCLIENT_PIDFILE="/run/dhclient6-${INTERFACE}.pid"
- rm -r ${_DHCLIENT_PIDFILE} &>/dev/null
- report_debug ethernet_up dhclient -6 -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf ${_DHCLIENT_PIDFILE} "$INTERFACE"
- if ! dhclient -6 -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf ${_DHCLIENT_PIDFILE} ${DHCLIENT6_OPTIONS} "$INTERFACE"; then
- report_fail "DHCPv6 IP lease attempt failed."
- stop_80211x
- return 1
- fi
- ;;
- stateless)
- sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=1"
- ;;
- static)
- sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=0"
- if [[ -n "$ADDR6" ]]; then
- for addr in "${ADDR6[@]}"; do
- report_debug ethernet_up ip -6 addr add $addr dev "$INTERFACE"
- if ! ip -6 addr add $addr dev "$INTERFACE"; then
- report_iproute "Could not add address '$addr' to interface"
- fi
- done
- fi
- ;;
- esac
-
- if [[ -n "$IP6" ]]; then
- # Wait for DAD to finish (FS#28887)
- report_debug ethernet_up ip -6 addr show dev "$INTERFACE" tentative
- if ! timeout_wait "${DAD_TIMEOUT:-3}" '[[ -z "$(ip -6 addr show dev "$INTERFACE" tentative)" ]]'; then
- report_iproute "Duplicate Address Detection is taking too long"
- fi
-
- # Add static IPv6 routes
- if [[ -n "$ROUTES6" ]]; then
- for route in "${ROUTES6[@]}"; do
- report_debug ethernet_up ip -6 route add $route dev "$INTERFACE"
- if ! ip -6 route add $route dev "$INTERFACE"; then
- report_iproute "Adding route '$route' failed"
- fi
- done
- fi
-
- # Set a custom gateway after waiting for DAD to finish
- if [[ "$IP6" == "static" && -n "$GATEWAY6" ]]; then
- report_debug ethernet_up ip -6 route replace default via "$GATEWAY6" dev "$INTERFACE"
- if ! ip -6 route replace default via "$GATEWAY6" dev "$INTERFACE"; then
- report_iproute "Adding gateway $GATEWAY6 failed"
- fi
- fi
- fi
-
- if [[ -n "$IPCFG" ]]; then
- for line in "${IPCFG[@]}"; do
- report_debug ethernet_up ip "$line"
- if ! ip $line; then
- report_iproute "Could not configure interface ($line)."
- fi
- done
- fi
-
- # Set hostname
- if [[ -n "$HOSTNAME" ]]; then
- report_debug ethernet_up hostname "$HOSTNAME"
- if ! echo "$HOSTNAME" >/proc/sys/kernel/hostname; then
- report_iproute "Cannot set hostname to $HOSTNAME"
- fi
- fi
-
- # Generate a new resolv.conf
- if [[ -n "$DNS" ]]; then
- : >/etc/resolv.conf
- [[ -n "$DOMAIN" ]] && echo "domain $DOMAIN" >>/etc/resolv.conf
- [[ -n "$SEARCH" ]] && echo "search $SEARCH" >>/etc/resolv.conf
- for dns in "${DNS[@]}"; do
- echo "nameserver $dns" >>/etc/resolv.conf
- done
- for dnsoption in "${DNS_OPTIONS[@]}"; do
- echo "options $dnsoption" >>/etc/resolv.conf
- done
- fi
-
- return 0
}
ethernet_down() {
- load_profile "$1"
-
- if [[ "$IP" == "dhcp" ]]; then
- if checkyesno "${DHCLIENT:-no}"; then
- if [[ -f "/run/dhclient-$INTERFACE.pid" ]]; then
- report_debug ethernet_down dhclient -q -x "$INTERFACE" -pf "/run/dhclient-$INTERFACE.pid"
- dhclient -q -x "$INTERFACE" -pf "/run/dhclient-$INTERFACE.pid" &>/dev/null
- #dhclient -q -r "$INTERFACE" &>/dev/null
- fi
- else
- if [[ -f "/run/dhcpcd-$INTERFACE.pid" ]]; then
- report_debug ethernet_down dhcpcd -qk "$INTERFACE"
- dhcpcd -qk "$INTERFACE" &>/dev/null
- fi
- fi
- fi
- if [[ "$IP6" == dhcp* ]]; then
- if [[ -f "/run/dhclient6-$INTERFACE.pid" ]]; then
- report_debug ethernet_down dhclient -6 -q -x "$INTERFACE" -pf "/run/dhclient6-$INTERFACE.pid"
- dhclient -6 -q -x "$INTERFACE" -pf "/run/dhclient6-$INTERFACE.pid" &>/dev/null
- report_debug ethernet_down /bin/kill $(< /run/dhclient6-$INTERFACE.pid)
- /bin/kill $(< /run/dhclient6-$INTERFACE.pid) &>/dev/null
- fi
- fi
-
+ ip_unset
stop_80211x
-
- if [[ "$CONNECTION" == "wireless" ]]; then
- report_debug ethernet_down bring_interface flush "$INTERFACE"
- bring_interface flush "$INTERFACE"
- else
- report_debug ethernet_down bring_interface down "$INTERFACE"
- bring_interface down "$INTERFACE"
- fi
- return 0
+ bring_interface_down "$Interface"
}
# Stop wpa_supplicant if neccessary
stop_80211x() {
- if checkyesno "${AUTH8021X:-no}"; then
+ if is_yes "${Auth8021X:-no}"; then
. "$SUBR_DIR/8021x"
- [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf"
- report_debug ethernet_down stop_wpa "$INTERFACE"
- stop_wpa "$INTERFACE"
+ : ${WPAConfigFile:=/etc/wpa_supplicant.conf}
+ do_debug wpa_stop "$Interface"
fi
}
-ethernet_$1 "$2"
-exit $?
+
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/pppoe b/src/lib/connections/pppoe
index 17fe42d..b24b503 100644
--- a/src/lib/connections/pppoe
+++ b/src/lib/connections/pppoe
@@ -1,5 +1,4 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Thomas Bächler <thomas@archlinux.org>
_quotestring() {
echo "\"${1/\"/\\\"}\""
@@ -7,60 +6,58 @@ _quotestring() {
pppoe_up() {
local cfg
- load_profile "$1"
- mkdir -p "$STATE_DIR/pppoe.${INTERFACE}.$1/"
- chmod 700 "$STATE_DIR/pppoe.${INTERFACE}.$1/"
- cfg="$STATE_DIR/pppoe.${INTERFACE}.$1/options"
+ mkdir -p "$STATE_DIR/pppoe.${Interface}.$1/"
+ chmod 700 "$STATE_DIR/pppoe.${Interface}.${Profile}/"
+ cfg="$STATE_DIR/pppoe.${Interface}.${Profile}/options"
: > "${cfg}"
chmod 600 "${cfg}"
echo "plugin rp-pppoe.so" >> "${cfg}"
- echo "nic-${INTERFACE}" >> "${cfg}"
+ echo "nic-${Interface}" >> "${cfg}"
echo "noauth" >> "${cfg}"
- if checkyesno ${DEFAULTROUTE:-1}; then
+ if is_yes "${DefaultRoute:-yes}"; then
echo "defaultroute" >> "${cfg}"
else
echo "nodefaultroute" >> "${cfg}"
fi
- if checkyesno ${USEPEERDNS:-1}; then
+ if is_yes "${UsePeerDNS:-yes}"; then
echo "usepeerdns" >> "${cfg}"
fi
- echo "linkname $(_quotestring "$1")" >> "${cfg}"
+ echo "linkname $(_quotestring "${Profile}")" >> "${cfg}"
echo "maxfail 5" >> "${cfg}"
echo "updetach" >> "${cfg}"
- if [[ ${CONNECTION_MODE} == demand ]]; then
+ if [[ ${ConnectionMode} == demand ]]; then
echo "demand" >> "${cfg}"
- echo "idle ${IDLE_TIMEOUT}" >> "${cfg}"
+ echo "idle ${IdleTimeout}" >> "${cfg}"
else
echo "persist" >> "${cfg}"
fi
- echo "user $(_quotestring "${USER}")" >> "${cfg}"
- echo "password $(_quotestring "${PASSWORD}")" >> "${cfg}"
- [[ -n ${LCP_ECHO_INTERVAL} ]] && echo "lcp-echo-interval ${LCP_ECHO_INTERVAL}" >> "${cfg}"
- [[ -n ${LCP_ECHO_FAILURE} ]] && echo "lcp-echo-failure ${LCP_ECHO_FAILURE}" >> "${cfg}"
- [[ -n ${PPPOE_SERVICE} ]] && echo "rp_pppoe_service $(_quotestring "${PPPOE_SERVICE}")" >> "${cfg}"
- [[ -n ${PPPOE_AC} ]] && echo "rp_pppoe_ac $(_quotestring "${PPPOE_AC}")" >> "${cfg}"
- [[ -n ${PPPOE_SESSION} ]] && echo "rp_pppoe_sess $(_quotestring "${PPPOE_SESSION}")" >> "${cfg}"
- [[ -n ${PPPOE_MAC} ]] && echo "pppoe-mac $(_quotestring "${PPPOE_MAC}")" >> "${cfg}"
- [[ ${PPPOE_IP6} == yes ]] && echo "+ipv6" >> "${cfg}"
+ echo "user $(_quotestring "${User}")" >> "${cfg}"
+ echo "password $(_quotestring "${Password}")" >> "${cfg}"
+ [[ -n ${LCPEchoInterval} ]] && echo "lcp-echo-interval ${LCPEchoInterval}" >> "${cfg}"
+ [[ -n ${LCPEchoFailure} ]] && echo "lcp-echo-failure ${LCPEchoFailure}" >> "${cfg}"
+ [[ -n ${PPPoEService} ]] && echo "rp_pppoe_service $(_quotestring "${PPPoEService}")" >> "${cfg}"
+ [[ -n ${PPPoEAC} ]] && echo "rp_pppoe_ac $(_quotestring "${PPPoEAC}")" >> "${cfg}"
+ [[ -n ${PPPoESession} ]] && echo "rp_pppoe_sess $(_quotestring "${PPPoESession}")" >> "${cfg}"
+ [[ -n ${PPPoEMAC} ]] && echo "pppoe-mac $(_quotestring "${PPPoEMAC}")" >> "${cfg}"
+ [[ ${PPPoEIP6} == yes ]] && echo "+ipv6" >> "${cfg}"
- /sbin/ip link set dev "${INTERFACE}" up
+ /sbin/ip link set dev "${Interface}" up
/usr/sbin/pppd file "${cfg}"
if [[ $? -ne 0 ]]; then
rm "${cfg}"
- rmdir "$STATE_DIR/pppoe.${INTERFACE}.$1/"
- report_fail "Couldn't make pppd connection."
+ rmdir "$STATE_DIR/pppoe.${Interface}.${Profile}/"
+ report_error "Couldn't make pppd connection."
return 1
fi
}
pppoe_down() {
- load_profile "$1"
local cfg
- cfg="$STATE_DIR/pppoe.${INTERFACE}.$1/options"
- PIDFILE="/var/run/ppp-$1.pid"
+ cfg="$STATE_DIR/pppoe.${Interface}.${Profile}/options"
+ PIDFILE="/var/run/ppp-${Profile}.pid"
if [[ -e $PIDFILE ]]; then
read PID < "$PIDFILE"
@@ -68,10 +65,8 @@ pppoe_down() {
fi
rm "${cfg}"
- rmdir "$STATE_DIR/pppoe.${INTERFACE}.$1/"
+ rmdir "$STATE_DIR/pppoe.${Interface}.${Profile}/"
}
-pppoe_$1 "$2"
-exit $?
# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/connections/tunnel b/src/lib/connections/tunnel
index 6cefc5c..f202371 100644
--- a/src/lib/connections/tunnel
+++ b/src/lib/connections/tunnel
@@ -1,34 +1,28 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Kyle Fuller <inbox@kylefuller.co.uk>
-tunnel_up() {
- load_profile "$1"
+. "$SUBR_DIR/ip"
- if [[ -e "/sys/class/net/$INTERFACE" ]]; then
- report_fail "Interface $INTERFACE already exists."
- exit 1
+tunnel_up() {
+ if is_interface "$Interface"; then
+ report_error "Interface '$Interface' already exists"
+ return 1
else
- ip tunnel add "$INTERFACE" mode "$MODE" remote "$REMOTE"
+ ip tunnel add "$Interface" mode "$Mode" remote "$Remote"
fi
- if [[ -n "$LOCAL" ]]; then
- ip tunnel change "$INTERFACE" local "$LOCAL"
+ if [[ -n "$Local" ]]; then
+ ip tunnel change "$Interface" local "$Local"
fi
- "$CONN_DIR/ethernet" up "$1"
- return 0
+ bring_interface_up "$Interface"
+ ip_set
}
tunnel_down() {
- load_profile "$1"
-
- "$CONN_DIR/ethernet" down "$1"
- ip tunnel del "$INTERFACE"
-
- return 0
+ ip_unset
+ bring_interface_down "$Interface"
+ ip tunnel del "$Interface"
}
-tunnel_$1 "$2"
-exit $?
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/tuntap b/src/lib/connections/tuntap
index 6985c8c..1ff5203 100644
--- a/src/lib/connections/tuntap
+++ b/src/lib/connections/tuntap
@@ -1,28 +1,24 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Rémy Oudompheng <remy@archlinux.org>
-tuntap_up() {
- load_profile "$1"
+. "$SUBR_DIR/ip"
- if [[ -e /sys/class/net/$INTERFACE ]]; then
- report_fail "Interface $INTERFACE already exists."
- exit 1
+tuntap_up() {
+ if is_interface "$Interface"; then
+ report_error "Interface '$Interface' already exists"
+ return 1
else
- ip tuntap add dev "$INTERFACE" mode "$MODE" \
- user "$USER" group "$GROUP"
+ ip tuntap add dev "$Interface" mode "$Mode" \
+ user "$User" group "$Group"
fi
- IP=${IP-no} "$CONN_DIR/ethernet" up "$1"
- return 0
+ bring_interface_up "$Interface"
+ IP=${IP-no} ip_set
}
tuntap_down() {
- load_profile "$1"
-
- "$CONN_DIR/ethernet" down "$1"
- ip tuntap del dev "$INTERFACE" mode "$MODE"
- return 0
+ ip_unset
+ bring_interface_down "$Interface"
+ ip tuntap del dev "$Interface" mode "$Mode"
}
-tuntap_$1 "$2"
-exit $?
+
# vim: set ts=4 et sw=4 tw=0:
diff --git a/src/lib/connections/vlan b/src/lib/connections/vlan
index 75c7fa9..86d1a2d 100644
--- a/src/lib/connections/vlan
+++ b/src/lib/connections/vlan
@@ -1,28 +1,26 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Contributed by: Thomas S Hatch <thatch45@gmail.com>
-vlan_up() {
- load_profile "$1"
+. "$CONN_DIR/ethernet"
- if [[ -e "/sys/class/net/$INTERFACE" ]]; then
- report_fail "Interface $INTERFACE already exists."
- exit 1
+vlan_up() {
+ if [[ ${#BindsToInterfaces} -ne 1 ]]; then
+ report_error "No unique physical device for VLAN interface '$Interface' specified"
+ return 1
+ fi
+ if is_interface "$Interface"; then
+ report_error "Interface '$Interface' already exists"
+ return 1
else
- bring_interface up "$VLAN_PHYS_DEV"
- ip link add link "$VLAN_PHYS_DEV" name "$INTERFACE" type vlan id "$VLAN_ID"
+ bring_interface_up "$BindsToInterfaces"
+ ip link add link "$BindsToInterfaces" name "$Interface" type vlan id "$VLANID"
fi
- "$CONN_DIR/ethernet" up "$1"
- return 0
+
+ ethernet_up
}
vlan_down() {
- load_profile "$1"
-
- "$CONN_DIR/ethernet" down "$1"
- ip link delete "$INTERFACE"
- return 0
+ ethernet_down
+ ip link delete "$Interface"
}
-vlan_$1 "$2"
-exit $?
# vim: set ts=4 et sw=4:
diff --git a/src/lib/connections/wireless b/src/lib/connections/wireless
index 135bec7..a3b324b 100644
--- a/src/lib/connections/wireless
+++ b/src/lib/connections/wireless
@@ -1,116 +1,89 @@
-#! /bin/bash
-. /usr/lib/network/network
+# Wireless connection support for netctl
+
. "$SUBR_DIR/8021x"
+. "$SUBR_DIR/ip"
. "$SUBR_DIR/rfkill"
-wireless_up() {
- PROFILE="$1"
- load_profile "$PROFILE"
- # Default settings
- SECURITY=${SECURITY:-none}
- WPA_DRIVER=${WPA_DRIVER:-nl80211,wext}
+wireless_up() {
+ local config_file
- enable_rf $INTERFACE $RFKILL $RFKILL_NAME || return 1
+ if ! is_interface "$Interface"; then
+ report_error "Interface '$Interface' does not exist"
+ return 1
+ fi
- # Check if interface exists
- is_interface "$INTERFACE" || { report_fail "interface $INTERFACE does not exist"; return 1; }
+ # Default settings
+ : ${Security:=none}
+ : ${WPADriver:=nl80211,wext}
+ : ${TimeoutWPA:=15}
+
+ if [[ $RFKill ]]; then
+ enable_rf "$Interface" "$RFKill" || return 1
+ fi
- # Kill any lingering wpa_supplicants.
- stop_wpa "$INTERFACE" &> /dev/null
+ # Kill any lingering WPA supplicants
+ WPAConfigFile= wpa_stop "$Interface" &> /dev/null
- # Start wpa_supplicant
- if [[ "$SECURITY" = "wpa-config" ]]; then
- WPA_CONF="${WPA_CONF:-/etc/wpa_supplicant.conf}"
+ if [[ $Security == "wpa-config" ]]; then
+ : ${WPAConfigFile:=/etc/wpa_supplicant.conf}
+ config_file=$WPAConfigFile
else
- WPA_CONF=$(make_wpa_config_file $INTERFACE)
+ config_file=$(wpa_make_config_file "$Interface")
+ if [[ -z $config_file ]]; then
+ report_error "Could not create a wpa config file for interface '$Interface'"
+ bring_interface_down "$Interface"
+ return 1
+ fi
+ printf "%s\n" "network={" "$(wpa_make_config_block)" "}" >> "$config_file"
fi
- report_debug wireless_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"
- if ! start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"; then
- report_fail "wpa_supplicant did not start, possible configuration error"
+
+ # Start the WPA supplicant
+ if ! do_debug wpa_start "$Interface" "$WPADriver" "$config_file"; then
+ report_error "The WPA supplicant did not start for interface '$Interface'"
+ bring_interface_down "$Interface"
return 1
fi
- # Scan for network's existence first
- if checkyesno "${SCAN:-no}"; then
- report_debug wireless_up scanning
- local OLDESSID="$ESSID"
- if [[ -n "$AP" ]]; then
- BSSID=$(wpa_find_ap "$INTERFACE" "$AP")
- else
- ESSID=$(wpa_find_essid "$INTERFACE" "$ESSID")
- fi
- if [[ $? -gt 0 ]]; then
- report_fail "Wireless network \"$OLDESSID\" not present."
- report_debug wireless_up stop_wpa "$INTERFACE"
- stop_wpa "$INTERFACE"
+ if is_yes "${Scan:-no}"; then
+ if ! wpa_wait_while_state "$TimeoutWPA" "$Interface" "DISCONNECTED" "SCANNING"; then
+ report_error "Wireless network '$ESSID' (or access point) not present"
+ wpa_stop "$Interface"
+ bring_interface_down "$interface"
return 1
fi
fi
-
- # Build configuration file
- case "$SECURITY" in
- wpa-config)
- ;;
- none|wep|wpa|wpa-configsection)
- printf "%s\n" "network={" "$(make_wpa_config)" "}" >> "$WPA_CONF"
- report_debug wireless_up "Configuration generated at $WPA_CONF"
- report_debug wireless_up wpa_reconfigure "$INTERFACE"
- if ! wpa_reconfigure "$INTERFACE"; then
- report_fail "WPA configuration failed!"
- stop_wpa "$INTERFACE"
- return 1
- fi
- ;;
- *)
- report_fail "Invalid SECURITY setting: $SECURITY"
- ;;
- esac
-
+
# Bring interface up after starting wpa_supplicant
# This is important since cards such as iwl3945 do not support
# mode switching when they are already up.
- report_debug wireless_up ifup
- bring_interface up "$INTERFACE" || return 1
+ bring_interface_up "$Interface" || return 1
- report_debug wireless_up wpa_check
- if ! wpa_check "$INTERFACE" "$TIMEOUT"; then
- report_fail "WPA Authentication/Association Failed"
+ if ! wpa_wait_until_state "$TimeoutWPA" "$Interface" "COMPLETED"; then
+ report_error "WPA association/authentication failed for interface '$Interface'"
+ wpa_stop "$Interface"
+ bring_interface_down "$Interface"
return 1
fi
- if ! "$CONN_DIR/ethernet" up "$PROFILE"; then
- wireless_down "$PROFILE" YES
+ if ! ip_set; then
+ wpa_stop "$Interface"
+ bring_interface_down "$Interface"
return 1
fi
}
-# wireless_down PROFILE [ LEAVE ifconfig up? default no ]
wireless_down() {
- local PROFILE="$1"
- load_profile "$PROFILE"
-
- "$CONN_DIR/ethernet" down "$PROFILE"
-
- # The config file can contain a non-standard control socket path
- if [[ "$SECURITY" = "wpa-config" ]]; then
- WPA_CONF="${WPA_CONF:-/etc/wpa_supplicant.conf}"
+ ip_unset
+ if [[ $Security == "wpa-config" ]]; then
+ : ${WPAConfigFile:=/etc/wpa_supplicant.conf}
fi
- report_debug wireless_down stop_wpa "$INTERFACE"
- stop_wpa "$INTERFACE"
- rm -rf "$STATE_DIR/wpa.$INTERFACE"
-
- bring_interface down "$INTERFACE"
-
- # Handle wireless kill switches
- # Any reason why a hardware switch should be considered on interface down?
- if [[ "$RFKILL" == "soft" ]]; then
- set_rf_state "$INTERFACE" disabled $RFKILL_NAME || return 1
+ wpa_stop "$Interface"
+ bring_interface_down "$Interface" || return 1
+ if [[ $RFKill ]]; then
+ disable_rf "$Interface" "$RFKill"
fi
}
-wireless_$1 "$2" "$3"
-exit $?
# vim: ft=sh ts=4 et sw=4 tw=0:
-
diff --git a/src/lib/globals b/src/lib/globals
index 491f9d6..8277a40 100644
--- a/src/lib/globals
+++ b/src/lib/globals
@@ -1,136 +1,121 @@
-# /usr/lib/networks/globals
-#
-# All +x files in /usr/lib/network/hooks will be sourced when this file is.
-# Hook files can override any of the utility functions defined here for custom
-# behavior (such as logging error messages to syslog). This lets us keep netcfg
-# simple but gives it the flexibility for users to make modular use of it to do
-# more complex things
-
-
-### Globals
PROFILE_DIR="/etc/network.d"
-IFACE_DIR="$PROFILE_DIR/interfaces"
SUBR_DIR="/usr/lib/network"
-HOOKS_DIR="$SUBR_DIR/hooks"
CONN_DIR="$SUBR_DIR/connections"
STATE_DIR="/run/network"
-
+STATE_FILE="${NETCTL_STATE_FILE:-/var/lib/netctl/netctl.state}"
### Logging/Error reporting
-function report_err {
+report_notice() {
echo "$*"
}
-function report_notice {
+report_error() {
echo "$*"
}
-function report_debug {
- checkyesno "$NETCFG_DEBUG" && echo "DEBUG: $*" >&2
+report_debug() {
+ is_yes "${NETCTL_DEBUG:-no}" && echo "DEBUG: $*" >&2
}
-function report_try {
- # This needs -n and a trailing space.
- echo -n ":: $* "
- REPORT_TRYING=1
+exit_error() {
+ report_error "$@" >&2
+ exit 1
}
-function report_fail {
- if [[ -n "$*" ]]; then
- if (( REPORT_TRYING )); then
- echo "- $* [fail]"
- REPORT_TRYING=
- else
- echo "$*"
- fi
- elif (( REPORT_TRYING )); then
- echo "[fail]"
- REPORT_TRYING=
- fi
-}
-function report_success {
- if [[ -n "$*" ]]; then
- # This needs -n and a trailing space.
- echo -n "- $* "
- fi
- echo "[done]"
- REPORT_TRYING=
+### Variable management
+
+## Check if a variable occurs in an array
+# $1: the variable to find
+# $2...: the array elements
+in_array() {
+ local hay needle=$1
+ shift
+ for hay; do
+ [[ $hay == "$needle" ]] && return 0
+ done
+ return 1
}
-### For calling scripts only; don't use in library functions
-function exit_stderr { echo "$*" >&2; exit 1; }
-function exit_err { report_err "$*"; exit 1; }
-function exit_fail { report_fail "$*"; exit 1; }
-
-
-### From FreeBSD's /etc/rc.subr
-##
-# checkyesno var
-# Test $1 variable, and warn if not set to YES or NO.
-# Return 0 if it's "yes" (et al), nonzero otherwise.
-# To default to yes, do: "checkyesno ${VAR:-yes}".
-#
-function checkyesno() {
- local _value="$1"
- #debug "checkyesno: $1 is set to $_value."
- case "$_value" in
-
- # "yes", "true", "on", or "1"
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+## Check if a variable denotes a positive truth value
+# $1: the variable to check, use is_yes ${VAR:-yes} to set a default
+is_yes() {
+ case ${1,,} in
+ yes|true|on|1)
return 0
;;
-
- # "no", "false", "off", or "0"
- [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
+ no|false|off|0)
return 1
;;
- *)
- #warn "\$${1} is not set properly - see rc.conf(5)."
+ *)
+ report_error "Not a valid truth value: '$1'"
return 1
;;
esac
}
-## Check if variable is a member of an array
-# $1: the variable to find
-# $2...: the array elements
-function inarray() {
- local item search="$1"
- shift
- for item in "$@"; do
- if [[ "$item" == "$search" ]]; then
- return 0
- fi
- done
- return 1
+
+### Control flow
+
+## Show what we evaluate when debugging, but always evaluate
+do_debug() {
+ report_debug "${FUNCNAME[1]}:" "$@"
+ "$@"
+}
+
+## Exit if we are not effectively root
+# $1: program name (optional)
+ensure_root() {
+ (( EUID == 0 )) || exit_error "${1-$0} needs root privileges"
}
## Waits until a statement succeeds or a timeout occurs
# $1: timeout in seconds
# $2...: condition command
-function timeout_wait() {
- local timeout="$1"
- (( timeout *= 10 ))
+timeout_wait() {
+ local timeout=$1
+ (( timeout *= 5 ))
shift
while ! eval "$*"; do
(( timeout-- > 0 )) || return 1
- sleep 0.1
+ sleep 0.2
done
return 0
}
-### Load all +x files in $HOOKS_DIR
-function load_hooks() {
+### Profile management
+
+## List all acceptable profiles names (assume they don't contain newlines)
+list_profiles() {
+ # JP: follow aliases with -L, also skip profiles that end with '.conf' (so
+ # profile.conf can be the wpa.conf file for profile)
+ find -L "$PROFILE_DIR/" -maxdepth 1 -type f -not -name '.*' -not -name '*~' -not -name '*.conf' -not -name '*.service' -printf "%f\n"
+}
+
+## Sources all hooks, a profile and any interface hook
+# $1: profile name
+load_profile() {
local hook
- for hook in $(find -L "$HOOKS_DIR/" -maxdepth 1 -type f -executable | sort -u); do
+ if [[ ! -r "$PROFILE_DIR/$1" ]]; then
+ exit_error "Profile '$1' does not exist or is not readable"
+ fi
+ while read -r hook; do
source "$hook"
- done
+ done < <(find -L "$PROFILE_DIR/hooks" -maxdepth 1 -type f -executable -not -name '.*' -not -name '*~' | sort -u)
+ source "$PROFILE_DIR/$1"
+ if [[ -z $Interface ]]; then
+ exit_error "Profile '$1' does not specify an interface"
+ fi
+ if [[ ! -r "$CONN_DIR/${Connection:-/dev/null/nonexistent}" ]]; then
+ exit_error "Profile '$1' does not specify a valid connection"
+ fi
+ if [[ -x "$PROFILE_DIR/interfaces/$Interface" ]]; then
+ source "$PROFILE_DIR/interfaces/$Interface"
+ fi
}
-load_hooks
# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/ip b/src/lib/ip
new file mode 100644
index 0000000..02d99f4
--- /dev/null
+++ b/src/lib/ip
@@ -0,0 +1,215 @@
+## /usr/lib/network/globals needs to be sourced before this file
+
+
+## Add resolv.conf entries for an interface
+# $1: interface name
+# $2...: entries, one line per variable
+resolvconf_add() {
+ local interface="$1"
+ shift
+ printf "%s\n" "$@" | resolvconf -a "$interface"
+}
+
+
+## Set up an IP configuration
+# $Interface: interface name
+# $IP: type of IPv4 configuration
+# $IP6: type of IPv6 configuration
+ip_set() {
+ local addr line route interface_sysctl=${Interface/.//}
+
+ if [[ -z $IP && -z $IP6 ]]; then
+ report_error "Neither IP, nor IP6 was specified"
+ return 1
+ fi
+
+ case $IP in
+ dhcp)
+ case ${DHCPClient:-dhcpcd} in
+ dhcpcd)
+ rm -f "/run/dhcpcd-$Interface".{pid,cache}
+ # If using own dns, tell dhcpcd to NOT replace resolv.conf
+ [[ $DNS ]] && DhcpcdOptions+=" -C resolv.conf"
+ do_debug dhcpcd -qL -t "${TimeoutDHCP:-10}" $DHCPOptions "$Interface" 2>&1 | report_debug "$(cat)"
+ # The first array value of PIPESTATUS is the exit status of dhcpcd
+ if (( PIPESTATUS != 0 )); then
+ report_error "DHCP IP lease attempt failed on interface '$Interface'"
+ return 1
+ fi
+ ;;
+ dhclient)
+ rm -f "/run/dhclient-${Interface}.pid"
+ if ! do_debug dhclient -q -e "TIMEOUT=${TimeoutDHCP:-10}" -pf "/run/dhclient-$Interface.pid" $DhclientOptions "$Interface"; then
+ report_error "DHCP IP lease attempt failed on interface '$Interface'"
+ return 1
+ fi
+ ;;
+ *)
+ report_error "Unsupported DHCP client: '$DHCPClient'"
+ return 1
+ ;;
+ esac
+ ;;
+ static)
+ if [[ $Address ]]; then
+ for addr in "${Address[@]}"; do
+ [[ $addr == */* ]] || addr+="/24"
+ if ! do_debug ip addr add "$addr" brd + dev "$Interface"; then
+ report_error "Could not add address '$addr' to interface '$Interface'"
+ return 1
+ fi
+ done
+ fi
+ if [[ $Gateway ]]; then
+ if ! do_debug ip route add default via "$Gateway" dev "$Interface"; then
+ report_error "Could not set gateway '$Gateway' on interface '$Interface'"
+ return 1
+ fi
+ fi
+ ;;
+ ""|no)
+ ;;
+ *)
+ report_error "IP must be either 'dhcp', 'static' or 'no'"
+ return 1
+ ;;
+ esac
+
+ # Add static IP routes
+ if [[ $IP && $Routes ]]; then
+ for route in "${Routes[@]}"; do
+ if ! do_debug ip route add $route dev "$Interface"; then
+ report_error "Could not add route '$route' to interface '$Interface'"
+ return 1
+ fi
+ done
+ fi
+
+ # Load ipv6 module if necessary
+ case "$IP6" in
+ dhcp*|stateless|static)
+ [[ -d "/proc/sys/net/ipv6" ]] || modprobe ipv6
+ ;;
+ no)
+ [[ -d "/proc/sys/net/ipv6" ]] && sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=0"
+ ;;
+ "") # undefined IP6 does not prevent RA's from being received -> nop
+ ;;
+ *)
+ report_error "IP6 must be 'dhcp', 'dhcp-noaddr', 'stateless', 'static' or 'no'"
+ return 1
+ ;;
+ esac
+
+ case "$IP6" in
+ dhcp*)
+ if ! type dhclient &>/dev/null; then
+ report_error "You need to install dhclient to use DHCPv6"
+ return 1
+ fi
+ sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=1"
+ [[ $IP6 == "dhcp-noaddr" ]] && Dhclient6Options+=" -S"
+ rm -f "/run/dhclient6-${Interface}.pid"
+ if ! do_debug dhclient -6 -q -e "TIMEOUT=${TimeoutDHCP:-10}" -pf "$Pidfile" $Dhclient6Options "$Interface"; then
+ report_error "DHCPv6 IP lease attempt failed on interface '$Interface'"
+ return 1
+ fi
+ ;;
+ stateless)
+ sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=1"
+ ;;
+ static)
+ sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=0"
+ if [[ -n $Address6 ]]; then
+ for addr in "${Address6[@]}"; do
+ if ! do_debug ip -6 addr add $addr dev "$Interface"; then
+ report_error "Could not add address '$addr' to interface '$Interface'"
+ fi
+ done
+ fi
+ ;;
+ esac
+
+ if [[ $IP6 ]]; then
+ # Wait for Duplicate Address Detection to finish
+ if ! timeout_wait "${TimeoutDAD:-3}" '[[ -z "$(ip -6 addr show dev "$Interface" tentative)" ]]'; then
+ report_error "Duplicate Address Detection is taking too long on interface '$Interface'"
+ return 1
+ fi
+
+ # Add static IPv6 routes
+ if [[ $Routes6 ]]; then
+ for route in "${Routes6[@]}"; do
+ if ! do_debug ip -6 route add $route dev "$Interface"; then
+ report_error "Could not add route '$route' to interface '$Interface'"
+ return 1
+ fi
+ done
+ fi
+
+ # Set a custom gateway after DAD has finished
+ if [[ $IP6 == "static" && $Gateway6 ]]; then
+ if ! do_debug ip -6 route replace default via "$Gateway6" dev "$Interface"; then
+ report_error "Could not set gateway '$Gateway6' on interface '$Interface'"
+ return 1
+ fi
+ fi
+ fi
+
+ if [[ $IPCustom ]]; then
+ for line in "${IPCustom[@]}"; do
+ if ! do_debug ip $line; then
+ report_error "Could not configure interface ($line)"
+ return 1
+ fi
+ done
+ fi
+
+ if [[ $Hostname ]]; then
+ if ! do_debug hostnamectl set-hostname "$Hostname"; then
+ report_error "Cannot set the hostname to '$Hostname'"
+ return 1
+ fi
+ fi
+
+ if [[ $DNS ]]; then
+ resolvconf_add "$Interface" \
+ "${DNSDomain/#/domain }" \
+ "${DNSSearch/#/search }" \
+ "${DNS[@]/#/nameserver }" \
+ "${DNSOptions[@]/#/options }"
+ fi
+}
+
+
+## Clean up the dynamic part of an IP configuration
+# $Interface: interface name
+# $IP: type of IPv4 configuration
+# $IP6: type of IPv6 configuration
+ip_unset() {
+ if [[ "$IP" == "dhcp" ]]; then
+ case $DHCPClient in
+ dhcpcd)
+ if [[ -f "/run/dhcpcd-$Interface.pid" ]]; then
+ do_debug dhcpcd -qk "$Interface" >/dev/null
+ fi
+ ;;
+ dhclient)
+ if [[ -f "/run/dhclient-$Interface.pid" ]]; then
+ # Alternatively, use -r instead of -x to also release the lease
+ do_debug dhclient -q -x "$Interface" -pf "/run/dhclient-$Interface.pid" >/dev/null
+ fi
+ ;;
+ esac
+ fi
+ if [[ "$IP6" == dhcp* ]]; then
+ if [[ -f "/run/dhclient6-$Interface.pid" ]]; then
+ do_debug dhclient -6 -q -x "$Interface" -pf "/run/dhclient6-$Interface.pid" >/dev/null
+ fi
+ fi
+
+ [[ $DNS ]] && resolvconf -d "$Interface"
+}
+
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/network b/src/lib/network
index 1aa384c..1117737 100644..100755
--- a/src/lib/network
+++ b/src/lib/network
@@ -1,368 +1,95 @@
-### Globals
-. /usr/lib/network/globals
-# will load hooks
-
-## Loads a profile.
-# $1: profile name
-load_profile()
-{
- unset ROUTES
- [[ -z "$1" ]] && return 1
- if [[ ! -f "$PROFILE_DIR/$1" ]]; then
- report_err "Profile \"$1\" does not exist"
- return 1
- fi
- report_debug "Loading profile $1"
- INTERFACE=$(. "$PROFILE_DIR/$1"; echo "$INTERFACE")
- report_debug "Configuring interface $INTERFACE"
- if [[ -z "$INTERFACE" ]]; then
- report_err "Profile missing an interface to configure"
- return 1
- fi
- if [[ -f "$IFACE_DIR/$INTERFACE" ]]; then
- report_debug "Interface level configuration enabled: $IFACE_DIR/$INTERFACE"
- . "$IFACE_DIR/$INTERFACE"
- fi
- . "$PROFILE_DIR/$1" # we want profile settings to override, so need to source profile again
- if [[ ! -f "$CONN_DIR/$CONNECTION" ]]; then
- report_err "$CONNECTION is not a valid connection, check spelling or look at examples"
- return 1
- fi
-}
-
-##################
-# Profile up/down
-##################
-
-## Take all registered profiles down.
-all_down()
-{
- find "$STATE_DIR/profiles/" -maxdepth 1 -type f -printf '%f\n' \
- | while read prof; do
- profile_down "$prof"
- done
-}
+#! /bin/bash
-## Create the state dir and sub directories if they don't already exist.
-check_make_state_dir()
-{
- [[ ! -d "$STATE_DIR" ]] && mkdir -p "$STATE_DIR"/{interfaces,profiles}
- for d in interfaces profiles suspend; do
- [[ ! -d "$STATE_DIR/$d" ]] && mkdir "$STATE_DIR/$d"
- done
-}
+. /usr/lib/network/globals
-## Save the list of running profiles and take them down if needed
-# $1: interface name or "all"
-# $2: take associated profiles down (optional, default="yes")
-interface_suspend()
-{
- report_debug interface_suspend "$@"
- check_make_state_dir
- find "$STATE_DIR/profiles/" -maxdepth 1 -type f -printf '%f\n' \
- | while read prof; do
- # the pipe to "while read" will create a subshell
- INTERFACE=$(. "$STATE_DIR/profiles/$prof"; echo "$INTERFACE")
- if [[ "$1" == all || "$1" == "$INTERFACE" ]]; then
- report_notice "suspending interface $INTERFACE with profile $prof"
- cp "$STATE_DIR/profiles/$prof" "$STATE_DIR/suspend/"
- if checkyesno "${2:-yes}"; then
- profile_down "$prof"
- fi
- fi
- done
-}
-
-## Save the list of all running profiles and take them down
-all_suspend() {
- interface_suspend all
+## Check if a string represents a network interface
+# $1: potential interface name
+is_interface() {
+ # Strip any old school alias specifier
+ [[ -d "/sys/class/net/${1%%:?*}" ]]
}
-## Restore saved profiles (for resume purposes).
-# $@: a list of interfaces not to resume (e.g., because they're disabled)
-all_resume()
-{
- report_debug all_resume "$@"
- find "$STATE_DIR/suspend/" -maxdepth 1 -type f -printf '%f\n' \
- | while read prof; do
- # the pipe to "while read" will create a subshell
- INTERFACE=$(. "$STATE_DIR/suspend/$prof"; echo "$INTERFACE")
- if [[ $# -eq 0 || ! " $* " =~ " $INTERFACE " ]]; then
- report_notice "resuming interface $INTERFACE with profile $prof"
- profile_up "$prof"
- rm -f "$STATE_DIR/suspend/$prof" # if profile_up succeeds, it will have already removed this
- fi
- done
+## Check if an interface is up
+# $1: interface name
+interface_is_up() {
+ local flags
+ read flags < "/sys/class/net/${1%%:?*}/flags"
+ # IFF_UP is defined as 0x1 in linux/if.h
+ (( flags & 0x1 ))
}
-## Puts up a profile.
-# $1: the profile name
-profile_up()
-{
- (
- # Keep inside subshell so that options from one profile don't cross to others
- # exit 1 used in a subshell is effectively exiting a new process
- check_make_state_dir
-
- local status PROFILE="$1" # save PROFILE in a variable so that it's available to PRE_UP/POST_DOWN etc hooks
-
- load_profile "$PROFILE" || exit 1
-
- if check_profile "$PROFILE"; then
- report_err "$PROFILE already connected"
+## Activate an interface
+# $1: interface name
+bring_interface_up() {
+ local interface=$1
+ ip link set dev "$interface" up &>/dev/null
+ timeout_wait "${TimeoutUp:-5}" 'interface_is_up "$interface"'
+}
+
+## Deactivate an interface
+# $1: interface name
+bring_interface_down() {
+ local interface=$1
+ ip addr flush dev "$interface" &>/dev/null
+ ip link set dev "$interface" down &>/dev/null
+ # We reuse the up timeout (down normally is faster)
+ timeout_wait "${TimeoutUp:-5}" '! interface_is_up "$interface"'
+}
+
+
+if [[ $# -ne 2 || $1 != @(start|stop) ]]; then
+ exit_error "Usage: $0 {start|stop} <profile>"
+fi
+ensure_root netctl
+# Ensure we are not in a transient directory
+cd /
+
+# Expose the profile name
+Profile=$2
+load_profile "$Profile"
+source "$CONN_DIR/$Connection"
+case $1 in
+ start)
+ report_notice "Starting network profile '$Profile'..."
+ if is_interface "$Interface" && interface_is_up "$Interface" && \
+ ! is_yes "${ForceConnect:-no}"; then
+ report_error "The interface of network profile '$Profile' is already up"
exit 1
fi
-
- # EXCLUSIVE, network.d/profile: Individual profile is mutually exclusive
- if checkyesno "$EXCLUSIVE"; then
- all_down
- fi
-
- report_try "$PROFILE up"
-
- status=$(check_iface "$INTERFACE")
- report_debug "status reported to profile_up as: $status"
- case "$status" in
- external)
- report_fail "Interface $INTERFACE externally controlled"
- exit 1
- ;;
- disabled)
- report_fail "Interface $INTERFACE is disabled"
- exit 1
- ;;
- "")
- ;;
- *)
- if checkyesno "$CHECK"; then
- report_fail "Interface $INTERFACE already in use"
- exit 1
-
- # not necessary to sandbox this call or reload PROFILE afterwards
- elif ! interface_down "$INTERFACE"; then
- report_fail
- exit 1
- fi
- ;;
- esac
-
- if ! ( eval $PRE_UP ); then # JP: sandbox the eval so variables don't bleed into current function
- report_debug profile_up "PRE_UP failed"
- report_fail
+ if ! "${Connection}_up"; then
+ report_error "Failed to bring the network up for profile '$Profile'"
exit 1
fi
-
- if ! "$CONN_DIR/$CONNECTION" up "$PROFILE"; then
- report_debug profile_up "connect failed"
- report_fail
- # "$CONN_DIR/$CONNECTION" down "$PROFILE" # JP: should we do this to make sure?
+ # JP: sandbox the eval
+ if ! ( eval $ExecUpPost ); then
+ report_error "ExecUpPost failed for network profile '$Profile'"
+ # Failing ExecUpPost will take the connection down
+ "${Connection}_down"
exit 1
fi
-
- if ! ( eval $POST_UP ); then # JP: sandbox the eval
- report_debug profile_up "POST_UP failed"
- report_fail
- # failing POST_UP will take interface down
- "$CONN_DIR/$CONNECTION" down "$PROFILE"
+ report_notice "Started network profile '$Profile'"
+ ;;
+ stop)
+ report_notice "Stopping network profile '$Profile'..."
+ # JP: sandbox the eval
+ if ! ( eval $ExecDownPre ); then
+ report_error "ExecDownPre failed for network profile '$Profile'"
+ # Failing ExecDownPre will leave the profile active
exit 1
fi
-
- set_profile up "$PROFILE"
- unset EXCLUSIVE
-
- # Successfully running a new profile; erase any suspended profiles on this interface
- local iface="$INTERFACE"
- find "$STATE_DIR/suspend/" -maxdepth 1 -type f -printf '%f\n' \
- | while read prof; do
- # the pipe to "while read" will create a subshell
- INTERFACE=$(. "$STATE_DIR/suspend/$prof"; echo "$INTERFACE")
- if [[ "$iface" == "$INTERFACE" ]]; then
- rm "$STATE_DIR/suspend/$prof"
- fi
- done
-
- report_success
- ); return $?
-}
-
-## Puts a profile down.
-# $1: the profile name
-profile_down()
-{
- (
- check_make_state_dir
-
- local status PROFILE="$1" # save PROFILE in a variable so that it's available to PRE_UP/POST_DOWN etc hooks
-
- load_profile "$PROFILE" || exit 1
-
- status=$(check_iface "$INTERFACE")
- report_debug "status reported to profile_down as: $status"
-
- if [[ "$status" != "$PROFILE" ]]; then
- # if interface not available to be controlled by netcfg, then
- # any profiles should have been removed by check_iface
- # else we get here if another profile is running
- report_err "Profile not connected"
+ if ! "${Connection}_down"; then
+ report_error "Failed to bring the network down for profile '$Profile'"
exit 1
fi
-
- report_try "$PROFILE down"
- if [[ "$(check_iface "$INTERFACE")" == "external" ]]; then
- report_fail "$interface was connected by another application"
+ if is_interface "$Interface" && interface_is_up "$Interface" && \
+ ! is_yes "${ForceConnect:-no}"; then
+ report_error "The interface of network profile '$Profile' did not go down"
exit 1
fi
+ report_notice "Stopped network profile '$Profile'"
+ ;;
+esac
- if ! ( eval $PRE_DOWN ); then # JP: sandbox the eval
- report_debug profile_down "PRE_DOWN failed"
- # true # JP: did we want failing PRE_DOWN to leave the profile active?
- report_fail
- exit 1
- fi
-
- if ! "$CONN_DIR/$CONNECTION" down "$PROFILE"; then
- report_debug profile_up "disconnect failed"
- report_fail
- exit 1
- fi
-
- if ! ( eval $POST_DOWN ); then # JP: sandbox the eval
- report_debug profile_down "POST_DOWN failed"
- report_fail
- exit 1
- fi
-
- set_profile down "$PROFILE"
- report_success
- ); return $?
-}
-
-# interface_down interface
-# take interface down
-#
-interface_down()
-{
- local profile=$(check_iface "$1")
- case "$profile" in
- ""|disabled) return 0 ;;
- external) return 1 ;;
- *) profile_down "$profile" ;;
- esac
-}
-
-# interface_reconnect interface
-# reconnects the profile active on interface
-interface_reconnect()
-{
- local profile=$(check_iface "$1")
- case "$profile" in
- ""|disabled|external)
- return 1
- ;;
- *)
- profile_down "$profile"
- profile_up "$profile"
- ;;
- esac
-}
-
-##
-# check_iface interface
-# Return 0 if interface unavailable (in use by a profile or externally, or disabled)
-# Return 1 if interface down and available to be used
-#
-check_iface() {
- if [[ -f "$STATE_DIR/interfaces/$1" ]]; then
- cat "$STATE_DIR/interfaces/$1"
- return 0
- else
- return 1
- fi
-}
-
-# list_profiles
-# Outputs a list of all profiles
-list_profiles() {
- # JP: follow aliases with -L, also skip profiles that start with '.' or end with '~' or '.conf' (so profile.conf can be the wpa.conf file for profile)
- find -L "$PROFILE_DIR/" -maxdepth 1 -type f -not -name '*~' -not -name '*.conf' -not -name '.*' -printf "%f\n"
-}
-
-# check_profile profile
-# Return 0 if profile registered as being up
-# Return 1 if profile not registered
-#
-check_profile() {
- [[ -f "$STATE_DIR/profiles/$1" && ! -f "$STATE_DIR/suspend/$1" ]] && return 0
- return 1
-}
-
-### Status setting functions
-##
-# set_profile up/down profile
-# Set profile state, either up or down
-#
-set_profile() {
- local INTERFACE
- if [[ "$1" == "up" ]]; then
- INTERFACE=$(. "$PROFILE_DIR/$2"; echo "$INTERFACE")
- cp "$PROFILE_DIR/$2" "$STATE_DIR/profiles/"
- set_iface up "$INTERFACE" "$2"
- elif [[ "$1" == "down" && -f "$STATE_DIR/profiles/$2" ]]; then # JP: skip if profile not already up
- INTERFACE=$(. "$STATE_DIR/profiles/$2"; echo "$INTERFACE")
- rm "$STATE_DIR/profiles/$2"
- set_iface down "$INTERFACE" "$2"
- fi
-}
-
-# set_iface up/down interface [profile]
-# Set interface status to up/down
-# optionally link it to a profile.
-#
-set_iface() {
- local PROFILE="${3:-external}"
- if [[ "$1" == "up" ]]; then
- echo "$PROFILE" > "$STATE_DIR/interfaces/$2"
- elif [[ "$1" == "down" ]]; then
- rm -f "$STATE_DIR/interfaces/$2" # JP: add -f so we don't complain if the interface isn't up
- fi
-}
-
-is_interface() {
- local INTERFACE="$1"
- if [[ ! -e "/sys/class/net/$INTERFACE" ]]; then
- if ! echo "$INTERFACE" | grep -F -q ":"; then
- return 1
- fi
- fi
- return 0
-}
-
-interface_is_up() {
- local flags
- read flags < "/sys/class/net/$1/flags"
- # IFF_UP is defined as 0x1 in linux/if.h
- (( flags & 0x1 ))
-}
-
-## Changes a network interface state.
-# $1: up, flush, or down.
-# $2: the interface name
-bring_interface()
-{
- local INTERFACE="$2"
- case "$1" in
- up)
- ip link set dev "$INTERFACE" up &>/dev/null
- timeout_wait "${UP_TIMEOUT:-5}" 'interface_is_up "$INTERFACE"' || return 1
- ;;
- flush|down)
- ip addr flush dev "$INTERFACE" &>/dev/null
- ;;&
- down)
- ip link set dev "$INTERFACE" down &>/dev/null
- ;;
- esac
-}
# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/rfkill b/src/lib/rfkill
index 1832dc1..996e463 100644
--- a/src/lib/rfkill
+++ b/src/lib/rfkill
@@ -1,61 +1,60 @@
-set_rf_state() {
- local INTERFACE="$1" state="$2" RFKILL_NAME="$3"
+## /usr/lib/network/globals needs to be sourced before this file
- if [[ "$RFKILL" == "hard" ]]; then
- report_fail "Cannot set state on hardware rfkill switch"
- return 1
- fi
- local path=$(get_rf_path "$INTERFACE" "$RFKILL_NAME") || return 1
- case "$state" in
- enabled)
- echo 0 > "$path/soft"
- ;;
- disabled)
- echo 1 > "$path/soft"
- ;;
- esac
-}
+## Determine the system interface of an rfkill device
+# $1: interface name
+# $2: rfkill name
get_rf_path() {
- local INTERFACE="$1" RFKILL_NAME="$2" path
+ local interface=$1 rfkill_name=${2:-auto} path
- if [[ -n "$RFKILL_NAME" ]]; then
+ if [[ $rfkill_name == "auto" ]]; then
+ path=$(find -L "/sys/class/net/$interface/" -maxdepth 2 -type d -name "rfkill*" 2> /dev/null | head -n 1)
+ if [[ $path ]]; then
+ echo "$path"
+ return 0
+ fi
+ report_error "No rfkill switch available on interface '$interface'"
+ else
for path in /sys/class/rfkill/*; do
- if [[ "$(< "$path/name")" == "$RFKILL_NAME" ]]; then
+ if [[ $(< "$path/name") == "$rfkill_name" ]]; then
echo "$path"
return 0
fi
done
- report_fail "no rfkill switch with name $RFKILL_NAME"
- else
- path=$(find -L "/sys/class/net/$INTERFACE/" -maxdepth 2 -type d -name "rfkill*" 2> /dev/null | head -n 1)
- if [[ -n "$path" ]]; then
- echo "$path"
- return 0
- fi
- report_fail "no rfkill switch available on interface $INTERFACE"
+ report_error "No rfkill switch with name '$rfkill_name'"
fi
return 1
}
+## Unblock transmission through a wireless device
+# $1: interface name
+# $2: rfkill name
enable_rf() {
- local INTERFACE="$1" RFKILL="$2" RFKILL_NAME="$3" path hard soft
-
- # Enable rfkill if necessary, or fail if it is hardware
- if [[ -n "$RFKILL" ]]; then
- path=$(get_rf_path "$INTERFACE" "$RFKILL_NAME") || return 1
- read hard < "$path/hard"
- read soft < "$path/soft"
-
- if (( hard )); then
- report_fail "radio is disabled on $INTERFACE"
- return 1
- elif (( soft )); then
- set_rf_state "$INTERFACE" enabled "$RFKILL_NAME" || return 1
- timeout_wait 1 "(( ! \$(< \"$path/soft\") ))"
- fi
+ local interface=$1 rfkill=$2 path hard soft
+
+ path=$(get_rf_path "$interface" "$rfkill") || return 1
+ read hard < "$path/hard"
+ read soft < "$path/soft"
+
+ if (( hard )); then
+ report_error "Transmission is hard-blocked on interface '$interface'"
+ return 1
+ elif (( soft )); then
+ do_debug echo 0 > "$path/soft"
+ timeout_wait 1 '(( ! $(< "$path/soft") ))'
fi
}
-# vim: ft=sh ts=4 et sw=4:
+## Block transmission through a wireless device
+# $1: interface name
+# $2: rfkill name
+disable_rf() {
+ local interface=$1 rfkill=$2 path
+
+ path=$(get_rf_path "$interface" "$rfkill") || return 1
+ do_debug echo 1 > "$path/soft"
+ timeout_wait 1 '(( $(< "$path/soft") ))'
+}
+
+# vim: ft=sh ts=4 et sw=4: