diff options
author | James Rayner <james@archlinux.org> | 2009-08-07 16:23:45 +0200 |
---|---|---|
committer | James Rayner <james@archlinux.org> | 2009-08-07 16:23:45 +0200 |
commit | 54e39849f1e60eb043f9d8f0904acf3c79d96a1c (patch) | |
tree | 9c10a01ea0ba58d31b3ab8282ead767da49264d3 /src/connections | |
parent | f7168ae05837a24060b41511be6e4626cb26828a (diff) | |
download | netctl-54e39849f1e60eb043f9d8f0904acf3c79d96a1c.tar.gz netctl-54e39849f1e60eb043f9d8f0904acf3c79d96a1c.tar.xz |
Patch from Jim Pryor
Diffstat (limited to 'src/connections')
-rw-r--r-- | src/connections/ethernet | 211 | ||||
-rw-r--r-- | src/connections/ethernet-iproute | 214 | ||||
-rw-r--r-- | src/connections/ppp | 53 | ||||
-rw-r--r-- | src/connections/wireless | 368 |
4 files changed, 693 insertions, 153 deletions
diff --git a/src/connections/ethernet b/src/connections/ethernet index e24e9f5..933dbd6 100644 --- a/src/connections/ethernet +++ b/src/connections/ethernet @@ -1,86 +1,114 @@ #! /bin/bash + +################################## +## +# /usr/lib/network/connections/ethernet +## +################################## + +. /etc/rc.conf +. /etc/rc.d/functions . /usr/lib/network/network ethernet_up() { - load_profile $1 + load_profile "$1" - if [[ ! -e /sys/class/net/"$INTERFACE" ]]; then - if ! echo "$INTERFACE"|grep ":"; then - err_append "interface $INTERFACE does not exist" + if [[ ! -e "/sys/class/net/$INTERFACE" ]]; then + if ! echo "$INTERFACE" | fgrep -q ":"; then + report_fail "Interface $INTERFACE does not exist." return 1 fi fi - ip link set $INTERFACE up - sleep 1 + report_debug ethernet_up ifup + ethernet_control "$INTERFACE" up + sleep 3 - if ip link show $INTERFACE|grep -q "NO-CARRIER"; then - err_append "No connection" + # don't think it's possible to detect carrier using ifconfig alone (at least, not without ifdown/ifupping the interface) + # if ip link show dev "$INTERFACE" | fgrep -q "NO-CARRIER"; then... + # if ! ethernet_query "$INTERFACE" address; then... + if [[ $(cat /sys/class/net/$INTERFACE/carrier 2>/dev/null) -ne 1 ]]; then # gives err if iface inactive (i.e. ifdown) + # 0 if up but not connected to network, 1 if connected + report_fail "No connection." return 1 fi if checkyesno "${AUTH8021X:-no}"; then - . "${SUBR_DIR}"/8021x + . "$SUBR_DIR/8021x" [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf" [[ -z "$WPA_OPTS" ]] && WPA_OPTS="-Dwired" + report_debug ethernet_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_OPTS" start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_OPTS" if ! wpa_check "$INTERFACE"; then - ifconfig "$INTERFACE" down + ethernet_control "$INTERFACE" forcedown # JP: forcedown ignores the nodown quirk, matching + # what was already here in the code...do we in fact want to ignore + # the nodown quirk here? return 1 fi fi - case $IP in + case "$IP" in dhcp) if checkyesno "${DHCLIENT:-no}"; then - rm -r /var/run/dhclient-${INTERFACE}.pid >/dev/null 2>&1 - if ! dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf /var/run/dhclient-${INTERFACE}.pid $INTERFACE; then - err_append "DHCP IP lease attempt failed." + rm -r "/var/run/dhclient-$INTERFACE.pid" >/dev/null 2>&1 + report_debug ethernet_up dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf "/var/run/dhclient-$INTERFACE.pid" "$INTERFACE" + if ! dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf "/var/run/dhclient-$INTERFACE.pid" "$INTERFACE"; then + report_fail "Couldn't get DHCP IP lease." return 1 fi else # Clear remaining pid files. - rm -f /var/run/dhcpcd-${INTERFACE}.{pid,cache} >/dev/null 2>&1 + rm -f "/var/run/dhcpcd-$INTERFACE".{pid,cache} >/dev/null 2>&1 # If using own dns, tell dhcpcd to NOT replace resolv.conf - [[ -n "$DNS1" ]] && DHCP_OPTIONS="-C resolv.conf $DHCP_OPTIONS" - # Start dhcpcd - if ! dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCP_OPTIONS "$INTERFACE"; then - err_append "DHCP IP lease attempt failed." + [[ -n "$DNS1" || -n "$DNS" ]] && DHCP_OPTIONS="-C resolv.conf $DHCP_OPTIONS" + + #if ! dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCP_OPTIONS "$INTERFACE" >/dev/null 2>&1; then + report_debug ethernet_up dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCP_OPTIONS "$INTERFACE" + dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCP_OPTIONS "$INTERFACE" 2>&1 | report_debug $(cat) + if [[ "$PIPESTATUS" -ne 0 ]]; then + report_fail "Couldn't get DHCP IP lease." return 1 fi fi - [[ -n "$IFOPTS" ]] && ifconfig "$INTERFACE" $IFOPTS + if [[ -n "$IFOPTS" ]]; then + report_debug ethernet_up ifup $IFOPTS + ifconfig "$INTERFACE" $IFOPTS + fi ;; static) + report_debug ethernet_up ifup $IFOPTS if ! ifconfig "$INTERFACE" $IFOPTS up; then - err_append "Bringing interface up failed." + report_fail "Couldn't configure $INTERFACE interface." return 1 fi # bring up the default route (gateway) if [[ -n "$GATEWAY" ]]; then - if ! route add default gw $GATEWAY; then - err_append "Adding gateway failed." + report_debug ethernet_up route add default gw "$GATEWAY" + if ! route add default gw "$GATEWAY"; then + ethernet_control "$INTERFACE" down # JP: don't we want to take the interface down if we failed (as ethernet-iproute does?) + report_fail "Couldn't add gateway $GATEWAY." return 1 fi fi ;; *) - err_append "IP=\"\" must be either 'dhcp' or 'static'." + report_err "Profile error: must be either IP=dhcp or IP=static." return 1 ;; esac # set the hostname if [[ -n "$HOSTNAME" ]]; then + report_debug ethernet_up hostname "$HOSTNAME" if ! hostname "$HOSTNAME"; then - err_append "Setting hostname failed." + report_fail "Couldn't set hostname." return 1 fi fi # Generate a new resolv.conf - if [[ -n "$DNS1" ]] || [[ -n "$DNS" ]]; then + if [[ -n "$DNS1" || -n "$DNS" ]]; then : >/etc/resolv.conf [[ -n "$DOMAIN" ]] && echo "domain $DOMAIN" >>/etc/resolv.conf @@ -94,36 +122,141 @@ ethernet_up() { done fi fi + + # 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, so sourced variables will already be in a sandbox + # we just need to clear INTERFACE which is all we care about + unset INTERFACE + . "$STATE_DIR/suspend/$prof" + if [[ "$iface" == "$INTERFACE" ]]; then + rm "$STATE_DIR/suspend/$prof" + fi + done + return 0 } ethernet_down() { - load_profile $1 - case $IP in + load_profile "$1" + case "$IP" in dhcp) if checkyesno "${DHCLIENT:-no}"; then - if [[ -f /var/run/dhclient-${INTERFACE}.pid ]]; then - kill `cat /var/run/dhclient-${INTERFACE}.pid` + if [[ -f "/var/run/dhclient-$INTERFACE.pid" ]]; then + report_debug ethernet_down kill dhclient + kill $(cat "/var/run/dhclient-$INTERFACE.pid") fi else - if [[ -f /var/run/dhcpcd-${INTERFACE}.pid ]]; then - dhcpcd -qx "$INTERFACE" + if [[ -f "/var/run/dhcpcd-$INTERFACE.pid" ]]; then + report_debug ethernet_down dhcpcd -qx "$INTERFACE" + dhcpcd -qx "$INTERFACE" >/dev/null 2>&1 fi fi ;; static) - [[ -n "$GATEWAY" ]] && route del default gw $GATEWAY + if [[ -n "$GATEWAY" ]]; then + report_debug ethernet_down route del default gw "$GATEWAY" + route del default gw "$GATEWAY" + fi ;; esac - ifconfig $INTERFACE 0.0.0.0 - - case "$CONNECTION" in # Keep interface up for wireless - ethernet|ethernet-old) - quirk "nodown" || ifconfig $INTERFACE down + + report_debug ethernet_down ifdown + ethernet_control "$INTERFACE" down +} + +# CONNECTION_query $INTERFACE [ profile | enabled (i.e. not rfkill-ed) | active (i.e. ifup'd) | associated | address ] +ethernet_query() { + local INTERFACE="$1" REQUEST="$2" + # report_debug ethernet_query "$@" + case "$REQUEST" in + + # JP: this duplicates code in ethernet-iproute, but doing so was necessary to refactor these functions into the CONNECTION scripts + profile) + # return code = 1 if iface is available to be used + # return code = 0 if unavailable (disabled, or in use by another profile or by external config) + # echo "" | "disabled" | "external" | PROFILE_NAME + if [[ ! -f "$STATE_DIR/interfaces/$INTERFACE" ]]; then + # interface is up but has no registered profile + if ethernet_query "$INTERFACE" address; then + set_iface up "$INTERFACE" external + echo "external" + return 0 + fi + # no ip address, count as inactive + # should we ifconfig iface down? no, may be up for a reason + return 1 + + else # interface is up and thinks it's running a profile + . "$STATE_DIR/interfaces/$INTERFACE" # these files should only contain a PROFILE=... statement + case "$PROFILE" in + external) + echo "external" + return 0 + ;; + disabled) # shouldn't happen for non-wireless interfaces, but leaving this here in case... + # iface should be down if it's disabled + ethernet_control "$INTERFACE" down + echo "disabled" + return 0 + ;; + *) + ( # use subshell to prevent overwriting currently loaded profile + . "$STATE_DIR/profiles/$PROFILE" + if ! ethernet_query "$INTERFACE" address; then + report_warn "INTERFACE $INTERFACE is inactive; no longer being controlled by $PROFILE" + set_profile down "$PROFILE" + exit 1 + else + echo "$PROFILE" # associated with loaded profile + exit 0 + fi + ) + # return $? + ;; + esac + fi + ;; + + active) + ifconfig "$INTERFACE" | fgrep -qw UP + # cat /sys/class/net/wlan0/carrier >/dev/null # gives err if iface inactive, 0 if up but not connected to network, 1 if connected + ;; + + address) + ifconfig "$INTERFACE" | fgrep -q addr: + ;; + + *) return 1 ;; + esac +} + +# CONNECTION_control $INTERFACE [ up | down | forcedown | enable | disable ] +ethernet_control() { + local INTERFACE="$1" ACTION="$2" + #report_debug ethernet_control "$@" + case "$ACTION" in + up) ifconfig "$INTERFACE" up 2>/dev/null + ethernet_query "$INTERFACE" active + ;; + down|forcedown) + ifconfig "$1" 0.0.0.0 + if [[ "$2" = forcedown ]] || ! quirk nodown; then + ifconfig "$INTERFACE" down + fi + ;; + *) return 1 ;; esac } -ethernet_$1 $2 +ethernet_verify() { + local INTERFACE="$1" + # do nothing +} + +ethernet_$1 "$2" "$3" exit $? # vim: set ts=4 et sw=4: diff --git a/src/connections/ethernet-iproute b/src/connections/ethernet-iproute index 1a4a6e4..8ecabe8 100644 --- a/src/connections/ethernet-iproute +++ b/src/connections/ethernet-iproute @@ -1,85 +1,102 @@ #! /bin/bash + +################################## +## +# /usr/lib/network/connections/ethernet-iproute +## +################################## + +. /etc/rc.conf +. /etc/rc.d/functions . /usr/lib/network/network -error() -{ - err_append "$*" - ip addr flush $INTERFACE &>/dev/null - quirk "nodown" || ip link set $INTERFACE down &>/dev/null +report_iproute() { + report_"$@" + ethernet_control "$INTERFACE" down exit 1 } ethernet_up() { - load_profile $1 + load_profile "$1" - if [[ ! -e /sys/class/net/$INTERFACE ]]; then - if ! echo "$INTERFACE"|grep ":"; then - error "Interface $INTERFACE does not exist" + if [[ ! -e "/sys/class/net/$INTERFACE" ]]; then + if ! echo "$INTERFACE" | fgrep -q ":"; then + report_iproute fail "Interface $INTERFACE does not exist." fi fi - ip link set $INTERFACE up - sleep 1 + report_debug ethernet_iproute_up ifup + ethernet_control "$INTERFACE" up + sleep 3 - if ip link show $INTERFACE|grep -q "NO-CARRIER"; then - err_append "No connection" - return 1 + # if ! ethernet_query "$INTERFACE" address; then... + if ip link show dev "$INTERFACE" | fgrep -q "NO-CARRIER"; then # JP: shouldn''t we include the "dev"? + report_iproute fail "No connection." fi - - if checkyesno ${AUTH8021X:-no}; then - . ${SUBR_DIR}/8021x + + if checkyesno "${AUTH8021X:-no}"; then + . "$SUBR_DIR/8021x" [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf" [[ -z "$WPA_OPTS" ]] && WPA_OPTS="-Dwired" - + report_debug ethernet_iproute_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_OPTS" start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_OPTS" if ! wpa_check "$INTERFACE"; then - ip link set $INTERFACE down + ethernet_control "$INTERFACE" forcedown # JP: forcedown ignores the nodown quirk, matching + # what was already here in the code...do we in fact want to ignore + # the nodown quirk here? return 1 fi fi - case $IP in + case "$IP" in dhcp) # Clear remaining pid files. - rm -f /var/run/dhcpcd-${INTERFACE}.{pid,cache} >/dev/null 2>&1 - + rm -f "/var/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" - - if ! dhcpcd -qL -t ${DHCP_TIMEOUT:-10} $DHCP_OPTIONS $INTERFACE; then - error "DHCP IP lease attempt failed" + + #if ! dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCP_OPTIONS "$INTERFACE" >/dev/null 2>&1; then + report_debug ethernet_iproute_up dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCP_OPTIONS "$INTERFACE" + dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCP_OPTIONS "$INTERFACE" 2>&1 | report_iproute debug $(cat) + if [[ "$PIPESTATUS" -ne 0 ]]; then + report_iproute fail "Couldn't get DHCP IP lease." fi ;; static) if [[ -n "$ADDR" ]]; then - if ! ip addr add ${ADDR}/24 brd + dev $INTERFACE; then - error "Could not configure interface" + report_debug ethernet_iproute_up ip addr add "$ADDR/24" brd + dev "$INTERFACE" + if ! ip addr add "$ADDR/24" brd + dev "$INTERFACE"; then + report_iproute fail "Couldn't configure $INTERFACE interface." fi fi if [[ -n "$GATEWAY" ]]; then - if ! ip route add default via $GATEWAY; then - error "Adding gateway failed" + report_debug ethernet_iproute_up ip route add default via "$GATEWAY" + if ! ip route add default via "$GATEWAY"; then + + report_iproute fail "Couldn't add gateway $GATEWAY." fi fi ;; *) - error "Profile error: IP must be either 'dhcp' or 'static'" + report_iproute err "Profile error: must be either IP=dhcp or IP=static." ;; esac if [[ -n "$IPCFG" ]]; then for line in "${IPCFG[@]}"; do - if ! ip $line; then - error "Could not configure interface" + report_debug ethernet_iproute_up ip "$line" + if ! ip "$line"; then + report_iproute fail "Couldn't configure $INTERFACE interface ($line)." fi done fi - # Set hostname + # set the hostname if [[ -n "$HOSTNAME" ]]; then - if ! hostname $HOSTNAME; then - error "Cannot set hostname" + report_debug ethernet_iproute_up hostname "$HOSTNAME" + if ! hostname "$HOSTNAME"; then + report_iproute fail "Couldn't set hostname." fi fi @@ -89,29 +106,132 @@ ethernet_up() { [[ -n "$DOMAIN" ]] && echo "domain $DOMAIN" >>/etc/resolv.conf [[ -n "$SEARCH" ]] && echo "search $SEARCH" >>/etc/resolv.conf - if [[ -n "$DNS" ]]; then - for dns in ${DNS[@]}; do - echo "nameserver $dns" >>/etc/resolv.conf - done - fi + for dns in "${DNS[@]}"; do + echo "nameserver $dns" >>/etc/resolv.conf + done fi + + # 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, so sourced variables will already be in a sandbox + # we just need to clear INTERFACE which is all we care about + unset INTERFACE + . "$STATE_DIR/suspend/$prof" + if [[ "$iface" == "$INTERFACE" ]]; then + rm "$STATE_DIR/suspend/$prof" + fi + done + return 0 } ethernet_down() { - load_profile $1 + load_profile "$1" - if [[ "$IP" == "dhcp" ]]; then - if [[ -f /var/run/dhcpcd-${INTERFACE}.pid ]]; then - dhcpcd -qx $INTERFACE + if [[ "$IP" == dhcp ]]; then + if [[ -f "/var/run/dhcpcd-$INTERFACE.pid" ]]; then + report_debug ethernet_iproute_down dhcpcd -qx "$INTERFACE" + dhcpcd -qx "$INTERFACE" >/dev/null 2>&1 fi fi - ip addr flush $INTERFACE - quirk "nodown" || ip link set $INTERFACE down + report_debug ethernet_iproute_down if_down + ethernet_control "$INTERFACE" down +} + +# CONNECTION_query $INTERFACE [ profile | enabled (i.e. not rfkill-ed) | active (i.e. ifup'd) | associated | address ] +ethernet_query() { + local INTERFACE="$1" REQUEST="$2" + # report_debug ethernet_iproute_query "$@" + case "$REQUEST" in + + profile) + # return code = 1 if iface is available to be used + # return code = 0 if unavailable (disabled, or in use by another profile or by external config) + # echo "" | "disabled" | "external" | PROFILE_NAME + if [[ ! -f "$STATE_DIR/interfaces/$INTERFACE" ]]; then + # interface is up but has no registered profile + if ethernet_query "$INTERFACE" address; then + set_iface up "$INTERFACE" external + echo "external" + return 0 + fi + # no ip address, count as inactive + # should we ifconfig iface down? no, may be up for a reason + return 1 + + else # interface is up and thinks it's running a profile + . "$STATE_DIR/interfaces/$INTERFACE" # these files should only contain a PROFILE=... statement + case "$PROFILE" in + external) + echo "external" + return 0 + ;; + disabled) # shouldn't happen for non-wireless interfaces, but leaving this here in case... + # iface should be down if it's disabled + ethernet_control "$INTERFACE" down + echo "disabled" + return 0 + ;; + *) + ( # use subshell to prevent overwriting currently loaded profile + . "$STATE_DIR/profiles/$PROFILE" + if ! ethernet_query "$INTERFACE" address; then + report_warn "INTERFACE $INTERFACE is inactive; no longer being controlled by $PROFILE" + set_profile down "$PROFILE" + exit 1 + else + echo "$PROFILE" # associated with loaded profile + exit 0 + fi + ) + # return $? + ;; + esac + fi + ;; + + active) + ip -o link show dev "$INTERFACE" | egrep -qw '^[^>]*,UP' # man ip is inconsistent about whether to use "dev" + # cat /sys/class/net/wlan0/carrier >/dev/null # gives err if iface inactive, 0 if up but not connected to network, 1 if connected + ;; + + address) + test -n "$(ip -o addr show dev "$INTERFACE" | sed -n '2p')" + # ip link show dev "$INTERFACE" | fgrep -q "NO-CARRIER" + ;; + + *) return 1 ;; + esac +} + +# CONNECTION_control $INTERFACE [ up | down | forcedown | enable | disable ] +ethernet_control() { + local INTERFACE="$1" ACTION="$2" + #report_debug ethernet_iproute_control "$@" + case "$ACTION" in + up) + ip link set dev "$INTERFACE" up 2>/dev/null # man ip is inconsistent about whether to use "dev" + ethernet_query "$INTERFACE" active + ;; + down|forcedown) + ip addr flush dev "$INTERFACE" &>/dev/null + if [[ "$2" = forcedown ]] || ! quirk nodown; then + ip link set dev "$INTERFACE" down &>/dev/null # man ip is inconsistent about whether to use "dev" + fi + ;; + *) return 1 + ;; + esac +} +ethernet_verify() { + local INTERFACE="$1" + # do nothing } -ethernet_$1 $2 +ethernet_$1 "$2" "$3" exit $? # vim: set ts=4 et sw=4: diff --git a/src/connections/ppp b/src/connections/ppp index 9432323..ce3c8ab 100644 --- a/src/connections/ppp +++ b/src/connections/ppp @@ -1,25 +1,58 @@ #! /bin/bash +################################## +## +# /usr/lib/network/connections/ppp +## +################################## + +. /etc/rc.conf +. /etc/rc.d/functions . /usr/lib/network/network ppp_up() { - load_profile $1 - [[ -z "$PEER" ]] && PEER="provider" + load_profile "$1" + [[ -z "$PEER" ]] && PEER=provider [[ -z "$PPP_TIMEOUT" ]] && PPP_TIMEOUT=30 - /usr/sbin/pppd call $PEER updetach child-timeout $PPP_TIMEOUT linkname $PEER - - if [[ $? -ne 0 ]]; then - err_append "pppd connection failed" - exit 1 + if ! /usr/sbin/pppd call "$PEER" updetach child-timeout "$PPP_TIMEOUT" linkname "$PEER"; then + report_fail "Couldn't make pppd connection." + return 1 fi + + # wireless and wireless-dbus connections run this block when they call "ethernet up"; but ppp needs to do it itself + # successfully running a new profile; erase any suspended profiles on this interface + local interface="$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, so sourced variables will already be in a sandbox + # we just need to clear INTERFACE which is all we care about + unset INTERFACE + . "$STATE_DIR/suspend/$prof" + if [[ "$interface" == "$INTERFACE" ]]; then + rm "$STATE_DIR/suspend/$prof" + fi + done } ppp_down() { - load_profile $1 - kill $(head -1 /var/run/ppp-$(basename $PEER).pid) + load_profile "$1" + kill $(head -1 "/var/run/ppp-$(basename "$PEER").pid") +} + +ppp_query() { + "$CONN_DIR/ethernet" query "$@" +} + +ppp_control() { + "$CONN_DIR/wireless" control "$@" +} + +ppp_verify() { + local INTERFACE="$1" + # do nothing } -ppp_$1 $2 +ppp_$1 "$2" exit $? # vim: set ts=4 et sw=4: diff --git a/src/connections/wireless b/src/connections/wireless index 8b43ed1..f316cb7 100644 --- a/src/connections/wireless +++ b/src/connections/wireless @@ -1,124 +1,378 @@ #! /bin/bash + +################################## +## +# /usr/lib/network/connections/wireless +## +################################## + +. /etc/rc.conf +. /etc/rc.d/functions . /usr/lib/network/network wireless_up() { - load_profile $1 - . ${SUBR_DIR}/8021x - . ${SUBR_DIR}/wireless + load_profile "$1" + [[ -n "$2" ]] && ESSID="$2" # JP: use the literal ESSID (though currently we only interpret wireless-dbus ESSIDs as regexps) + + . "$SUBR_DIR/8021x" + . "$SUBR_DIR/wireless_utils" # Check if interface exists - if [[ ! -e /sys/class/net/"$INTERFACE" ]]; then - if ! echo "$INTERFACE"|grep ":"; then - err_append "interface $INTERFACE does not exist" + if [[ ! -e "/sys/class/net/$INTERFACE" ]]; then + if ! echo "$INTERFACE" | fgrep -q ":"; then + report_fail "Interface $INTERFACE does not exist." return 1 fi fi # Kill any lingering wpa_supplicants. - stop_wpa $INTERFACE + report_debug wireless_up stop_wpa "$INTERFACE" + stop_wpa "$INTERFACE" # Most drivers (mac80211) need mode set before device is brought up # Drivers generally default to managed, but set this to be sure. - if [[ "$(iwgetid -sm $INTERFACE)" -ne "Managed" ]]; then - iwconfig $INTERFACE mode managed - fi + if [[ $(iwgetid -sm "$INTERFACE") -ne Managed ]]; then + report_debug wireless_up iwconfig "$INTERFACE" mode managed + iwconfig "$INTERFACE" mode managed + fi - ifconfig $INTERFACE up + report_debug wireless_up ifup + wireless_control "$INTERFACE" up || return 1 + + quirk prescan && iwlist "$INTERFACE" scan &> /dev/null # bcm43xx + + + if quirk preessid; then # ipw3945 + if [[ -n "$AP" ]]; then # JP: enable use of AP + # JP: Since I don't undertand why the else block below is an eval, I'm not sure + # if this command also needs to be eval'd + iwconfig "$INTERFACE" mode managed ap "$AP" + else + # JP: I don't understand why this needs to be an eval. What's wrong with just: + # iwconfig "$INTERFACE" mode managed essid "$ESSID" + eval "iwconfig \"$INTERFACE\" mode managed essid \"$ESSID\"" + fi - quirk "prescan" && iwlist $INTERFACE scan &> /dev/null # bcm43xx - quirk "preessid" && eval "iwconfig $INTERFACE mode managed essid \"$ESSID\"" # ipw3945 + fi - if checkyesno ${SCAN:-no}; then - if ! find_essid $INTERFACE "$ESSID"; then - err_append "Network not present." + if checkyesno "${SCAN:-no}"; then + report_debug wireless_up scanning + local OLDESSID="$ESSID" + if [[ -n "$AP" ]]; then + ESSID=$(find_ap "$INTERFACE" "$AP") + else + ESSID=$(find_essid "$INTERFACE" "$ESSID" "$CONNECTION") # JP: we could have left $3 null for default of treating ESSID as literal + # but instead we explicitly pass $CONNECTION + fi + if [[ $? -gt 0 ]]; then + report_fail "Wireless network \"$OLDESSID\" not present." return 1 fi fi # Manually set iwconfig options - [[ "$IWCONFIG" ]] && iwconfig $INTERFACE $IWCONFIG + if [[ -n "$IWCONFIG" ]]; then + report_debug wireless_up iwconfig "$INTERFACE" $IWCONFIG + iwconfig "$INTERFACE" $IWCONFIG + fi # Set to 'none' if not set - [[ -z "$SECURITY" ]] && SECURITY="none" + [[ -z "$SECURITY" ]] && SECURITY=none - case $SECURITY in + case "$SECURITY" in wep|none) # 'none' uses iwconfig like wep. Use sane default if WEP_OPTS="" - if [[ "$SECURITY" = "wep" ]]; then - WEP_OPTS="essid \"$ESSID\" key $KEY" - elif [[ "$SECURITY" = "none" ]]; then - WEP_OPTS="essid \"$ESSID\"" - fi + if [[ -z "$WEP_OPTS" ]]; then + if [[ "$SECURITY" = wep ]]; then + if [[ -n "$AP" ]]; then + WEP_OPTS="ap \"$AP\" key $KEY" # JP: formerly I had "...key open $KEY"; is it correct to omit the 'open'? + else + WEP_OPTS="essid \"$ESSID\" key $KEY" # JP: formerly I had "...key open $KEY"; is it correct to omit the 'open'? + fi + else # SECURITY=none + if [[ -n "$AP" ]]; then + WEP_OPTS="ap \"$AP\"" + else + WEP_OPTS="essid \"$ESSID\"" + fi + fi + fi - quirk "predown" && ifconfig $INTERFACE down # madwifi FS#10585 + quirk predown && wireless_control "$INTERFACE" forcedown # madwifi FS#10585 - if ! eval iwconfig $INTERFACE $WEP_OPTS; then - err_append "Could not set wireless configuration." + report_debug wireless_up iwconfig "$INTERFACE" $WEP_OPTS + # JP: I don't understand why this needs to be an eval. What's wrong with just: + # iwconfig "$INTERFACE" $WEP_OPTS + if ! eval "iwconfig \"$INTERFACE\" $WEP_OPTS"; then + report_fail "Couldn't configure wireless." return 1 fi - quirk "predown" && ifconfig $INTERFACE up # madwifi FS#10585 + + + quirk predown && wireless_control "$INTERFACE" up # madwifi FS#10585 - wep_check $INTERFACE $TIMEOUT||return 1 + report_debug ethernet_up wep_check + wep_check "$INTERFACE" "$TIMEOUT" || return 1 ;; + wpa) # Quirk for broken drivers... http://bbs.archlinux.org/viewtopic.php?id=36384 - quirk "wpaessid" && eval iwconfig $INTERFACE essid "\"$ESSID\"" + if quirk wpaessid; then + if [[ -n "$AP" ]]; then + # JP: Since I don't undertand why the else block below is an eval, I'm not sure + # if this command also needs to be eval'd + iwconfig "$INTERFACE" ap "$AP" + else + # JP: I don't understand why this needs to be an eval. What's wrong with just: + # iwconfig "$INTERFACE" essid "$ESSID" + eval "iwconfig \"$INTERFACE\" essid \"$ESSID\"" + fi + fi - local WPA_CONF="/tmp/wpa.${1// /}" # substitute spaces out - echo "ctrl_interface=/var/run/wpa_supplicant" >> $WPA_CONF - echo "ctrl_interface_group=${WPA_GROUP:-wheel}" >> $WPA_CONF - chmod 600 $WPA_CONF + local WPA_CONF="${TMPDIR:-/tmp}/wpa.${1// /}" # substitute spaces out + # make empty tmp dir with correct permissions, rename it + rm -rf "$WPA_CONF" + mv -f $(mktemp -d) "$WPA_CONF" || return 1 + echo "ctrl_interface=/var/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" # Generate configuration - if [[ "${#KEY}" == "64" ]]; then - echo -e "network={ \nssid=\"$ESSID\" \npsk=$KEY \n}">> $WPA_CONF - elif ! echo "$KEY" | wpa_passphrase "$ESSID" >> $WPA_CONF; then - err_append "Configuration generation failed. $(cat $WPA_CONF)" + if [[ "${#KEY}" -eq 64 ]]; then + echo -e "network={ \nssid=\"$ESSID\" \npsk=$KEY \n}">> "$WPA_CONF/wpa.conf" + # JP: formerly I had { \nssid=\"$ESSID\" \nproto=WPA \nkey_mgmt=WPA-PSK \npsk=$KEY \n} + # JP: is what's above better? + elif ! echo "$KEY" | wpa_passphrase "$ESSID" >> "$WPA_CONF/wpa.conf"; then + report_fail "Couldn't generate WPA configuration." + cat "$WPA_CONF/wpa.conf" >&2 return 1 fi # Connect! [[ -z "$WPA_OPTS" ]] && WPA_OPTS="-Dwext" - start_wpa $INTERFACE $WPA_CONF $WPA_OPTS || return 1 - if ! wpa_check $INTERFACE $TIMEOUT; then - stop_wpa $INTERFACE + report_debug wireless_up start_wpa "$INTERFACE" "$WPA_CONF/wpa.conf" "$WPA_OPTS" + start_wpa "$INTERFACE" "$WPA_CONF/wpa.conf" "$WPA_OPTS" || return 1 + report_debug wireless_up wpa_check + if ! wpa_check "$INTERFACE" "$TIMEOUT"; then + stop_wpa "$INTERFACE" return 1 fi ;; wpa-config) - . ${SUBR_DIR}/8021x + . "$SUBR_DIR/8021x" [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf" # defaults [[ -z "$WPA_OPTS" ]] && WPA_OPTS="-Dwext" - start_wpa $INTERFACE $WPA_CONF $WPA_OPTS || return 1 - if ! wpa_check $INTERFACE $TIMEOUT; then - stop_wpa $INTERFACE + report_debug wireless_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_OPTS" + start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_OPTS" || return 1 + report_debug wireless_up wpa_check + if ! wpa_check "$INTERFACE" "$TIMEOUT"; then + stop_wpa "$INTERFACE" return 1 fi ;; esac - if ! ${CONN_DIR}/ethernet up $1; then - wireless_down $1 YES + if ! "$CONN_DIR/ethernet" up "$1"; then + wireless_down "$1" YES return 1 fi } +# wireless_down PROFILE [ LEAVE ifconfig up? default no ] wireless_down() { - load_profile $1 - . ${SUBR_DIR}/8021x - PROFILE=$1 NOETHERNETDOWN=$2 - if ! checkyesno $2; then - ${CONN_DIR}/ethernet down $1 + load_profile "$1" + . "$SUBR_DIR/8021x" + local PROFILE="$1" NOETHERNETDOWN="$2" # JP: made declarations local?? also, why introduce these vars if you're not going to use them? + if ! checkyesno "$NOETHERNETDOWN"; then + "$CONN_DIR/ethernet" down "$PROFILE" fi - stop_wpa $INTERFACE - [[ "$SECURITY" == "wpa" ]] && rm -f "/tmp/wpa.${1// /}" # remove wpa config - iwconfig $INTERFACE essid off key off &> /dev/null - ifconfig $INTERFACE down + report_debug wireless_down stop_wpa "$INTERFACE" + stop_wpa "$INTERFACE" + [[ "$SECURITY" == wpa ]] && rm -rf "/tmp/wpa.${PROFILE// /}" # remove tmp wpa config + report_debug wireless_down iwconfig "$INTERFACE" essid off key off + iwconfig "$INTERFACE" essid off key off &> /dev/null + #wireless_control "$INTERFACE" forcedown # this is now handled in ethernet down, isn't it? } -wireless_$1 $2 +# CONNECTION_query $INTERFACE [ profile | enabled (i.e. not rfkill-ed) | active (i.e. ifup'd) | associated | address ] [ "" | "-iproute" ] +# "query associated" also uses $4=ESSID $5=AP if known +wireless_query() { + local INTERFACE="$1" REQUEST="$2" NEW="$3" + #report_debug wireless_query "$@" + case "$REQUEST" in + + profile) + # return code = 1 if iface is available to be used + # return code = 0 if unavailable (disabled, or in use by another profile or by external config) + # echo "" | "disabled" | "external" | PROFILE_NAME + if [[ ! -f "$STATE_DIR/interfaces/$INTERFACE" ]]; then + # wireless interface is up but has no registered profile + if ! wireless_query "$INTERFACE" enabled "$NEW"; then + wireless_control disable "$INTERFACE" # STATE_DIR/interface should say "disabled" instead + # iface should be down if it''s disabled + wireless_control "$INTERFACE" down "$NEW" + echo "disabled" + return 0 + fi + if wireless_query "$INTERFACE" address "$NEW"; then + set_iface up "$INTERFACE" external + echo "external" + return 0 + fi + # no ip address, count as inactive (even if associated) + # should we tell iface to de-associate if still associated? + # should we ifconfig iface down? no, may be up for a reason + return 1 + + else # interface is up and thinks it's running a profile + . "$STATE_DIR/interfaces/$INTERFACE" # these files should only contain a PROFILE=... statement + case "$PROFILE" in + external) + echo "external" + return 0 + ;; + disabled) + # iface should be down if it's disabled + wireless_control "$INTERFACE" down "$NEW" + echo "disabled" + return 0 + ;; + *) + ( # use subshell to prevent overwriting currently loaded profile + . "$STATE_DIR/profiles/$PROFILE" + if ! "$CONN_DIR/$CONNECTION" query "$INTERFACE" enabled; then + report_warn "INTERFACE $INTERFACE is disabled; no longer being controlled by $PROFILE" + set_profile down "$PROFILE" + wireless_control disable "$INTERFACE" + wireless_control "$INTERFACE" down "$NEW" + echo "disabled" + exit 0 + elif ! wireless_query "$INTERFACE" address "$NEW"; then + report_warn "INTERFACE $INTERFACE is inactive; no longer being controlled by $PROFILE" + set_profile down "$PROFILE" + exit 1 + elif "$CONN_DIR/$CONNECTION" query "$INTERFACE" associated "$NEW" "$ESSID" "$AP"; then + echo "$PROFILE" # associated with loaded profile + exit 0 + else + report_warn "INTERFACE $INTERFACE no longer being controlled by $PROFILE" + set_profile down "$PROFILE" + set_iface up "$INTERFACE" external + echo "external" + exit 0 + fi + ) + # return $? + ;; + esac + fi + ;; + + enabled) + local rfkill iftype + for rfkill in /sys/class/rfkill/*; do + if [[ -e "$rfkill/type" && -e "$rfkill/state" ]]; then + iftype=$(cat "$rfkill/type") + if [[ "$iftype" == wlan || "$iftype" == "${INTERFACE:0:${#INTERFACE}-1}" ]]; then # JP: don't really know what the range of values for this is + # on my machine, the INTERFACE is wlan0 and the type=wlan + test $(cat "$rfkill/state") -eq 1 # state is 1 when enabled, 2 when killed + return $? + fi + fi + done +# # JP: this is easier, but I don't know if it can be relied on to stay in place... +# if [[ -e /sys/class/net/$INTERFACE/device/rfkill/rfkill?/state ]]; then +# test $(cat /sys/class/net/$INTERFACE/device/rfkill/rfkill?/state) -eq 1 +# return $? +# fi + return 0 # default to enabled + ;; + + associated) + # assumed to have ip address + # return 0: associated with loaded profile + # 1: associated with other + # 2: still has ip address but unassociated: can this happen? + local ESSID="$4" AP="$5" + local essid=$(iwgetid "$INTERFACE" -r) ap=$(iwgetid "$INTERFACE" -ra) + [[ -z "$ap" ]] && return 2 + if [[ -n "$AP" ]]; then + [[ $(echo "$AP" | tr 'abcdef' 'ABCDEF') == "$ap" ]] + return $? + fi + case "$ESSID" in + # [Rr][Oo][Aa][Mm]|[Oo][Pp][Ee][Nn]) + # return 0 + # ;; + *) + if [[ "$NEW" == -iproute ]]; then + # JP: ESSID is a regexp; we handle this here instead of in the wireless-dbus script for now + expr match "$essid" "^$ESSID\$" >/dev/null + return $? # returns true if matched more than 0 chars + else + [[ "$ESSID" == "$essid" ]] + return $? + fi + ;; + esac + ;; + + active|address) + "$CONN_DIR/ethernet$NEW" query "$INTERFACE" "$REQUEST" + ;; + + *) return 1;; + esac +} + +# CONNECTION_control $INTERFACE [ up | down | forcedown | enable | disable ] [ "" | "-iproute" ] +wireless_control() { + local INTERFACE="$1" ACTION="$2" NEW="$3" + #report_debug wireless_control "$@" + case "$ACTION" in + enable) + [[ $(query_iface "$INTERFACE") == disabled ]] && set_iface "$INTERFACE" down + ;; + disable) + set_iface up "$INTERFACE" disabled + ;; + up) + if [[ "$NEW" = -iproute ]]; then + "$CONN_DIR/ethernet-iproute" control "$INTERFACE" "$ACTION" + else + # JP: same as ethernet control ... up + #ifconfig "$INTERFACE" up 2>/dev/null + ifconfig "$INTERFACE" up + wireless_query "$INTERFACE" active + fi + ;; + down|forcedown) + if [[ "$NEW" = -iproute ]]; then + "$CONN_DIR/ethernet-iproute" control "$INTERFACE" "$ACTION" + else + # JP: differs slightly from ethernet control ... down (but I don't know whether the difference is really appropriate, I'm just preserving it from older codebase) + ifconfig "$INTERFACE" 0.0.0.0 + if [[ "$2" = forcedown ]]; then + ifconfig "$INTERFACE" down + fi + fi + ;; + *) return 1;; + esac +} + +wireless_verify() { + local INTERFACE="$1" + if [[ -d "/sys/class/net/$INTERFACE/phy80211" || -d "/sys/class/net/$INTERFACE/wireless" ]]; then + return 0 + else + return 1 + fi +} + +wireless_$1 "$2" "$3" "$4" "$5" "$6" exit $? # vim: set ts=4 et sw=4: + |