summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Rayner <james@archlinux.org>2009-08-07 16:23:45 +0200
committerJames Rayner <james@archlinux.org>2009-08-07 16:23:45 +0200
commit54e39849f1e60eb043f9d8f0904acf3c79d96a1c (patch)
tree9c10a01ea0ba58d31b3ab8282ead767da49264d3
parentf7168ae05837a24060b41511be6e4626cb26828a (diff)
downloadnetctl-54e39849f1e60eb043f9d8f0904acf3c79d96a1c.tar.gz
netctl-54e39849f1e60eb043f9d8f0904acf3c79d96a1c.tar.xz
Patch from Jim Pryor
-rw-r--r--Makefile10
-rwxr-xr-xcontrib/common.hook49
-rwxr-xr-xcontrib/ifplugd.action25
-rwxr-xr-xcontrib/logging.hook86
-rwxr-xr-xcontrib/pm-utils.handler68
-rw-r--r--doc/ethernet-subr.html99
-rw-r--r--doc/ethernet.html87
-rw-r--r--doc/wireless7
-rw-r--r--doc/wireless-dbus6
-rw-r--r--doc/wireless-dbus.html53
-rw-r--r--doc/wireless.html63
-rw-r--r--[-rwxr-xr-x]examples/ethernet-iproute0
-rw-r--r--man/netcfg.822
-rw-r--r--[-rwxr-xr-x]src-wireless/net-auto43
-rw-r--r--[-rwxr-xr-x]src-wireless/netcfg-auto-wireless139
-rw-r--r--[-rwxr-xr-x]src-wireless/wireless-dbus146
-rw-r--r--src/8021x36
-rw-r--r--src/connections/ethernet211
-rw-r--r--src/connections/ethernet-iproute214
-rw-r--r--src/connections/ppp53
-rw-r--r--src/connections/wireless368
-rw-r--r--src/globals118
-rw-r--r--[-rwxr-xr-x]src/net-profiles63
-rw-r--r--[-rwxr-xr-x]src/net-rename10
-rw-r--r--src/netcfg56
-rw-r--r--[-rwxr-xr-x]src/netcfg-menu59
-rw-r--r--src/network460
-rw-r--r--src/wireless141
28 files changed, 2165 insertions, 527 deletions
diff --git a/Makefile b/Makefile
index ff57a39..d72029c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,10 @@
DESTDIR=
-VERSION=2.2.1
+VERSION=2.3.0b1
VPATH = doc
install:
install -d $(DESTDIR)/usr/lib/network/connections $(DESTDIR)/etc/network.d/examples \
+ $(DESTDIR)/etc/network.d/hooks \
$(DESTDIR)/var/run/network/{interfaces,profiles} \
$(DESTDIR)/usr/bin/ $(DESTDIR)/etc/rc.d/ \
$(DESTDIR)/usr/share/man/{man5,man8}
@@ -12,7 +13,7 @@ install:
install -m644 src/iftab $(DESTDIR)/etc/iftab
install -m644 man/*.8 $(DESTDIR)/usr/share/man/man8
# Libs
- install -m644 src/{network,wireless,8021x} $(DESTDIR)/usr/lib/network
+ install -m644 src/{network,wireless_utils,8021x,globals} $(DESTDIR)/usr/lib/network
install -m755 src/connections/* ${DESTDIR}/usr/lib/network/connections
# 'Binaries'
install -m755 src/netcfg $(DESTDIR)/usr/bin/netcfg2
@@ -28,8 +29,9 @@ install-wireless:
install -m755 src-wireless/net-auto $(DESTDIR)/etc/rc.d
install-docs: docs
- install -d $(DESTDIR)/usr/share/doc/netcfg
+ install -d $(DESTDIR)/usr/share/doc/netcfg/contrib
install -m644 doc/*html $(DESTDIR)/usr/share/doc/netcfg/
+ install -m644 contrib/* $(DESTDIR)/usr/share/doc/netcfg/contrib/
docs: doc/*
for doc in $(?); do \
@@ -39,7 +41,7 @@ docs: doc/*
tarball:
sed -i "s/NETCFG_VER=.*/NETCFG_VER=$(VERSION)/g" src/netcfg
mkdir -p netcfg-$(VERSION)
- cp -r src src-wireless examples man Makefile LICENSE README netcfg-$(VERSION)
+ cp -r src src-wireless examples contrib man Makefile LICENSE README netcfg-$(VERSION)
tar -zcvf netcfg-$(VERSION).tar.gz netcfg-$(VERSION)
mv netcfg-$(VERSION).tar.gz ../
rm -rf netcfg-$(VERSION)
diff --git a/contrib/common.hook b/contrib/common.hook
new file mode 100755
index 0000000..bf5f192
--- /dev/null
+++ b/contrib/common.hook
@@ -0,0 +1,49 @@
+### Sample netcfg hook script showing how to declare shared settings
+#
+### These functions and variables will be available to all profiles
+### (They can be manually overridden by any profile.)
+### To install, make this executable and put it in /etc/network.d/hooks
+
+function RUNDAEMON {
+ # "RUNDAEMON daemon [ start | stop ]" will run the daemon only if it's enabled in the DAEMONS array
+ # "RUNDAEMON -f daemon [ start | stop ]" will run it no matter what
+ local enabled result
+ if [[ "$1" = "-f" ]]; then
+ enabled=1
+ shift
+ fi
+ local daemon="$1"
+ shift
+ if [[ ! -x "/etc/rc.d/$daemon" ]]; then
+ echo "DAEMON $daemon isn't executable." >&2
+ return 1
+ elif [[ "$enabled" -ne 1 ]]; then
+ for f in "${DAEMONS[@]}"; do
+ if [[ "$f" = "$daemon" || "$f" = "@$daemon" ]]; then
+ enabled=1
+ break
+ fi
+ done
+ fi
+ if [[ "$enabled" -eq 1 ]]; then
+ "/etc/rc.d/$daemon" "$@"
+ result=$?
+ stat_busy "Continuing $PROFILE..." # else we'll get a [DONE] or [FAIL] at the end of a third blank line, after messages from $daemon
+ return $result
+ fi
+ return 1 # $daemon isn't enabled in DAEMON array
+}
+
+# Example of some things you might do in your POST_UP/PRE_DOWN scripts
+# (In fact, I couldn't get awesome-client to work on its own in this context, I had to call a wrapper instead that
+# sources the file in ~/.dbus/session-bus and then exports DBUS_SESSION_BUS_ADDRESS, and then calls awesome-client.)
+#
+POST_UP='( sleep 3 && echo "mynetworkfun()" | sudo -Hu me /usr/bin/awesome-client 2>/dev/null) & RUNDAEMON netfs start'
+PRE_DOWN='RUNDAEMON netfs stop'
+POST_DOWN='( sleep 3 && echo "mynetworkfun()" | sudo -Hu me /usr/bin/awesome-client 2>/dev/null) &'
+
+# Quirks and other variables defined here will apply to all your profiles...
+QUIRKS=()
+WPA_GROUP="network"
+
+
diff --git a/contrib/ifplugd.action b/contrib/ifplugd.action
new file mode 100755
index 0000000..4700c46
--- /dev/null
+++ b/contrib/ifplugd.action
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# /etc/ifplugd/ifplugd.action script for Arch Linux
+# can replace the one that comes with extra/ifplugd
+
+# . /etc/rc.conf
+# . /etc/rc.d/functions
+
+case "$2" in
+ up)
+ if [ "${1:0:3}" == eth ]; then
+ /usr/bin/netcfg "myethernet" # replace with name of your desired profile
+ fi
+ ;;
+ down)
+ /usr/bin/netcfg iface-down "$1"
+ /sbin/ifconfig "$1" down # note that we'll return 0 even if the netcfg call failed, e.g. because iface was already down
+ # hence no "failure" messages to syslog
+ ;;
+ *)
+ echo "Wrong arguments" > /dev/stderr
+ exit 1
+ ;;
+esac
+
diff --git a/contrib/logging.hook b/contrib/logging.hook
new file mode 100755
index 0000000..27a7c39
--- /dev/null
+++ b/contrib/logging.hook
@@ -0,0 +1,86 @@
+### Sample netcfg hook script for logging/debugging connections
+### To install, make this executable and put it in /etc/network.d/hooks
+
+
+# These functions are loaded after, and override, the ones in /usr/lib/network/globals
+
+# uncomment one of the following lines
+#function report_log { report_syslog "$@"; }
+#function report_log { report_stderr "$@"; }
+
+
+
+
+
+# What facility to send log messages to?
+NETCFGLOG="${NETCFGLOG-local0}"
+
+function report_syslog {
+ if [[ -n "$NETCFGLOG" ]]; then
+ local caller level="$1"
+ shift
+ case "$0" in
+ net-auto|netcfg-auto-*) caller=net-auto;;
+ net-profiles) caller=net-profiles;;
+ net-rename) caller=net-rename;;
+ *) caller=netcfg;;
+ esac
+ logger -p "${NETCFGLOG}.$level" -t "$caller" -- "$*"
+ fi
+}
+
+function report_stderr {
+ local level="$1"
+ shift
+ echo "netcfg $level: $*" >&2
+}
+
+function report_err {
+ report_log err "$*"
+ printhl "$*"
+}
+
+function report_warn {
+ report_log warning "$*"
+ # printhl "$*"
+}
+
+function report_notify {
+ report_log notice "$*"
+ # print "$*" >&2
+}
+
+function report_debug {
+ report_log debug "$*"
+}
+
+function report_try {
+ report_log notice "trying $*..."
+ REPORT_TRYING=1
+ stat_busy "$*"
+}
+
+function report_fail {
+ if [[ -n "$*" ]]; then
+ report_log err "$*"
+ if [[ -n "$REPORT_TRYING" ]]; then
+ stat_append "- $*"
+ REPORT_TRYING=
+ stat_fail
+ else
+ printhl "$*"
+ fi
+ elif [[ -n "$REPORT_TRYING" ]]; then
+ REPORT_TRYING=
+ stat_fail
+ fi
+}
+
+function report_success {
+ if [[ -n "$*" ]]; then
+ stat_append "- $*"
+ fi
+ report_log notice "${*:-succeeded}"
+ stat_done
+}
+
diff --git a/contrib/pm-utils.handler b/contrib/pm-utils.handler
new file mode 100755
index 0000000..5115b75
--- /dev/null
+++ b/contrib/pm-utils.handler
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+. /etc/rc.conf
+. /etc/rc.d/functions
+. /usr/lib/pm-utils/functions
+
+[[ -f /usr/lib/network/network ]] || exit $NA
+. /usr/lib/network/network
+
+auto_resume()
+{
+ all_resume
+ sleep 2
+ # if didn't successfully resume wifi, and running net-auto daemon, then restart the daemon
+ if [[ -f /var/run/daemons/net-auto && -x /usr/bin/netcfg-auto-wireless ]]; then
+ if check_iface "$1"; then # ret=0 when iface down and available
+ /usr/bin/netcfg-auto-wireless "$1"
+ fi
+ fi
+}
+
+
+case "$1" in
+ hibernate|suspend_hybrid|suspend)
+ report_log notice "suspending all interfaces..."
+ interface_suspend all
+ ;;
+ thaw|resume)
+ if "$CONN_DIR/wireless" query wlan0 enabled; then
+ report_log notice "resuming all interfaces..."
+ auto_resume wlan0
+ else
+ report_log notice "resuming all interfaces except wireless..."
+ all_resume wlan0
+ fi
+ ;;
+
+ # radio_off and radio_on aren't actions that pm-utils will ever send
+ # but if you're able to detect the toggling of your rfkill switch with acpid,
+ # you could have your acpid handler call this script as e.g. "SCRIPT radio_off"
+ radio_off)
+ report_log notice "suspending wireless interface..."
+ interface_suspend wlan0 no
+ "$CONN_DIR/wireless" control wlan0 disable
+ ifconfig wlan0 down
+ ;;
+ radio_on)
+ report_log notice "resuming wireless interface..."
+ auto_resume wlan0
+ if [ -x /etc/pm/power.d/??wifi ]; then
+ /usr/bin/on_ac_power # this is in pm-utils
+ case $? in
+ 0) # on ac
+ /etc/pm/power.d/??wifi false
+ ;;
+ 1) # on battery
+ /etc/pm/power.d/??wifi true
+ ;;
+ esac
+ fi
+ ;;
+ *)
+ ;;
+esac
+
+exit $?
+
+
diff --git a/doc/ethernet-subr.html b/doc/ethernet-subr.html
new file mode 100644
index 0000000..3d74cf8
--- /dev/null
+++ b/doc/ethernet-subr.html
@@ -0,0 +1,99 @@
+<h1 id="ethernet-iproute-connection-manual"
+>ethernet-iproute Connection manual</h1
+><h2 id="description"
+>Description</h2
+><p
+>This connection method uses the iproute suite of tools and dhcpcd to gain an IP address.</p
+><h2 id="options"
+>Options</h2
+><dl
+><dt
+ >INTERFACE (required)</dt
+ ><dd
+ >The wireless interface to configure</dd
+ ><dt
+ >IP (required)</dt
+ ><dd
+ >Can be either 'static' or 'dhcp'. Static requires at least one of ADDR or IPCFG.</dd
+ ><dt
+ >ADDR (requires IP of 'static')</dt
+ ><dd
+ >A single IP address to configure a static IP. For example:</dd
+ ><dt
+ >GATEWAY (requires IP of 'static')</dt
+ ><dd
+ >Set specified gateway</dd
+ ><dt
+ >IPCFG</dt
+ ><dd
+ >Array of arguments to pass to 'ip'. The power of this options is that it allows both simple and complicated routing configurations, within the framework of netcfg.</dd
+ ></dl
+><h3 id="dns"
+>DNS</h3
+><dl
+><dt
+ >DNS</dt
+ ><dd
+ >Array of DNS nameservers. Simply specify the IP's of each of the DNS nameservers.</dd
+ ><dt
+ >SEARCH</dt
+ ><dd
+ >&quot;search&quot; line for /etc/resolv.conf</dd
+ ><dt
+ >DOMAIN</dt
+ ><dd
+ >&quot;domain&quot; line for /etc/resolv.conf</dd
+ ><dt
+ >HOSTNAME</dt
+ ><dd
+ >Set the system hostname. Ensure any hostname is correctly referenced in /etc/hosts.</dd
+ ></dl
+><h3 id="dhcp"
+>DHCP</h3
+><dl
+><dt
+ >DHCP_OPTIONS</dt
+ ><dd
+ >String. Any extra arguments to pass to the dhcp client, presently dhcpcd.</dd
+ ><dt
+ >DHCP_TIMEOUT</dt
+ ><dd
+ >Integer. Maximum time to try for a DHCP IP. Default is 10 seconds.</dd
+ ></dl
+><h3 id="x-authentication"
+>802.11x Authentication</h3
+><dl
+><dt
+ >AUTH8021X</dt
+ ><dd
+ >Use 802.11x authentication. Enable with 'yes'.</dd
+ ><dt
+ >WPA_CONF (required for an AUTH8021X of 'yes' only)</dt
+ ><dd
+ >Path to wpa_supplicant configuration. Defaults to '/etc/wpa_supplicant.conf'</dd
+ ><dt
+ >WPA_OPTS (optional for an AUTH8021X of 'yes')</dt
+ ><dd
+ >Extra arguments for wpa_supplicant not specified otherwise. Any option here must specify wpa_supplicant driver. Defaults to '-Dwired'.</dd
+ ></dl
+><h2 id="examples"
+>Examples</h2
+><h3 id="using-addr-and-gateway-to-set-static-ip-and-gateway"
+>Using ADDR and GATEWAY to set static IP and gateway</h3
+><pre
+><code
+ >IP=&quot;static&quot;
+ADDR=&quot;192.168.1.23&quot;
+GATEWAY=&quot;192.168.1.1&quot;
+</code
+ ></pre
+><h3 id="using-ipcfg-to-set-a-static-ip-and-gateway-with-custom-dns"
+>Using IPCFG to set a static IP and gateway with custom DNS</h3
+><pre
+><code
+ >IP=&quot;static&quot;
+IPCFG=(&quot;addr add dev eth0 192.168.1.23/24 brd +&quot; &quot;route add default via 192.168.1.1&quot;)
+DNS=(&quot;208.67.222.222&quot; &quot;208.67.220.220&quot;)
+</code
+ ></pre
+>
diff --git a/doc/ethernet.html b/doc/ethernet.html
new file mode 100644
index 0000000..b2ab91a
--- /dev/null
+++ b/doc/ethernet.html
@@ -0,0 +1,87 @@
+<h1 id="ethernet-manual"
+>ethernet Manual</h1
+><h2 id="description"
+>Description</h2
+><p
+>This connection method uses the unmaintained net-tools (ifconfig) and dhcpcd to gain an IP address.</p
+><h2 id="options"
+>Options</h2
+><dl
+><dt
+ >INTERFACE (required)</dt
+ ><dd
+ >The wireless interface to configure</dd
+ ><dt
+ >IP (required)</dt
+ ><dd
+ >Can be either 'static' or 'dhcp'. Static requires IFOPTS at least.</dd
+ ><dt
+ >IFOPTS</dt
+ ><dd
+ >Arguments to pass to 'ifconfig'.</dd
+ ><dt
+ >GATEWAY (requires IP of 'static')</dt
+ ><dd
+ >Set specified gateway</dd
+ ></dl
+><h3 id="dns"
+>DNS</h3
+><dl
+><dt
+ >DNS</dt
+ ><dd
+ >Array of DNS nameservers. Simply specify the IP's of each of the DNS nameservers.</dd
+ ><dt
+ >DNS1, DNS2 (deprecated)</dt
+ ><dd
+ >Specify first and second nameservers.</dd
+ ><dt
+ >SEARCH</dt
+ ><dd
+ >&quot;search&quot; line for /etc/resolv.conf</dd
+ ><dt
+ >DOMAIN</dt
+ ><dd
+ >&quot;domain&quot; line for /etc/resolv.conf</dd
+ ><dt
+ >HOSTNAME</dt
+ ><dd
+ >Set the system hostname. Ensure any hostname is correctly referenced in /etc/hosts.</dd
+ ></dl
+><h3 id="dhcp"
+>DHCP</h3
+><dl
+><dt
+ >DHCLIENT</dt
+ ><dd
+ >yes/no. Use dhclient instead of dhcpcd. Defaults to no.</dd
+ ><dt
+ >DHCP_OPTIONS</dt
+ ><dd
+ >String. Any extra arguments to pass to the dhcp client, presently dhcpcd.</dd
+ ><dt
+ >DHCP_TIMEOUT</dt
+ ><dd
+ >Integer. Maximum time to try for a DHCP IP. Default is 10 seconds.</dd
+ ></dl
+><h3 id="x-authentication"
+>802.11x Authentication</h3
+><dl
+><dt
+ >AUTH8021X</dt
+ ><dd
+ >Use 802.11x authentication. Enable with 'yes'.</dd
+ ><dt
+ >WPA_CONF (required for an AUTH8021X of 'yes' only)</dt
+ ><dd
+ >Path to wpa_supplicant configuration. Defaults to '/etc/wpa_supplicant.conf'</dd
+ ><dt
+ >WPA_OPTS (optional for an AUTH8021X of 'yes')</dt
+ ><dd
+ >Extra arguments for wpa_supplicant not specified otherwise. Any option here must specify wpa_supplicant driver. Defaults to '-Dwired'.</dd
+ ></dl
+><h2 id="examples"
+>Examples</h2
+><p
+>See /etc/network.d/examples</p
+>
diff --git a/doc/wireless b/doc/wireless
index 20ced91..e1f649e 100644
--- a/doc/wireless
+++ b/doc/wireless
@@ -17,8 +17,10 @@ SECURITY (required for security of 'wep', 'wpa' or 'wpa-config')
: One of 'wpa', 'wep', 'none' or 'wpa-config'. Defaults to 'none'
KEY (required for SECURITY of 'wpa' or 'wep' only)
: Wireless encryption key.
-ESSID (required)
+ESSID (this or AP is required)
: Name of network to connect to.
+AP (this or ESSID is required)
+: AP of the network to connect to.
TIMEOUT (optional)
: Time to wait for association. Defaults to 15 seconds.
SCAN (optional)
@@ -31,3 +33,6 @@ WPA_CONF (for SECURITY of 'wpa-config' only)
: Path to wpa_supplicant configuration. Defaults to '/etc/wpa_supplicant.conf'
WPA_OPTS
: Extra arguments for wpa_supplicant not specified otherwise. Any option here must specify wpa_supplicant driver. Defaults to '-Dwext'.
+WPA_GROUP
+: Group that has authority for on-the-fly config files created when SECURITY="wpa"
+
diff --git a/doc/wireless-dbus b/doc/wireless-dbus
index 918256d..bddd565 100644
--- a/doc/wireless-dbus
+++ b/doc/wireless-dbus
@@ -15,8 +15,10 @@ SECURITY (required)
: One of 'wpa', 'wep', 'none' or 'wpa-config'
KEY (required for SECURITY of 'wpa' or 'wep' only)
: Wireless encryption key.
-ESSID (required)
-: Name of network to connect to.
+ESSID (this or AP is required)
+: Name of network to connect to. Note that for "wireless-dbus" profiles this is always a Gnu regexp (as interpreted by "expr").
+AP (this or ESSID is required)
+: AP of the network to connect to.
TIMEOUT
: Time to wait for association. Defaults to 15 seconds.
diff --git a/doc/wireless-dbus.html b/doc/wireless-dbus.html
new file mode 100644
index 0000000..a2d2aea
--- /dev/null
+++ b/doc/wireless-dbus.html
@@ -0,0 +1,53 @@
+<h1 id="wireless-dbus-connection-manual"
+>'wireless-dbus' Connection manual</h1
+><h2 id="description"
+>Description</h2
+><p
+>This connection method uses wpa_supplicant's dbus interface to configure a wireless network connection.</p
+><p
+>This connection uses the 'ethernet-iproute' connection after successful association and thus supports all of it's options.</p
+><h2 id="options"
+>Options</h2
+><dl
+><dt
+ >INTERFACE (required)</dt
+ ><dd
+ >The wireless interface to configure</dd
+ ><dt
+ >SECURITY (required)</dt
+ ><dd
+ >One of 'wpa', 'wep', 'none' or 'wpa-config'</dd
+ ><dt
+ >KEY (required for SECURITY of 'wpa' or 'wep' only)</dt
+ ><dd
+ >Wireless encryption key.</dd
+ ><dt
+ >ESSID (this or AP is required)</dt
+ ><dd
+ >Name of network to connect to. Note that for &quot;wireless-dbus&quot; profiles this is always a Gnu regexp (as interpreted by &quot;expr&quot;).</dd
+ ><dt
+ >AP (this or ESSID is required)</dt
+ ><dd
+ >AP of the network to connect to.</dd
+ ><dt
+ >TIMEOUT</dt
+ ><dd
+ >Time to wait for association. Defaults to 15 seconds.</dd
+ ></dl
+><h3 id="wpa-options"
+>WPA options</h3
+><dl
+><dt
+ >WPA_CONF (for SECURITY of 'wpa-config' only)</dt
+ ><dd
+ >Path to wpa_supplicant configuration. Defaults to '/etc/wpa_supplicant.conf'</dd
+ ><dt
+ >WPA_DRIVER</dt
+ ><dd
+ >wpa_supplicant driver to be used. Defaults to 'wext'</dd
+ ><dt
+ >WPA_OPTS</dt
+ ><dd
+ >Extra arguments for wpa_supplicant not specified otherwise.</dd
+ ></dl
+>
diff --git a/doc/wireless.html b/doc/wireless.html
new file mode 100644
index 0000000..d78d7b6
--- /dev/null
+++ b/doc/wireless.html
@@ -0,0 +1,63 @@
+<h1 id="wireless-connection-manual"
+>'wireless' Connection manual</h1
+><h2 id="description"
+>Description</h2
+><p
+>This connection method uses wireless_tools and wpa_supplicant to configure a wireless network connection.</p
+><p
+>The new 'wireless-dbus' connection method is preferred over this</p
+><p
+>This connection uses the 'ethernet' connection after successful association and thus supports all of it's options.</p
+><h2 id="options"
+>Options</h2
+><dl
+><dt
+ >INTERFACE (required)</dt
+ ><dd
+ >The wireless interface to configure</dd
+ ><dt
+ >SECURITY (required for security of 'wep', 'wpa' or 'wpa-config')</dt
+ ><dd
+ >One of 'wpa', 'wep', 'none' or 'wpa-config'. Defaults to 'none'</dd
+ ><dt
+ >KEY (required for SECURITY of 'wpa' or 'wep' only)</dt
+ ><dd
+ >Wireless encryption key.</dd
+ ><dt
+ >ESSID (this or AP is required)</dt
+ ><dd
+ >Name of network to connect to.</dd
+ ><dt
+ >AP (this or ESSID is required)</dt
+ ><dd
+ >AP of the network to connect to.</dd
+ ><dt
+ >TIMEOUT (optional)</dt
+ ><dd
+ >Time to wait for association. Defaults to 15 seconds.</dd
+ ><dt
+ >SCAN (optional)</dt
+ ><dd
+ >Scan for a wireless network rather than blindly attempting to connect. Hidden SSID networks do not appear in a scan. Enable with 'yes'. Defaults to 'no'.</dd
+ ><dt
+ >IWCONFIG (optional)</dt
+ ><dd
+ >Arguments to pass to iwconfig before attempting to configure the connection. For example, BSSID.</dd
+ ></dl
+><h3 id="wpa-options"
+>WPA options</h3
+><dl
+><dt
+ >WPA_CONF (for SECURITY of 'wpa-config' only)</dt
+ ><dd
+ >Path to wpa_supplicant configuration. Defaults to '/etc/wpa_supplicant.conf'</dd
+ ><dt
+ >WPA_OPTS</dt
+ ><dd
+ >Extra arguments for wpa_supplicant not specified otherwise. Any option here must specify wpa_supplicant driver. Defaults to '-Dwext'.</dd
+ ><dt
+ >WPA_GROUP</dt
+ ><dd
+ >Group that has authority for on-the-fly config files created when SECURITY=&quot;wpa&quot;</dd
+ ></dl
+>
diff --git a/examples/ethernet-iproute b/examples/ethernet-iproute
index 6ac20e1..6ac20e1 100755..100644
--- a/examples/ethernet-iproute
+++ b/examples/ethernet-iproute
diff --git a/man/netcfg.8 b/man/netcfg.8
index f07e12a..312366d 100644
--- a/man/netcfg.8
+++ b/man/netcfg.8
@@ -1,4 +1,4 @@
-.TH NETCFG 8 "MAY 2007" "Arch Linux" "Network Scripts"
+.TH NETCFG 8 "AUGUST 2009" "Arch Linux" "Network Scripts"
.\" groff -man -Tascii foo.1
.SH NAME
netcfg \- start/stop/control network profiles
@@ -19,10 +19,13 @@ Start the specified profile, only if it's interface is not currently up.
.B \-d, down \fIprofile\fP
Stop the specified profile
.TP
+.B\-r, reconnect \fIprofile\fP
+Disconnect and reconnect the specified profile
+.TP
.B \-i, iface-down \fBinterface\fP
Stop the profile up on the specified interface.
.TP
-.B \-a, all-down
+.B \-a, all-down
Stop all connected profiles
.TP
.B all-suspend
@@ -31,19 +34,28 @@ Suspend and store the name of all active profiles.
.B all-resume
Reconnect any profiles that have been suspended.
.TP
+.B current
+Report currently running profiles
+.TP
+.B \-l, list
+List all available profiles
+.TP
.B \-v, --version
Display version information and exit
.TP
.B \-h, --help
Display help message and exit
-.SH FILES
+.SH FILES
.TP
.I /usr/lib/network/
Currently installed network profile types.
.TP
-.I /etc/network.d/examples
+.I /etc/network.d/examples
Example configurations for this script
+.TP
+.I /etc/network.d/hooks
+See /usr/share/doc/netcfg/contrib for examples.
.SH BUGS
None, hopefully, but if you do find one of these elusive things, please submit at http://bugs.archlinux.org/ or email one of the authors below.
@@ -52,6 +64,6 @@ James Rayner <james@archlinux.org>
Others listed in AUTHORS file in source.
.SH SEE ALSO
-.BR ethernet (5),
+.BR ethernet (5),
.BR iwconfig (8),
.BR wireless (5)
diff --git a/src-wireless/net-auto b/src-wireless/net-auto
index 8b724a5..98bb91d 100755..100644
--- a/src-wireless/net-auto
+++ b/src-wireless/net-auto
@@ -2,12 +2,16 @@
. /etc/rc.conf
. /etc/rc.d/functions
+. /usr/lib/network/globals
case "$1" in
start)
+ if ! ck_daemon net-auto; then # JP: check if it's already running
+ exit_stderr "net-auto has already been started: try \"/etc/rc.d/net-auto restart\""
+ fi
# Ensure any device renaming has occurred as intended
for daemon in "${DAEMONS[@]}"; do
- if [ "$daemon" = "${daemon#!}" -a "$daemon" = "net-rename" ]; then
+ if [[ "$daemon" = "${daemon#!}" && "$daemon" = net-rename ]]; then
if ck_daemon net-rename; then
/etc/rc.d/net-rename start
fi
@@ -15,28 +19,43 @@ case "$1" in
done
# TODO: check if any way of using 'stacks' in bash
- for iface in ${AUTO_NETWORKS[@]}; do
- if [[ "${iface:0:4}" = "auto" ]]; then
- auto=$iface
- elif [[ "$auto" ]]; then
- /usr/bin/netcfg-$auto $iface
- [[ $? -eq 0 ]] && echo $iface >> /var/run/daemons/net-auto
+
+ rm -f "$STATE_DIR/net-auto"
+ for iface in "${AUTO_NETWORKS[@]}"; do
+ if [[ "${iface:0:4}" = auto ]]; then
+ auto="$iface"
+ elif [[ -n "$auto" ]]; then
+ if /usr/bin/netcfg-"$auto" "$iface"; then
+ echo "$iface" >> "$STATE_DIR/net-auto"
+ add_daemon net-auto # JP: was this forgotten?
+ fi
unset auto
+ else
+ true # JP: can AUTO_NETWORKS contain elements other than ...auto-CONNECTION INTERFACE...?
+ # JP: for example, what do we do with AUTO_NETWORKS=(auto-wireless wlan0 eth0)?
+ # JP: or with AUTO_NETWORKS=(eth0 auto-wireless wlan0)?
fi
done
;;
stop)
- [[ ! -e /var/run/daemons/net-auto ]] && exit 0
- for iface in $(cat /var/run/daemons/net-auto); do
- netcfg iface-down $iface
+ if ck_daemon net-auto; then
+ exit_stderr "net-auto not running"
+ fi
+
+ for iface in $(cat "$STATE_DIR/net-auto"); do # JP: note that we may have written "wlan0 wlan1" to net-auto
+ # e.g. if the user did AUTO_NETWORKS=(auto-wireless "wlan0 wlan1")
+ # and now we're unpacking and handling wlan0, wlan1 one by one
+ # that's not necessarily a problem...I'm just calling attention to it
+ /usr/bin/netcfg iface-down "$iface"
done
+ rm -f "$STATE_DIR/net-auto"
rm_daemon net-auto
;;
restart)
- $0 stop; sleep 1; $0 start
+ "$0" stop; sleep 1; "$0" start
;;
*)
- echo "usage: $0 {start|stop|restart}"
+ exit_stderr "Usage: $0 {start|stop|restart}"
esac
# vim: set ts=4 et sw=4:
diff --git a/src-wireless/netcfg-auto-wireless b/src-wireless/netcfg-auto-wireless
index e77eb0e..a17232c 100755..100644
--- a/src-wireless/netcfg-auto-wireless
+++ b/src-wireless/netcfg-auto-wireless
@@ -1,59 +1,128 @@
#! /bin/bash
# Originally contributed by Neuro: http://bbs.archlinux.org/viewtopic.php?pid=278148#p278148
-. /usr/lib/network/network
-. /usr/lib/network/wireless
. /etc/rc.conf
. /etc/rc.d/functions
+. /usr/lib/network/network
+. /usr/lib/network/wireless_utils
# wifi_auto
# autoconnect wireless interface
# $1 - wireless interface
wifi_auto()
{
- interface=$1;
- stat_busy "Scanning for networks"
+ local interface="$1" connection="$2"
+
+ if [[ ! -f "$CONN_DIR/$connection" ]]; then
+ exit_err "$connection is not a valid connection."
+ elif ! "$CONN_DIR/$connection" verify "$interface"; then
+ exit_err "$interface is not a wireless interface."
+ fi
+
+ report_try "Scanning for networks"
- ifconfig $interface up
- networks="$(list_networks $interface)"
+ local status=$(query_iface "$interface" "$connection") # supply $connection as hint
+ case "$status" in
+ disabled)
+ exit_fail "INTERFACE $interface is disabled."
+ ;;
+ external)
+ exit_fail "INTERFACE $interface was configured by another application."
+ ;;
+ "")
+ #ifconfig "$interface" up 2>/dev/null # $? is 255 when radio-switched-off
+ "$CONN_DIR/$connection" control "$interface" up
+ if [[ $? -gt 0 ]]; then
+ # interface is really disabled
+ "$CONN_DIR/$connection" control "$interface" disable
+ exit_fail "INTERFACE $interface is disabled."
+ fi
+ ;;
+ *)
+ # interface already up and controlled by a profile
+ ;;
+ esac
- if [[ ! "$networks" ]]; then
- stat_append "- No networks available."
- stat_fail
- exit 1
+ networks=$(list_networks "$interface")
+
+ if [[ -z "$networks" ]]; then
+ # disconnect interface if it wasn't already up
+ [[ -z "$status" ]] && "$CONN_DIR/$connection" control "$interface" forcedown
+ exit_fail "No local networks."
fi
+ [[ -z "$status" ]] && "$CONN_DIR/$connection" control "$interface" down # take iface down here so that query_iface doesn't perceive it as externally controlled
+ # unclear what should happen if $status set to an already-connected profile...?
+
# Loop through all the found essid's, then find a matching profile.
- while read essid; do
- for network in $(list_profiles); do
- load_profile $network
- case "$CONNECTION" in
- wireless-old|wireless|wireless-dbus)
- if [[ "$essid" = "$ESSID" && "$interface" = "$INTERFACE" ]]; then
- found=$network
- fi
- ;;
- esac
- done
- done < $networks
+
+ local found_profile found_essid
+
+ # JP: add ability to use AP instead of ESSID
+ # JP: also, make ESSIDs in wireless-dbus CONNECTIONS a regexp instead of a literal
+ while read ap essid; do
+ while read network; do
+ (
+ unset CONNECTION INTERFACE AP
+ load_profile "$network"
+ case "$CONNECTION" in
+ wireless-old|wireless|wireless-dbus)
+ if [[ "$interface" = "$INTERFACE" ]]; then
+ if [[ "$ap" == "$AP" ]]; then
+ exit 2
+ elif [[ -z "$found_profile" ]]; then
+ if [[ "$CONNECTION" == wireless-dbus ]]; then
+ if expr match "$essid" "^$ESSID\$" 1>/dev/null; then
+ exit 1
+ fi
+ elif [[ "$essid" == "$ESSID" ]]; then
+ exit 1
+ fi
+ fi
+ fi
+ ;;
+ esac
+ exit 0
+ )
+ case $? in
+ 2) found_profile="$network"
+ found_essid="$essid"
+ break 2;;
+ 1) found_profile="$network"
+ found_essid="$essid"
+ ;;
+ esac
+ done < <(list_profiles) # avoid subshell
+ done < "$networks" # avoid subshell; list_networks returns name of a tmp file
+ # JP: now each line of that file is of format: ap essid...
- if [[ "$found" ]]; then
- netcfg $found
- exit $?
+ rm -f "$networks" # shouldn't we delete the tmp file?
+
+ if [[ -n "$found_profile" ]]; then
+ report_success
+ if profile_up "$found_profile" "$found_essid"; then # we pass literal essid to profile_up as $2
+ exit 0
+ else
+
+
+
+ "$CONN_DIR/$connection" control "$interface" forcedown # take down interface?
+ exit_fail "Couldn't connect profile $found_profile."
+ fi
+ else
+ [[ -z "$status" ]] && "$CONN_DIR/$connection" control "$interface" forcedown
+ exit_fail "No profiles matched the local networks."
fi
- stat_append "- No profiles matched the found networks"
- stat_fail
- exit 1
}
if [[ $(id -u) -ne 0 ]]; then
- err "This script needs to be run with root priviledges"
- exit 1
+ exit_stderr "This script should be run as root."
fi
-if [[ -z $1 ]]; then
- err "Please supply an interface to connect"
- exit 1
+if [[ -z "$1" ]]; then
+ exit_stderr "Must supply an interface to connect."
fi
-wifi_auto $1
-
+
+SELF=$(basename $0)
+wifi_auto "$1" "${SELF#netcfg-auto-}" # we assume this script is named netcfg-auto-CONNECTIONTYPE
+
diff --git a/src-wireless/wireless-dbus b/src-wireless/wireless-dbus
index 6f53a6c..f1c1cd8 100755..100644
--- a/src-wireless/wireless-dbus
+++ b/src-wireless/wireless-dbus
@@ -4,7 +4,7 @@ import dbus
import shlex
import subprocess
from signal import SIGTERM
-from os import kill
+from os import kill,path
from time import sleep
# dbus constants.
@@ -21,16 +21,20 @@ def read_config(config):
cfg = shlex.split(open(config, "r").read())
options = {}
for line in cfg:
- (var, delim, value) = line.partition('=')
- if delim and var.lstrip()[0] != "#":
- options[var] = value
+ (var, delim, value) = line.partition('=')
+ if delim:
+ var = var.lstrip()
+ if var[0] != '#':
+ value = value.partition("#")[0].rstrip()
+ if value[0] == value[-1] and value[0] in ('"',"'"):
+ value=value[1:-1]
+ options[var] = value
return options
def wep_hex2dec(key):
if len(key) not in [10, 26]:
- print "Bad key"
- raise SyntaxError
+ fail("Profile error: invalid KEY.", report_type="err")
x=0
new_key=[]
@@ -40,14 +44,24 @@ def wep_hex2dec(key):
return new_key
-def fail(msg=None):
+# JP: connect to our hookable reporting functions in /usr/lib/network/globals
+
+def report(report_type, *args):
+ report_handler.stdin.write('report_%s %s\n' % (report_type, ' '.join(map(repr,args))))
+
+def fail(msg=None, report_type="fail"):
if msg:
- print " -", msg
- kill(int(open("/var/run/wpa_supplicant.pid").read()),SIGTERM)
+ report(report_type, msg)
+ try:
+ pid = open("/var/run/wpa_supplicant.pid").read()
+ except IOError:
+ pass
+ else:
+ kill(int(pid),SIGTERM)
sys.exit(1)
-def start(profile):
+def start(profile, essid):
# TODO: Add check if it's even a wireless interface
# Interface up - probably redundant, should be 'ip' instead.
#try:
@@ -68,22 +82,25 @@ def start(profile):
except KeyError:
args.append("-Dwext")
- if profile['SECURITY'] == "wpa-config":
+ security = profile.get('SECURITY','none')
+ if security == "wpa-config":
try:
args.append("-c" + profile["WPA_CONF"])
except KeyError:
args.append("-c/etc/wpa_supplicant.conf")
- elif not profile['SECURITY'] in ['wpa', 'wep', 'none']:
- fail("Invalid security chosen")
+ elif not security in ['wpa', 'wep', 'none']:
+ fail("Profile error: invalid SECURITY.", report_type="err")
# Start wpa_supplicant
+ report('debug', 'wireless_dbus', 'starting wpa_supplicant')
supplicant = subprocess.Popen(args,stderr=subprocess.STDOUT,stdout=subprocess.PIPE)
output = supplicant.communicate()[0]
if supplicant.returncode not in [255,0]:
- print output
- fail("Could not start wpa_supplicant")
+ print >>sys.stderr, output # JP: print to stderr
+ fail("Couldn't start wpa_supplicant.")
# Connect to wpa_supplicant
+ report('debug', 'wireless_dbus', 'connecting to wpa_supplicant')
bus = dbus.SystemBus()
wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
@@ -104,20 +121,26 @@ def start(profile):
iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE);
# Add and select the network. Networks already specified for wpa-config
- if profile['SECURITY'] in ['wpa','wep','none']:
+ if security in ['wpa','wep','none']:
+ report('debug', 'wireless_dbus', 'add and select network')
path = iface.addNetwork()
net_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
rnet = dbus.Interface(net_obj, WPAS_DBUS_NETWORKS_INTERFACE)
iface.selectNetwork(rnet)
+ if not essid:
+ essid = profile["ESSID"]
- if profile['SECURITY'] == "wpa":
- opts = dbus.Dictionary({"ssid": dbus.ByteArray(profile['ESSID']),
+ if security == "wpa":
+ opts = dbus.Dictionary({"ssid": dbus.ByteArray(essid),
"psk": dbus.String(profile['KEY'])},
signature="sv")
+ report('debug', 'wireless_dbus', 'connect to network with security=wpa')
+ # next line crashes with
+ # dbus.exceptions.DBusException: fi.epitest.hostap.WPASupplicant.InvalidOptions: Did not receive correct message arguments
rnet.set(opts)
- elif profile['SECURITY'] == "wep":
+ elif security == "wep":
key=profile['KEY']
if key[:2] == "s:": # String key prefixed by "s:"
keydbus=key[2:]
@@ -127,15 +150,17 @@ def start(profile):
for l in key:
keydbus+=chr(l)
- opts = dbus.Dictionary({"ssid": dbus.ByteArray(profile['ESSID']),
+ opts = dbus.Dictionary({"ssid": dbus.ByteArray(essid),
"key_mgmt": dbus.String("NONE"),
"wep_tx_keyidx": dbus.Int32(1),
"wep_key0": dbus.ByteArray(keydbus)},
signature="sv")
+ report('debug', 'wireless_dbus', 'connect to network with security=wep')
rnet.set(opts)
- elif profile['SECURITY'] == "none":
- opts = dbus.Dictionary({"ssid": dbus.ByteArray(profile['ESSID'])},
+ elif security == "none":
+ opts = dbus.Dictionary({"ssid": dbus.ByteArray(essid)},
signature="sv")
+ report('debug', 'wireless_dbus', 'connect to network with security=none')
rnet.set(opts)
# Determine timeout
@@ -154,24 +179,81 @@ def start(profile):
break
if n == timeout:
- fail("Association/Authentication failed:" + state)
+ # fail("Association/Authentication failed:" + state)
+ fail("Couldn't associate/authenticate with wireless network.")
# Run ethernet and get an ip.
try:
- subprocess.check_call(["/usr/lib/network/connections/ethernet-iproute", "up", sys.argv[2]])
+ subprocess.check_call([ETHERNET_IPROUTE, "up", sys.argv[2]])
except subprocess.CalledProcessError:
fail()
sys.exit(0)
def stop(profile):
- subprocess.call(["/usr/lib/network/connections/ethernet", "down", sys.argv[2]])
+ ret = subprocess.call([ETHERNET_IPROUTE, "down", sys.argv[2]])
kill(int(open("/var/run/wpa_supplicant.pid").read()),SIGTERM)
- sys.exit(0)
+ sys.exit(ret)
+
+def query(interface,request):
+ if request == 'profile' or request=='enabled':
+ ret = subprocess.call([WIRELESS, "query", interface, request, "-iproute"]) # JP: left some of the new query functionality in the wireless file because it's so bash-heavy
+ elif request=='associated':
+ ret = subprocess.call([WIRELESS, "query", interface, request, "-iproute", sys.argv[5], sys.argv[6]]) # JP: left some of the new query functionality in the wireless file because it's so bash-heavy
+ else:
+ ret = subprocess.call([ETHERNET_IPROUTE, "query", interface, request]) # JP: for these requests, we can call the ethernet-iproute functions directly and save some process overhead
+ sys.exit(ret)
+
+def control(interface,action):
+ if action == 'enable' or action == 'disable':
+ ret = subprocess.call([WIRELESS, "control", interface, action])
+ else:
+ ret = subprocess.call([ETHERNET_IPROUTE, "control", interface, action]) # JP: for these actions, we can call the ethernet-iproute functions directly and save some process overhead
+ sys.exit(ret)
+
+def verify(interface):
+ ret = subprocess.call([WIRELESS, "verify", interface])
+ sys.exit(ret)
if __name__ == "__main__":
- profile = read_config("/etc/network.d/"+sys.argv[2])
-
- if sys.argv[1] == "up":
- start(profile)
- elif sys.argv[1] == "down":
- stop(profile)
+
+ CONN_DIR = path.abspath(path.dirname(sys.argv[0]))
+ ETHERNET_IPROUTE = path.join(CONN_DIR,"ethernet-iproute")
+ WIRELESS = path.join(CONN_DIR,"wireless")
+
+ if sys.argv[1] == "query":
+ interface,request = sys.argv[2:4]
+ query(interface,request)
+
+ elif sys.argv[1] == "control":
+ interface,action = sys.argv[2:4]
+ control(interface,action)
+
+ elif sys.argv[1] == "verify":
+ interface = sys.argv[2]
+ verify(interface)
+
+ else:
+ # setup bash report_* handler
+ report_handler_script = 'source /etc/rc.conf; source /etc/rc.d/functions; source %s/../globals; while read cmd args; do eval $cmd "$args"; done' % (CONN_DIR,)
+ report_handler = subprocess.Popen(report_handler_script, executable='/bin/bash', stdin=subprocess.PIPE, shell=True)
+
+ try:
+ profile_name = sys.argv[2]
+ profile = read_config("/etc/network.d/"+profile_name)
+
+ essid = sys.argv[3] if len(sys.argv)>3 else "" # JP: pass literal ESSID as an argument, so that we can have entry in profile be a regexp
+
+ if 'INTERFACE' not in profile:
+ fail("Profile error: no INTERFACE to configure.", report_type="err")
+
+ if sys.argv[1] == "up":
+ start(profile, essid)
+ elif sys.argv[1] == "down":
+ stop(profile)
+
+
+ finally:
+ report_handler.stdin.close()
+ report_handler.wait()
+
+# vim: et ts=4
diff --git a/src/8021x b/src/8021x
index 75030e9..7daecce 100644
--- a/src/8021x
+++ b/src/8021x
@@ -1,45 +1,53 @@
+##################################
+##
+# /usr/lib/network/8021x
+##
+##################################
+
# Uses wpa_supplicant to check for association to a network
# wpa_check interface [timeout]
wpa_check()
{
- local timeout=0 INTERFACE=$1 TIMEOUT=${2:-15}
+ local INTERFACE="$1" TIMEOUT="${2:-15}" timeout=0
- while [[ $timeout -lt $TIMEOUT ]]; do
+ while [[ "$timeout" -lt "$TIMEOUT" ]]; do
( # Sometimes wpa_supplicant isn't ready so silence errors for 2s only to avoid hiding real errors
- if [[ $timeout -lt 2 ]]; then
- eval `wpa_cli status 2> /dev/null|grep wpa_state`
+ if [[ "$timeout" -lt 2 ]]; then
+ eval $(wpa_cli -i "$INTERFACE" status 2> /dev/null | fgrep "wpa_state=")
else
- eval `wpa_cli status|grep wpa_state`
+ eval $(wpa_cli -i "$INTERFACE" status | fgrep "wpa_state=")
fi
- [[ "$wpa_state" = "COMPLETED" ]]
+ [[ "$wpa_state" = COMPLETED ]]
) && return 0
sleep 1
let timeout++
done
wpa_cli terminate >/dev/null 2>&1
- err_append "Authentication/association failed"
+ report_fail "Couldn't associate/authenticate with wireless network."
return 1
}
start_wpa()
{
- INTERFACE="$1"; WPA_CONF="$2"; WPA_OPTS="$3"
+ local INTERFACE="$1" WPA_CONF="$2" WPA_OPTS="$3"
- wpa_supplicant -B -P/var/run/wpa_supplicant_${INTERFACE}.pid -i"${INTERFACE}" -c "$WPA_CONF" $WPA_OPTS
+ wpa_supplicant -B -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"
+ if [[ ! -f "/var/run/wpa_supplicant_$INTERFACE.pid" ]]; then
+ report_fail "wpa_supplicant did not start, possible configuration error"
return 1
fi
}
stop_wpa()
{
- wpa_cli terminate &> /dev/null
- if [[ -f /var/run/wpa_supplicant_$1.pid ]]; then
- kill $(cat /var/run/wpa_supplicant_$1.pid) &>/dev/null &
+ wpa_cli -i "$1" terminate &> /dev/null
+ sleep 1 # JP: need this else the file tends to disappear after [[ -f ... ]] but before cat...
+ # see <http://bbs.archlinux.org/viewtopic.php?pid=515667#p515667>
+ if [[ -f "/var/run/wpa_supplicant_$1.pid" ]]; then
+ kill $(cat "/var/run/wpa_supplicant_$1.pid") &>/dev/null &
fi
}
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:
+
diff --git a/src/globals b/src/globals
new file mode 100644
index 0000000..e227d51
--- /dev/null
+++ b/src/globals
@@ -0,0 +1,118 @@
+##################################
+##
+# /usr/lib/network/globals
+##
+##################################
+
+# JP: rather than declare these in several library files, we just declare them
+# once here, so they only need to be changed at a single point
+
+# JP: added the /etc/network.d/hooks directory
+# any +x files in that directory will be sourced when this file is sourced
+# they can override any of the utility functions defined here for custom behavior
+# (such as logging error messages to syslog, as I like to do)
+# 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/"
+HOOKS_DIR="$PROFILE_DIR/hooks/"
+SUBR_DIR="/usr/lib/network/"
+CONN_DIR="${SUBR_DIR}/connections/"
+STATE_DIR="/var/run/network/"
+
+
+### Logging/Error reporting
+#
+
+function report_err {
+ printhl "$*"
+}
+
+function report_warn {
+ printhl "$*"
+}
+
+function report_notify {
+ true
+}
+
+function report_debug {
+ true
+}
+
+function report_try {
+ stat_busy "$*"
+ REPORT_TRYING=1
+}
+
+function report_fail {
+ if [[ -n "$*" ]]; then
+ if [[ -n "$REPORT_TRYING" ]]; then
+ stat_append "- $*"
+ REPORT_TRYING=
+ stat_fail
+ else
+ printhl "$*"
+ fi
+ elif [[ -n "$REPORT_TRYING" ]]; then
+ REPORT_TRYING=
+ stat_fail
+ fi
+}
+
+function report_success {
+ if [[ -n "$*" ]]; then
+ stat_append "- $*"
+ fi
+ stat_done
+}
+
+### 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; }
+
+
+
+function line_input {
+ # saves $IFS and noglob shell option (to restore them, eval the output of this function)
+ if [[ $(shopt -o noglob) =~ off ]]; then
+ printf "set +f; IFS=%q" "$IFS"
+ else
+ printf "set -f; IFS=%q" "$IFS"
+ fi
+ # now set $IFS and noglob to handle line-at-a-time input
+ set -f
+ IFS=$'\n'
+}
+
+function load_hooks() {
+ ### Load any +x files in $HOOKS_DIR
+
+ # JP: we need to process line-at-a-time input (don't want to assume path to HOOKS_DIR and its content are all single bash tokens)
+ # find ... | while read ... is no good because anything we do inside the while read ... subshell will be invisible to the outside calling context
+
+# # JP: this technique works in general (and is used elsewhere in the code)
+# # <(cmd) creates a file descriptor whose content is the stdout of cmd, which we then use as stdin by saying "< <(cmd)"
+#
+# # JP: HOWEVER, for reasons I don't understand, this construct can't be sourced from the Python wireless-dbus script
+# # Why bash can source the rest of the file but not that construct, just in that context, eludes me
+# if [[ -d "$HOOKS_DIR" ]]; then
+# while read h; do
+# source "$h"
+# done < <(find -L "$HOOKS_DIR/" -maxdepth 1 -type f -executable)
+# fi
+
+ # JP: this might be a more elegant way to process input line-at-a-time without a pipe, anyway
+ local h OLDIFS=$(line_input)
+ for h in $(find -L "$HOOKS_DIR/" -maxdepth 1 -type f -executable | sort); do
+ source "$h"
+ done
+ eval $OLDIFS
+}
+
+load_hooks
+
diff --git a/src/net-profiles b/src/net-profiles
index 67ab5e8..a4b964b 100755..100644
--- a/src/net-profiles
+++ b/src/net-profiles
@@ -2,17 +2,17 @@
. /etc/rc.conf
. /etc/rc.d/functions
+. /usr/lib/network/globals
case "$1" in
start)
if ! ck_daemon net-profiles; then
- echo "net-profiles has already been started. Try '/etc/rc.d/net-profiles restart'"
- exit
+ exit_stderr "net-profiles is already running: try \"/etc/rc.d/net-profiles restart\""
fi
# Ensure any device renaming has occurred as intended
for daemon in "${DAEMONS[@]}"; do
- if [ "$daemon" = "${daemon#!}" -a "$daemon" = "net-rename" ]; then
+ if [[ "$daemon" = "${daemon#!}" && "$daemon" = net-rename ]]; then
if ck_daemon net-rename; then
/etc/rc.d/net-rename start
fi
@@ -20,40 +20,65 @@ case "$1" in
done
# $NET env var is passed from the kernel boot line
- [ ! "$NETWORKS_MENU_TIMEOUT" ] && NETWORKS_MENU_TIMEOUT=5
+ # JP: is that true? or does $NET come from /etc/rc.conf?
+ [[ -z "$NETWORKS_MENU_TIMEOUT" ]] && NETWORKS_MENU_TIMEOUT=5
- if [[ "$NET" = "menu" ]]; then
- /usr/bin/netcfg-menu $NETWORKS_MENU_TIMEOUT
- elif [[ "$NET" ]]; then
- /usr/bin/netcfg2 -c $NET
- else
+ if [[ "$NET" = menu ]]; then
+ if /usr/bin/netcfg-menu "$NETWORKS_MENU_TIMEOUT"; then
+ mv "$STATE_DIR"/{menu,net-profiles} # JP: user may want to disconnect profile by calling net-profiles stop
+ add_daemon net-profiles
+ exit 0
+ fi
+ elif [[ -n "$NET" ]]; then
+ if /usr/bin/netcfg check-iface "$NET"; then
+ echo "$NET" > "$STATE_DIR/net-profiles" # JP: user may want to disconnect profile by calling net-profiles stop
+ add_daemon net-profiles
+ exit 0
+ fi
+ else
# No NET= passed at boot, go to NETWORKS=()
- for network in ${NETWORKS[@]}; do
- case $network in
+ for network in "${NETWORKS[@]}"; do
+ case "$network" in
menu) # Pull up menu of networks
- /usr/bin/netcfg-menu $NETWORKS_MENU_TIMEOUT
+ if /usr/bin/netcfg-menu "$NETWORKS_MENU_TIMEOUT"; then
+ mv "$STATE_DIR"/{menu,net-profiles} # JP: user may want to disconnect profile by calling net-profiles stop
+ add_daemon net-profiles
+ exit 0
+ fi
+ break # if netcfg-menu was called but failed: exit for loop
;;
*) # Either interface or profile
- if [ "$network" = "${network#!}" ]; then # otherwise profile
- /usr/bin/netcfg2 -c $network
+ if [[ "$network" = "${network#!}" ]]; then # otherwise profile
+ if /usr/bin/netcfg check-iface "$network"; then
+ echo "$network" > "$STATE_DIR/net-profiles" # JP: user may want to disconnect profile by calling net-profiles stop
+ add_daemon net-profiles
+ exit 0
+ fi
+ break # found an enabled profile but failed to bring it up: exit for loop
fi
;;
esac
done
- fi
+ fi
- add_daemon net-profiles
+ exit_err "No profile started." # JP: don't add_daemon unless we were successful (above)
;;
stop)
+ if ck_daemon net-profiles; then
+ exit_stderr "net-profiles not running"
+ fi
+
# shutdown any profiles started by netcfg (or from NET_PROFILES in rc.conf)
- /usr/bin/netcfg2 -a
+ # JP: only attempt to disconnect the profiles we're controlling
+ cat "${state_DIR}/net-profiles" 2>/dev/null | xargs -d'\n' /usr/bin/netcfg down # JP: use xargs in case any of the profile names contain spaces etc
+ rm -f "$STATE_DIR/net-profiles"
rm_daemon net-profiles
;;
restart)
- $0 stop; sleep 1; $0 start
+ "$0" stop; sleep 1; "$0" start
;;
*)
- echo "usage: $0 {start|stop|restart}"
+ exit_stderr "Usage: $0 {start|stop|restart}"
esac
# vim: set ts=4 et sw=4:
diff --git a/src/net-rename b/src/net-rename
index db2c461..1cff1c1 100755..100644
--- a/src/net-rename
+++ b/src/net-rename
@@ -2,12 +2,13 @@
. /etc/rc.conf
. /etc/rc.d/functions
+. /usr/lib/network/globals
case "$1" in
start)
- stat_busy "Renaming network devices"
+ report_try "Renaming network devices"
ifrename -p -t
- stat_done
+ report_success
add_daemon net-rename
;;
@@ -17,9 +18,10 @@ case "$1" in
/bin/true
;;
restart)
- $0 start
+ "$0" start
;;
*)
- echo "usage: $0 {start|stop|restart}"
+ exit_stderr "Usage: $0 {start|stop|restart}"
+ ;;
esac
# vim: set ts=4 et sw=4:
diff --git a/src/netcfg b/src/netcfg
index 3222d46..8f03ea2 100644
--- a/src/netcfg
+++ b/src/netcfg
@@ -4,7 +4,7 @@
. /etc/rc.d/functions
. /usr/lib/network/network
-NETCFG_VER=2.2.1
+NETCFG_VER=2.3.0b1
version()
{
@@ -18,45 +18,69 @@ usage()
echo " Start specified profile: netcfg profile "
echo " Other functions: netcfg argument profile"
echo "Arguments:"
+ echo " current Report currently running profiles"
echo "-a, all-down Take all active profiles down"
echo "-c, check-iface Do not start profile if interface is already up"
echo "-d, down Take specified profile down"
echo "-h, help This help message"
echo "-i, iface-down Take down profile active on specified interface"
+ echo "-l, list List all available profiles"
echo "-r, reconnect Disconnect and reconnect specified profile"
echo "-u, up Start specified profile"
echo "-v, version Output version information and exit"
echo " all-resume Resume previously suspended profiles and reconnect them"
echo " all-suspend Store a list of current running profiles and suspend them"
+ exit 1
}
-# TODO: Re-add ROOT check and rewrite with getopts from BashFAQ
+# TODO: rewrite with getopts from BashFAQ
-case $1 in
+case "$1" in
--version|-v|version)
- version;;
+ version
+ exit 0;;
--help|-h|help)
usage;;
+ list|-l)
+ echo "Available Profiles"
+ echo "------------------"
+ list_profiles
+ exit 0;;
+ current)
+ if [[ -d "$STATE_DIR/profiles/" ]]; then
+ ls "$STATE_DIR/profiles/"
+ exit 0
+ else
+ exit_err "No active profiles."
+ fi;;
+esac
+
+if [[ $(id -u) -gt 0 ]]; then
+ exit_stderr "This script should be run as root."
+fi
+
+case "$1" in
+
-c|check-iface|-u|up)
- CHECK="YES";
- profile_up $2;;
+ CHECK=YES
+ profile_up "$2";;
clean)
- rm /var/run/network/interfaces/* 2> /dev/null
- rm /var/run/network/profiles/* 2> /dev/null
- rm /var/run/network/suspend/* 2> /dev/null
- rm /var/run/network/last_profile 2> /dev/null
+ rm "$STATE_DIR/interfaces"/* 2> /dev/null
+ rm "$STATE_DIR/profiles"/* 2> /dev/null
+ rm "$STATE_DIR/suspend"/* 2> /dev/null
+ rm "$STATE_DIR/last_profile" 2> /dev/null
killall wpa_supplicant 2> /dev/null
killall dhcpcd 2> /dev/null
;;
-d|down)
- profile_down $2;;
+ profile_down "$2";;
-i|iface-down)
- interface_down $2;;
+ interface_down "$2";;
-a|all-down)
all_down;;
-r|reconnect)
- profile_down $2
- profile_up $2;;
+ profile_down "$2"
+ profile_up "$2";;
all-resume)
all_resume;;
all-suspend)
@@ -64,8 +88,8 @@ case $1 in
-*|--*)
usage;;
*)
- if [ -n "$1" ]; then
- profile_up $1
+ if [[ -n "$1" ]]; then
+ profile_up "$1"
else
usage
fi
diff --git a/src/netcfg-menu b/src/netcfg-menu
index 8c58edc..70acf5a 100755..100644
--- a/src/netcfg-menu
+++ b/src/netcfg-menu
@@ -4,57 +4,58 @@
. /etc/rc.d/functions
. /usr/lib/network/network
+# JP: we'll use $STATE_DIR/menu to record what profile is being connected in this way
+rm -f "$STATE_DIR/menu"
# Scan all profiles
i=0
-for prof in `find -L $PROFILE_DIR -maxdepth 1 -type f -printf "%f\n"|sort`; do
+while read prof; do
# if there is a profile called "main", Use as default
- [ "$prof" = "main" ] && DEFAULT=$prof
- unset DESCRIPTION
- . $PROFILE_DIR/$prof
- profiles[$i]=$prof
- i=$((i+1))
- profiles[$i]=$DESCRIPTION
- i=$((i+1))
-done
-
-if [ ${#profiles} -eq 0 ]; then
- echo "No profiles were found in $PROFILE_DIR"
- return 1
+ [[ "$prof" = main ]] && DEFAULT=main
+ unset DESCRIPTION # JP: we cant sandbox the sourced profiles, because we need to expose the profiles array
+ . "$PROFILE_DIR/$prof"
+ profiles[$i]="$prof"
+ let i++
+ profiles[$i]="$DESCRIPTION"
+ let i++
+done < <(list_profiles | sort) # JP: re-use list_profiles instead of duplicating it; avoid subshell we'd get by piping it to the while read...
+
+if [[ ${#profiles} -eq 0 ]]; then
+ exit_err "No profiles were found in $PROFILE_DIR"
fi
+[[ -n "$NETWORKS_MENU_DEFAULT" ]] && DEFAULT="$NETWORKS_MENU_DEFAULT"
# if no default yet, use the first entry
-[ "$NETWORKS_MENU_DEFAULT" ] && DEFAULT="$NETWORKS_MENU_DEFAULT"
-
-[ "$DEFAULT" = "" ] && DEFAULT=${profiles[0]}
-ANSWER=$(mktemp) || exit 1
+[[ -z "$DEFAULT" ]] && DEFAULT="${profiles[0]}"
+ANSWER=$(mktemp /tmp/menu.XXXXXXXX) || exit 1
# Set timeout
-if [ "$1" = "" ]; then
- TIMEOUT="0"
-else
- TIMEOUT="$1"
-fi
+TIMEOUT="${1:-0}" # JP: equivalent to the block that was here before
# Display Dialog
-dialog --timeout $TIMEOUT --default-item $DEFAULT \
+dialog --timeout "$TIMEOUT" --default-item "$DEFAULT" \
--menu "Select the network profile you wish to use" \
- 13 50 6 "${profiles[@]}" 2>$ANSWER
+ 13 50 6 "${profiles[@]}" 2> $ANSWER
ret=$?
case $ret in
1) ;; # Cancel - do nothing
255) # timeout - use default
- netcfg2 $DEFAULT
+ profile_up "$DEFAULT" # JP: use profile_up and catch $?
+ ret=$?
+ if [[ $ret -eq 0 ]]; then echo "$DEFAULT" > "$STATE_DIR/menu"; fi
;;
0) # User selection
- netcfg2 $(cat $ANSWER)
+ profile_up "$(cat $ANSWER)"
+ ret=$?
+ if [[ $ret -eq 0 ]]; then mv $ANSWER "$STATE_DIR/menu"; fi
;;
- *) # Shouldnt happen
- echo "Abnormal ret code from dialog: $ret"
+ *) # Shouldn't happen
+ echo "Abnormal ret code from dialog: $ret" >&2
;;
esac
-rm $ANSWER
+rm -f $ANSWER # JP: add -f
+exit $ret # JP: exit with caught $?
# vim: set ts=4 et sw=4:
diff --git a/src/network b/src/network
index b45caaa..2720caa 100644
--- a/src/network
+++ b/src/network
@@ -1,272 +1,391 @@
-### 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 " - $*"
-}
+# /usr/lib/network/network
+##
+##################################
+
+. /usr/lib/network/globals
-err() {
- printhl "$*"
-}
-### Profile loading
+### Profile listing and loading
##
+# 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"
+}
# load_profile profile
# source the profile
load_profile() {
- validate_profile $1 || return 1
- . $PROFILE_DIR/$1
+ validate_profile "$1" || return 1
+ . "$PROFILE_DIR/$1"
}
# validate_profile profile
# check whether profile exists and is usable
-validate_profile()
-{
+validate_profile() {
[[ -z "$1" ]] && return 1
- if [[ ! -f $PROFILE_DIR/$1 ]]; then
- err "Profile \"$1\" does not exist"
+ if [[ ! -f "$PROFILE_DIR/$1" ]]; then
+ report_err "Profile \"$1\" does not exist."
return 1
fi
- . $PROFILE_DIR/$1
+ . "$PROFILE_DIR/$1"
if [[ -z "$INTERFACE" ]]; then
- err "Profile missing an interface to configure"
+ report_err "Profile error: no 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"
+ if [[ ! -f "$CONN_DIR/$CONNECTION" ]]; then
+ report_err "Profile error: $CONNECTION is not a valid connection, check spelling or look at examples."
return 1
fi
}
-### Profile up/down
+### Profile suspend/resume
##
-# all_down
-# take all profiles down
-#
-all_down()
-{
- for prof in $(find ${STATE_DIR}/profiles/ -maxdepth 1 -type f -printf '%f\n'); do
- profile_down $prof
+# interface_suspend interface/all [call_profile_down? default=yes]
+# store a list of running profiles and take them down (unless $2 is no)
+interface_suspend() {
+ report_debug interface_suspend "$@"
+
+ [[ ! -d "$STATE_DIR" ]] && mkdir -p "$STATE_DIR"/{interfaces,profiles}
+ [[ ! -d "$STATE_DIR/suspend" ]] && mkdir "$STATE_DIR/suspend"
+
+ find "$STATE_DIR/profiles/" -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/profiles/$prof"
+ if [[ "$1" == all || "$1" == "$INTERFACE" ]]; then
+ report_notify "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
}
-
# 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
-
- for prof in $(find $STATE_DIR/profiles/ -maxdepth 1 -type f); do
- cp $prof $STATE_DIR/suspend/
- profile_down $(basename $prof)
- done
+all_suspend() {
+ interface_suspend all
}
+# all_resume
+# resume suspended interfaces
+# optional arguments: interfaces not to resume (e.g., because they're disabled)
+all_resume() {
+ report_debug all_resume "$@"
-# all_suspend
-# store a list of running profiles and take them down
-#
-all_resume()
-{
- for prof in $(find $STATE_DIR/suspend/ -maxdepth 1 -type f); do
- profile_up $(basename $prof)
- rm $prof
+ 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 [[ $# -eq 0 || ! " $* " =~ " $INTERFACE " ]]; then
+ report_notify "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
}
-# profile_up profile
+### Profile up/down
+##
+# profile_up profile [literal essid]
# put all profiles up
#
-profile_up()
-{
+profile_up() {
(
# Keep inside subshell so that options from one profile don't cross to others
- # exit 1 used as a subshell is effectively a new process
- [[ ! -d $STATE_DIR ]] && mkdir -p $STATE_DIR/{interfaces,profiles}
+ # exit 1 used in a subshell is effectively exiting a new process
+ [[ ! -d "$STATE_DIR" ]] && mkdir -p "$STATE_DIR"/{interfaces,profiles,suspend}
+
+ local status PROFILE="$1" # save PROFILE in a variable so that it's available to PREUP/POSTDOWN etc hooks
- load_profile $1 || exit 1
+ load_profile "$PROFILE" || exit 1
- check_profile $1 && err "$1 already connected" && exit 1
+ if check_profile "$PROFILE"; then
+ report_err "$PROFILE already connected."
+ exit 1
+ fi
# 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
+ if checkyesno "$NETWORKS_EXCLUSIVE" || checkyesno "$EXCLUSIVE"; then
all_down
fi
- stat_busy "$1 up"
+ report_try "$PROFILE up"
- if check_iface $INTERFACE; then
- if checkyesno $CHECK; then
- err_append "Interface $INTERFACE already in use"
- stat_fail && exit 1
- else
- interface_down $INTERFACE || exit 1
- load_profile $1
- fi
- fi
+ status=$(query_iface "$INTERFACE" "$CONNECTION")
+ report_debug "status reported to profile_up as: $status"
+
+ if [[ -n "$status" && "$status" != "$PROFILE" ]]; then
+ case "$status" in
+ disabled)
+ # interface radio-switch disabled
+ report_fail "INTERFACE $INTERFACE is disabled."
+ exit 1
+ ;;
+ external)
+ # interface being controlled externally
+ report_fail "INTERFACE $INTERFACE was configured by another application."
+ exit 1
+ ;;
+ *)
+ # report_fail if iface in use by another profile? (default no)
+ if checkyesno "$CHECK"; then
+ report_fail "INTERFACE $INTERFACE already in use by another profile."
+ exit 1
+ elif ! ( # use subshell so interface_down -> profile_down doesn't overwrite loaded profile
+ interface_down "$INTERFACE" "$CONNECTION" # supply current CONNECTION-type as hint
+ ); then
+ report_fail
+ exit 1
+ fi
+ ;;
+ esac
+ fi
- eval $PRE_UP || exit 1
+
+ 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
+ exit 1
+ fi
- if ! ${CONN_DIR}/${CONNECTION} up $1; then
- stat_fail
+ if ! "$CONN_DIR/$CONNECTION" up "$PROFILE" "$2"; then
+ report_debug profile_up "connect failed"
+ report_fail
+ # "$CONN_DIR/$CONNECTION" down "$PROFILE" "$2" # JP: should we do this to make sure?
exit 1
fi
- eval $POST_UP || exit 1
+ 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" "$2"
+ exit 1
+ fi
- set_profile up $1
- unset EXCLUSIVE
-
- stat_done
+ set_profile up "$PROFILE"
+ # unset EXCLUSIVE
+ report_success
); return $?
}
-
# profile_down profile
# take profile down
#
-profile_down()
-{
+profile_down() {
(
- [[ ! -d $STATE_DIR ]] && mkdir -p $STATE_DIR/{interfaces,profiles}
+ [[ ! -d "$STATE_DIR" ]] && mkdir -p "$STATE_DIR"/{interfaces,profiles,suspend}
- load_profile $1 || exit 1
+ local status PROFILE="$1" # save PROFILE in a variable so that it's available to PREUP/POSTDOWN etc hooks
+
+ load_profile "$PROFILE" || exit 1
+
+ status=$(query_iface "$INTERFACE" "$CONNECTION")
+ report_debug "status reported to profile_down as: $status"
- if ! check_profile $1; then
- err "Profile not connected"
- exit 1
- fi
+ if [[ "$status" != "$PROFILE" ]]; then
+ # if interface not available to be controlled by netcfg, then
+ # any profiles will have been removed by check_iface
+ # else another profile is running
+ report_err "Profile wasn't connected."
+ exit 1
+ fi
- stat_busy "$1 down"
- if [[ "$(get_iface_prof $INTERFACE)" == "external" ]]; then
- err_append "$interface was connected by another application"
- stat_fail
- exit 1
- fi
+ report_try "$PROFILE down"
+# JP: the following will have already been caught by the block above...
+# if [[ "$status" == external ]]; then
+# report_fail "Interface $INTERFACE was configured by another application."
+# exit 1
+# fi
- eval $PRE_DOWN || exit 1
+ 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 $1; then
- stat_fail
+ if ! "$CONN_DIR/$CONNECTION" down "$PROFILE" "$2"; then
+ report_debug profile_up "disconnect failed"
+ report_fail
exit 1
fi
- eval $POST_DOWN || exit 1
+ if ! ( eval $POST_DOWN ); then # JP: sandbox the eval
+ report_debug profile_down "POST_DOWN failed"
+ report_fail
+ exit 1
+ fi
- set_profile down $1
- stat_done
+ set_profile down "$PROFILE"
+ report_success
); return $?
}
-
-# 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
+# all_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
+}
+# interface_down interface
+# take interface down
+#
+interface_down() {
+ local status=$(query_iface "$@") # we may not be hinting what CONNECTION type to use, e.g. when called from /usr/bin/netcfg
+ case "$status" in
+ none|disabled) return 0;;
+ external) return 1;;
+ *) profile_down "$status";;
+ esac
}
-quirk() {
-inarray $1 ${QUIRKS[@]}
-return $?
+
+### Status setting functions
+##
+# set_profile up/down profile
+# Set profile state, either up or down
+#
+set_profile() {
+ if [[ "$1" == up ]]; then
+ ( # subshell creates sandbox for sourced variables
+ . "$PROFILE_DIR/$2"
+ cp "$PROFILE_DIR/$2" "$STATE_DIR/profiles/"
+ echo "$2" > "$STATE_DIR/last_profile"
+ set_iface up "$INTERFACE" "$2"
+ )
+ elif [[ "$1" == down && -f "$STATE_DIR/profiles/$2" ]]; then
+ ( # subshell
+ . "$STATE_DIR/profiles/$2"
+ rm "$STATE_DIR/profiles/$2"
+ set_iface down "$INTERFACE" "$2"
+ )
+ fi
}
-# interface_down interface
-# take interface down
+# set_iface up/down interface [profile/disabled/external]
+# Set interface status to up/down (really up means "unavailable" (may be down & disabled) and down means "available"
+# optionally link it to a profile.
#
-interface_down()
-{
- local prof=$(get_iface_prof $1)
- profile_down $prof
- return $?
+set_iface() {
+ local PROFILE="${3:-external}" # JP: this is equivalent to the two-line block that was here before
+ if [[ "$1" == up ]]; then
+ echo "PROFILE=$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
}
-### Query functions
+
+
+### Checking/querying 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
+ [[ -f "$STATE_DIR/interfaces/$1" ]] && return 0
+ return 1
}
+############################################################################
+# Note: get_iface_prof left in for compatibility with any external code that calls it
+# but in this codebase, it's superceded by query_iface
# 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
+ 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
+# Return 0 if profile registered as being up
+# Return 1 if profile not registered
#
check_profile() {
- [[ -f $STATE_DIR/profiles/$1 ]] && return 0
+ [[ -f "$STATE_DIR/profiles/$1" && ! -f "$STATE_DIR/suspend/$1" ]] && return 0
return 1
-}
+}
+
+
+# query_iface interface [connection]
+# Return 0 if interface up or otherwise unavailable for connecting
+# Return 1 if interface down (and so free to be connected)
+# echoes which profile controls the interface (or "external" or "disabled")
+
+query_iface() {
+
+ local INTERFACE="$1" PROFILE connection="$2"
+
+ if [[ -z "$connection" ]]; then # JP: the difficulty with factoring this code into the CONNECTION routines
+ # is that we sometimes want to query/control the interface without knowing what CONNECTION type it instantiates
+ # so we supply the CONNECTION type as a hint ($2) when possible
+ # and when CONNECTION wasn't hinted, we default to wireless-dbus if iface verifies as wireless, else ethernet-iproute
+ if "$CONN_DIR/wireless-dbus" verify "$INTERFACE"; then
+ connection=wireless-dbus
+ else
+ connection=ethernet-iproute
+ fi
+ fi
+
+ if ! "$CONN_DIR/$connection" query "$INTERFACE" active; then
+ # interface is not up
+ if [[ -f "$STATE_DIR/interfaces/$INTERFACE" ]]; then # but the interface thinks it's running a profile...
+ . "$STATE_DIR/interfaces/$INTERFACE" # these files should only contain a PROFILE=... statement
+ if [[ "$PROFILE" == disabled ]]; then
+ echo "disabled"
+ return 0
+ elif [[ "$PROFILE" != external ]]; then
+ report_warn "INTERFACE $INTERFACE no longer being controlled by $PROFILE"
+ set_profile down "$PROFILE"
+ PROFILE=
+ fi
+ set_iface down "$INTERFACE" # update iface status: no longer profile/external
+ fi
+ echo "$PROFILE"
+ return 1
+ else
+ "$CONN_DIR/$connection" query "$INTERFACE" profile
+ return $?
+ fi
-### 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
+
+### Utility functions
+##
+# Check if variable is a member of an array
+inarray() {
+ local item search="$1"
+ shift
+ for item; do
+ if [[ "$item" == "$search" ]]; then
+ return 0
+ fi
+ done
+ return 1
}
+quirk() {
+ inarray "$1" "${QUIRKS[@]}"
+}
### From FreeBSD's /etc/rc.subr
##
@@ -274,11 +393,10 @@ set_iface() {
# 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}
+checkyesno() {
+ local _value="$1"
#debug "checkyesno: $1 is set to $_value."
- case $_value in
+ case "$_value" in
# "yes", "true", "on", or "1"
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
@@ -295,3 +413,5 @@ checkyesno()
;;
esac
}
+
+
diff --git a/src/wireless b/src/wireless
index 62454e4..d27c43b 100644
--- a/src/wireless
+++ b/src/wireless
@@ -1,62 +1,141 @@
+##################################
+##
+# /usr/lib/network/wireless_utils
+##
+##################################
+
# Uses wireless_tools, to check for association to a network.
# wep_check interface [timeout]
-wep_check()
-{
- INTERFACE=$1; TIMEOUT=$2
+wep_check() {
+ local INTERFACE="$1" TIMEOUT="${2:-15}" timeout=0 bssid
- [[ -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
+ while [[ "$timeout" -lt "$TIMEOUT" ]]; do
+ bssid=$(iwgetid "$INTERFACE" -ra)
+ [[ -n "$bssid" && "$bssid" != "00:00:00:00:00:00" ]] && return 0
sleep 1
let timeout++
done
- err_append "Wireless association failed"
+ report_fail "Couldn't associate with wireless network."
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
+# find_essid interface essid connection (we treat ESSID as regexp when CONNECTION=wireless-dbus)
+find_essid() {
+ local INTERFACE="$1" ESSID="$2" CONNECTION="$3" RETRIES=20 try=0 res scanned
+ while [[ "$try" -lt "$RETRIES" ]]; do
+ sleep 0.5
+ let try++
+ if [[ "$CONNECTION" == wireless-dbus ]]; then
+ # JP: ESSID is a regexp
+ found=$(
+ res=$(iwlist "$INTERFACE" scan 2>/dev/null)
+ [[ -z "$res" ]] && exit 1
+ # if results were non-null, process them and exit 0
+ echo "$res" | sed -nr 's/^\s+ESSID:"([^"]*)"$/\1/p' | egrep -xm1 "$ESSID"
+ )
+ else
+ found=$(
+ res=$(iwlist "$INTERFACE" scan 2>/dev/null)
+ [[ -z "$res" ]] && exit 1
+ # if results were non-null, process them and exit 0
+ echo "$res" | sed -nr 's/^\s+ESSID:"([^"]*)"$/\1/p' | fgrep -xm1 "$ESSID"
+ )
+ fi && {
+ scanned=1
+ report_debug find_essid "\"$found\""
+ # we only bother with at most 5 successful scans
+ if (( try < RETRIES-4 )); then try=$((RETRIES-4)); fi
+ }
+ if [[ -n "$found" ]]; then
+ echo "$found" # JP: echo literal ESSID
return 0 # network found
fi
- sleep 1
+ done
+ if [[ "$scanned" -ne 1 ]]; then
+ report_debug find_essid "unable to scan"
+ fi
+ return 1
+}
+
+# Check if a particular network is within range
+# find_ap interface ap
+find_ap() {
+ local INTERFACE="$1" ap=$(echo "$2" | tr 'abcdef' 'ABCDEF') RETRIES=20 try=0 res scanned
+ while [[ "$try" -lt "$RETRIES" ]]; do
+ sleep 0.5
let try++
+ found=$(
+ res=$(iwlist "$INTERFACE" scan 2> /dev/null)
+ [[ -z "$res" ]] && exit 1
+ # if results were non-null, process them and exit 0
+ echo "$res" | sed -nr '/^\s+Cell .. - Address: ([[:xdigit:]:]+)$/ { s//\1/; N; s/(.*)\n\s+ESSID:"([^"]*)"$/\1\t\2/p }' \
+ | egrep -m1 "^$ap\t"
+ ) && {
+ scanned=1
+ report_debug find_ap "\"$found\""
+ # we only bother with at most 5 successful scans
+ if (( try < RETRIES-4 )); then try=$((RETRIES-4)); fi
+ }
+ if [[ -n "$found" ]]; then
+ echo "$found" | cut -f2 # JP: echo literal ESSID
+ return 0
+ fi
done
+ if [[ "$scanned" -ne 1 ]]; then
+ report_debug find_ap "unable to scan"
+ fi
return 1
}
-# Return a filename containing a list of network ESSID's found.
+# Return a filename containing a list of network APs and ESSIDs found (sorted by decreasing signal strength)
# list_networks interface
-list_networks()
-{
+list_networks() {
+ local INTERFACE="$1" essids try=0 RETRIES=20 res scanned
# 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
-
+ [[ -z "$INTERFACE" ]] && return 1
+ essids=$(mktemp /tmp/essid.XXXXXXXX)
+
+# # James suggested using this, but it requires wpa_supplicant to be running
+# wpa_cli -i "$INTERFACE" scan 2>/dev/null || { rm $essids; return 1; }
+# sleep 0.5
+# wpa_cli -i "$INTERFACE" scan_results > $essids 2>/dev/null || { rm $essids; return 1; }
+
+ {
+ while [[ "$try" -lt "$RETRIES" ]]; do
+ sleep 0.5
+ let try++
+ # iwlist "$INTERFACE" scan 2> /dev/null | fgrep "ESSID" | sed 's/.*ESSID:"\([^"]\+\)".*/\1/' > $essids
+ res=$(iwlist "$INTERFACE" scan 2> /dev/null)
+ [[ -z "$res" ]] && continue
+ scanned=1
+ # we only bother with at most 5 successful scans
+ if (( try < RETRIES-4 )); then try=$((RETRIES-4)); fi
+ echo "$res" | sed -r '1d; $ { H; ba }; 2 { h; d }; /^\s+Cell /! { H; d }; :a; x; s/\n/ /g'
+ done
+ } \
+ | sed -rne 's/.*Address: ([[:xdigit:]:]+).*ESSID:"([^"]*)".*Quality=([0-9]+).*/\1\t\3\t\1\t\2/p' \
+ -e 's/.*Address: ([[:xdigit:]:]+).*Quality=([0-9]+).*ESSID:"([^"]*)".*/\1\t\2\t\1\t\3/p' \
+ | sort -k1 -k2nr | uniq -w17 \
+ | sort -k2nr \
+ | cut -f3- > "$essids"
+ # 1. make tab-separated fields: ap, signal-strength, ap, essid (easiest way to use uniq and cut here requires ap twice)
+ # 2. eliminate duplicate aps (keeping strongest signal)
+ # 3. sort entire list by decreasing signal
+ # 4. then return tab-separated fields: ap, essid (ap needs to come first so that read can assume format is <word> <rest of line>)
+#
# File of 0 length, ie. no ssid's.
if [[ ! -s $essids ]]; then
+ rm $essids
return 1
fi
echo $essids
return 0
}
+
+
# vim: set ts=4 et sw=4 ft=sh: