diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/8021x | 32 | ||||
-rw-r--r-- | src/connections/ethernet | 122 | ||||
-rw-r--r-- | src/connections/ppp | 18 | ||||
-rw-r--r-- | src/connections/wireless | 119 | ||||
-rw-r--r-- | src/network | 297 | ||||
-rw-r--r-- | src/wireless | 61 |
6 files changed, 649 insertions, 0 deletions
diff --git a/src/8021x b/src/8021x new file mode 100644 index 0000000..cce66cd --- /dev/null +++ b/src/8021x @@ -0,0 +1,32 @@ +# Uses wpa_supplicant to check for association to a network +# wpa_check interface [timeout] +wpa_check() +{ + local timeout=0 INTERFACE=$1 TIMEOUT=${2:-15} + + while [[ $timeout -lt $TIMEOUT ]]; do + ( + eval `wpa_cli status|grep wpa_state` + [[ "$wpa_state" = "COMPLETED" ]] + ) && return 0 + sleep 1 + let timeout++ + done + + wpa_cli terminate >/dev/null 2>&1 + err_append "Authentication/association failed" + return 1 +} + +start_wpa() +{ + INTERFACE="$1"; WPA_CONF="$2"; WPA_OPTS="$3" + + wpa_supplicant -wB -P/var/run/wpa_supplicant_${INTERFACE}.pid -i"${INTERFACE}" -c "$WPA_CONF" $WPA_OPTS + sleep 1 + + if [[ ! -f "/var/run/wpa_supplicant_${INTERFACE}.pid" ]]; then + err_append "wpa_supplicant did not start, possible configuration error" + return 1 + fi +} diff --git a/src/connections/ethernet b/src/connections/ethernet new file mode 100644 index 0000000..3605663 --- /dev/null +++ b/src/connections/ethernet @@ -0,0 +1,122 @@ +#! /bin/bash + + +ethernet_up() { + if [[ ! -e /sys/class/net/$INTERFACE ]]; then + if ! echo "$INTERFACE"|grep ":"; then + err_append "Interface $INTERFACE does not exist" + fi + fi + + if ip link show $INTERFACE|grep -q "NO-CARRIER"; then + err_append "No connection available" + return 1 + fi + + ifconfig $INTERFACE up + + if checkyesno ${AUTH8021X:-no}; then + . ${SUBR_DIR}/8021x + [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf" + [[ -z "$WPA_OPTS" ]] && WPA_OPTS="-Dwired" + start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_OPTS" + if ! wpa_check "$INTERFACE"; then + ifconfig $INTERFACE down + return 1 + fi + fi + + case $IP in + dhcp) + # Check if DHCP_TIMEOUT was set if not set a default value + [[ -z "$DHCP_TIMEOUT" ]] && DHCP_TIMEOUT=10 + + if checkyesno $DHCLIENT; then + rm -r /var/run/dhclient-${INTERFACE}.pid >/dev/null 2>&1 + if ! dhclient -q -e TIMEOUT=$DHCP_TIMEOUT -pf /var/run/dhclient-${INTERFACE}.pid $INTERFACE; then + err_append "DHCP IP lease attempt failed" + return 1 + fi + else + # Clear remaining pid files. + 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 $DHCP_OPTIONS $INTERFACE; then + err_append "DHCP IP lease attempt failed" + return 1 + fi + fi + # TODO: add support for $section:ifconfig for other stuff, like mtu or mac? + ;; + static) + if ! ifconfig $INTERFACE $IFOPTS up; then + err_append "Could not bring interface up" + return 1 + fi + + # bring up the default route (gateway) + if [[ -n "$GATEWAY" ]]; then + if ! route add default gw $GATEWAY; then + err_append "Adding gateway $GATEWAY failed" + return 1 + fi + fi + ;; + *) + err_append "Profile error: IP must be either 'dhcp' or 'static'" + return 1 + ;; + esac + + # set the hostname + if [[ -n "$HOSTNAME" ]]; then + if ! hostname $HOSTNAME; then + err_append "Cannot set hostname" + return 1 + fi + fi + + # Generate a new resolv.conf + if [[ -n "$DNS1" ]] || [[ -n "$DNS" ]]; then + + : >/etc/resolv.conf + [[ -n "$DOMAIN" ]] && echo "domain $DOMAIN" >>/etc/resolv.conf + [[ -n "$SEARCH" ]] && echo "search $SEARCH" >>/etc/resolv.conf + [[ -n "$DNS1" ]] && echo "nameserver $DNS1" >>/etc/resolv.conf + [[ -n "$DNS2" ]] && echo "nameserver $DNS2" >>/etc/resolv.conf + + if [[ -n "$DNS" ]]; then + for dns in ${DNS[@]}; do + echo "nameserver $dns" >>/etc/resolv.conf + done + fi + fi + return 0 +} + +ethernet_down() { + case $IP in + dhcp) + if checkyesno $DHCLIENT; then + if [[ -f /var/run/dhclient-${INTERFACE}.pid ]]; then + kill `cat /var/run/dhclient-${INTERFACE}.pid` + fi + else + if [[ -f /var/run/dhcpcd-${INTERFACE}.pid ]]; then + dhcpcd -qx $INTERFACE + fi + fi + ;; + static) + [[ -n "$GATEWAY" ]] && route del default gw $GATEWAY + ;; + esac + ifconfig $INTERFACE 0.0.0.0 + + quirk "nodown" || ifconfig $INTERFACE down + +} + +# vim: set ts=4 et sw=4: diff --git a/src/connections/ppp b/src/connections/ppp new file mode 100644 index 0000000..ecefd63 --- /dev/null +++ b/src/connections/ppp @@ -0,0 +1,18 @@ +#! /bin/bash +ppp_up() { + [[ -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 + fi +} + +ppp_down() { + kill $(head -1 /var/run/ppp-$(basename $PEER).pid) +} + +# vim: set ts=4 et sw=4: diff --git a/src/connections/wireless b/src/connections/wireless new file mode 100644 index 0000000..dbc2a29 --- /dev/null +++ b/src/connections/wireless @@ -0,0 +1,119 @@ +#! /bin/bash + +wireless_up() { + + load_profile $1 + + . ${SUBR_DIR}/wireless + + if [[ ! -d /sys/class/net/$INTERFACE/wireless ]]; then + err_append "Interface $INTERFACE is not a wireless interface" + return 1 + fi + + # Required by atheros and others (mac80211?) to enable device + ifconfig $INTERFACE up + + # Hack that has been required by some broadcom + quirk "prescan" && iwlist $INTERFACE scan &> /dev/null + + # Required by ipw3945 to properly re-associate + quirk "preessid" && eval "iwconfig $INTERFACE mode managed essid \"$ESSID\"" + + # Kill any lingering wpa_supplicants. + if [[ -f /var/run/wpa_supplicant_$INTERFACE.pid ]]; then + kill $(cat /var/run/wpa_supplicant_$INTERFACE.pid) + fi + + # Default scan off as it won't see hidden networks and some hardware's scanning is dodgy + [[ ! "$SCAN" ]] && SCAN="no" + if checkyesno $SCAN; then + if ! find_essid $INTERFACE "$ESSID"; then + err_append "Network unavailable" + return 1 + fi + fi + + # Manually set iwconfig options + if [[ "$IWCONFIG" ]]; then + iwconfig $INTERFACE $IWCONFIG + fi + + case $SECURITY in + wep|none) + # 'none' security uses iwconfig, like wep, so use same code, minus keysetting. + # Use sane default if no alternative is specified + if [[ "$SECURITY" = "wep" && "$WEP_OPTS" = "" ]]; then + WEP_OPTS="mode managed essid \"$ESSID\" key $KEY" + elif [[ "$SECURITY" = "none" && "$WEP_OPTS" = "" ]]; then + WEP_OPTS="mode managed essid \"$ESSID\"" + fi + + # Add wierd quirk for some Atheros in response to FS#10585 + quirk "predown" && ifconfig $INTERFACE down + + if ! eval iwconfig $INTERFACE $WEP_OPTS; then + err_append "Could not set wireless configuration" + return 1 + fi + + quirk "postsleep" && sleep 1 + quirk "postscan" && sleep 1 && iwlist $INTERFACE scan &>/dev/null + quirk "predown" && ifconfig $INTERFACE up + + wep_check $INTERFACE $TIMEOUT|| return 1 + ;; + wpa) + . ${SUBR_DIR}/8021x + + # Quirk for broken drivers... http://bbs.archlinux.org/viewtopic.php?id=36384 + quirk "wpaessid" && eval iwconfig $INTERFACE mode managed essid "\"$ESSID\"" + + local WPA_CONF="/tmp/wpa.${1// /}" # substitute spaces out + echo "ctrl_interface=/var/run/wpa_supplicant" >> $WPA_CONF + echo "ctrl_interface_group=0" >> $WPA_CONF + chmod 600 $WPA_CONF + + # Generate configuration + if [[ "${#KEY}" == "64" ]]; then + echo -e 'network={ \nssid="$ESSID" \npsk=$KEY \n}'> $WPA_CONF + elif ! wpa_passphrase "$ESSID" "$KEY" >> $WPA_CONF; then + err_append "Configuration generation failed: `cat $WPA_CONF`" + return 1 + fi + + # Connect! + [[ "$WPA_OPTS" == "" ]] && WPA_OPTS="-Dwext" + start_wpa $INTERFACE $WPA_CONF $WPA_OPTS || return 1 + wpa_check $INTERFACE $TIMEOUT || return 1 + ;; + wpa-config) + . ${SUBR_DIR}/8021x + # If user hasnt defined one, use stock config. + [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf" + [[ "$WPA_OPTS" == "" ]] && WPA_OPTS="-Dwext" + start_wpa $INTERFACE $WPA_CONF $WPA_OPTS || return 1 + wpa_check $INTERFACE $TIMEOUT || return 1 + ;; + esac + + . $CONN_DIR/ethernet + if ! ethernet_up $1; then + wireless_down $1 YES + return 1 + fi +} + +wireless_down() { + PROFILE=$1 NOETHERNETDOWN=$2 + if ! checkyesno $2; then + . $CONN_DIR/ethernet + ethernet_down $1 + fi + wpa_cli terminate &> /dev/null + [[ "$SECURITY" == "wpa" ]] && rm -f "/tmp/wpa.${1// /}" # remove wpa config + iwconfig $INTERFACE essid off key off &> /dev/null + +} + +# vim: set ts=4 et sw=4: diff --git a/src/network b/src/network new file mode 100644 index 0000000..88f689e --- /dev/null +++ b/src/network @@ -0,0 +1,297 @@ +### Globals +PROFILE_DIR="/etc/network.d/" +SUBR_DIR="/usr/lib/network/" +CONN_DIR="${SUBR_DIR}/connections/" +STATE_DIR="/var/run/network/" + +### Messages +## +# err msg +# output specified message +err_append() { +echo -n $* +} + +err() { +echo $* +} + +### Profile loading +## +# load_profile profile +# source the profile +load_profile() { + validate_profile $1 || return 1 + . $PROFILE_DIR/$1 +} +# validate_profile profile +# check whether profile exists and is usable +validate_profile() +{ + [[ -z "$1" ]] && return 1 + if [[ ! -f $PROFILE_DIR/$1 ]]; then + err "Profile \"$1\" does not exist" + return 1 + fi + . $PROFILE_DIR/$1 + if [[ -z "$INTERFACE" ]]; then + err "Profile missing an interface to configure" + return 1 + fi + if [[ ! -f $CONN_DIR/$CONNECTION ]]; then + err "$CONNECTION is not a valid connection, check spelling or look at examples" + return 1 + fi +} + +### Profile up/down +## +# all_down +# take all profiles down +# +all_down() +{ + ls -1 $STATE_DIR/profiles/ | while read prof; do + profile_down $prof + done + rm_daemon net-profiles +} + +# all_suspend +# store a list of running profiles and take them down +# +all_suspend() +{ + [[ ! -d $STATE_DIR ]] && mkdir -p $STATE_DIR/{interfaces,profiles} + [[ ! -d $STATE_DIR/suspend ]] && mkdir $STATE_DIR/suspend + + ls -1 $STATE_DIR/profiles/ | while read prof; do + cp $STATE_DIR/profiles/$prof $STATE_DIR/suspend/ + profile_down $prof + done +} + +# all_suspend +# store a list of running profiles and take them down +# +all_resume() +{ + ls -1 $STATE_DIR/suspend/ | while read prof; do + profile_up $prof + rm $STATE_DIR/suspend/$prof + done +} + +# profile_up profile +# put all profiles up +# +profile_up() +{ + + [[ ! -d $STATE_DIR ]] && mkdir -p $STATE_DIR/{interfaces,profiles} + + load_profile $1 || return 1 + + check_profile $1 && err "$1 already connected" && return 1 + + # NETWORKS_EXCLUSIVE, rc.conf: Profiles are globally mutually exclusive + # EXCLUSIVE, network.d/profile: Individual profile is mutually exclusive + if checkyesno $NETWORKS_EXCLUSIVE || checkyesno $EXCLUSIVE; then + all_down + fi + + stat_busy "$1 up" + + if check_iface $INTERFACE; then + if checkyesno $CHECK; then + err_append "Interface $INTERFACE already in use" + stat_fail && return 1 + else + interface_down $INTERFACE || return 1 + load_profile $1 + fi + fi + + + eval $PRE_UP || return 1 + + . $CONN_DIR/${CONNECTION} + if ! ${CONNECTION}_up $1; then + stat_fail + return 1 + fi + + eval $POST_UP || return 1 + + set_profile up $1 + unset EXCLUSIVE + + add_daemon net-profiles + stat_done +} + +# profile_down profile +# take profile down +# +profile_down() +{ + + [[ ! -d $STATE_DIR ]] && mkdir -p $STATE_DIR/{interfaces,profiles} + + load_profile $1 || return 1 + + if ! check_profile $1; then + err "Profile not connected" + return 1 + fi + + stat_busy "$1 down" + if [[ "$(get_iface_prof $INTERFACE)" == "external" ]]; then + err_append "$interface was connected by another application" + stat_fail + return 1 + fi + + eval $PRE_DOWN || return 1 + + . $CONN_DIR/${CONNECTION} + if ! ${CONNECTION}_down $1; then + stat_fail + return 1 + fi + + eval $POST_DOWN || return 1 + + set_profile down $1 + stat_done +} + +# Check if variable is a member of an array +inarray() +{ +search=$1 +shift +for item in $*; do + if [[ "$item" == "$search" ]]; then + return 0 + fi +done +return 1 +} + +quirk() { +inarray $1 ${QUIRKS[@]} +return $? +} + +# interface_down interface +# take interface down +# +interface_down() +{ + local prof=$(get_iface_prof $1) + profile_down $prof + return $? +} + + +### Query functions +## +# check_iface interface +# Return 0 if interface up +# Return 1 if interface down +# +check_iface() { + [[ -f $STATE_DIR/interfaces/$1 ]] && return 0 + return 1 +} + +# get_iface_prof interface +# Echo interface profile and return 0 if up +# Return 1 if down. +# +get_iface_prof() { + if check_iface $1; then + . $STATE_DIR/interfaces/$1 + echo $PROFILE + else + return 1 + fi +} + +# list_profiles +# Outputs a list of all profiles +list_profiles() { + find $PROFILE_DIR/ -maxdepth 1 -type f -printf "%f\n" +} + +# check_profile profile +# Return 0 if profile up +# Return 1 if profile down +# +check_profile() { + [[ -f $STATE_DIR/profiles/$1 ]] && return 0 + return 1 +} + +### Status setting functions +## +# set_profile up/down profile +# Set profile state, either up or down +# +set_profile() { + if [[ "$1" == "up" ]]; then + . $PROFILE_DIR/$2 + cp $PROFILE_DIR/$2 $STATE_DIR/profiles/ + echo $2 > $STATE_DIR/last_profile + set_iface up $INTERFACE $2 + + elif [[ "$1" == "down" ]]; then + . $STATE_DIR/profiles/$2 + 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() { + PROFILE=$3 + [[ -z "$PROFILE" ]] && PROFILE=external + if [[ "$1" == "up" ]]; then + echo "PROFILE=$PROFILE" > $STATE_DIR/interfaces/$2 + elif [[ "$1" == "down" ]]; then + rm $STATE_DIR/interfaces/$2 + fi +} + + +### 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. +# +checkyesno() +{ + _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) + return 0 + ;; + + # "no", "false", "off", or "0" + [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + return 1 + ;; + *) + #warn "\$${1} is not set properly - see ${rcvar_manpage}." + return 1 + ;; + esac +} diff --git a/src/wireless b/src/wireless new file mode 100644 index 0000000..405b86b --- /dev/null +++ b/src/wireless @@ -0,0 +1,61 @@ +# Uses wireless_tools, to check for association to a network. +# wep_check interface [timeout] +wep_check() +{ + INTERFACE=$1; TIMEOUT=$2 + + [[ -z "$TIMEOUT" ]] && TIMEOUT=15 + let timeout=0 + while [[ $timeout -ne $TIMEOUT ]]; do + bssid=`iwgetid $INTERFACE -ra` + [[ ! "$bssid" = "00:00:00:00:00:00" ]] && return 0 + sleep 1 + let timeout++ + done + + err_append "Wireless association failed" + return 1 +} + +# Check if a particular network is within range +# find_essid interface essid +find_essid() +{ + INTERFACE=$1; ESSID=$2; RETRIES=5 + try=0; + while [[ $try -ne $RETRIES ]]; do + if iwlist $INTERFACE scan|sed "s/ESSID://g"|grep -q "\"$ESSID\""; then + return 0 # network found + fi + sleep 1 + let try++ + done + return 1 +} + +# Return a filename containing a list of network ESSID's found. +# list_networks interface +list_networks() +{ + # 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 "$1" ]] && return 1 + essids=$(mktemp /tmp/essid.XXXXX) + + let try=0; + RETRIES=6; + while [[ $try -ne $RETRIES ]]; do + iwlist $1 scan 2> /dev/null|grep ESSID|sed 's/.*ESSID:"\([^"]\+\)".*/\1/' > $essids + sleep 0.5; let try++ + done + sort -u $essids -o $essids + + # File of 0 length, ie. no ssid's. + if [[ ! -s $essids ]]; then + return 1 + fi + + echo $essids + return 0 +} |