From 27c11787d7c58b02f12d7afd476ea66abfeecaaf Mon Sep 17 00:00:00 2001 From: Jouke Witteveen Date: Fri, 28 Dec 2012 02:43:13 +0100 Subject: Forking netcfg to netctl (2/2) This commit contains the refactoring and rewriting of code. --- contrib/bash-completion | 63 ++-- docs/examples/bonding | 15 +- docs/examples/bridge | 14 +- docs/examples/ethernet-dhcp | 12 +- docs/examples/ethernet-iproute | 10 +- docs/examples/ethernet-static | 22 +- docs/examples/pppoe | 34 +- docs/examples/tunnel-he-ipv6 | 19 +- docs/examples/tuntap | 15 +- docs/examples/vlan-dhcp | 11 +- docs/examples/vlan-static | 22 +- docs/examples/wireless-open | 10 +- docs/examples/wireless-wep | 17 +- docs/examples/wireless-wep-string-key | 12 +- docs/examples/wireless-wpa | 16 +- docs/examples/wireless-wpa-config | 12 +- docs/examples/wireless-wpa-configsection | 31 +- docs/examples/wireless-wpa-static | 18 +- docs/netctl.1.txt | 141 ++++---- docs/netctl.profile.5.txt | 599 +++++++++++++++++-------------- docs/netctl.special.7.txt | 55 +++ services/netctl-auto@.service | 8 +- services/netctl-ifplugd@.service | 7 +- services/netctl.service | 7 +- services/netctl@.service | 9 +- src/ifplugd.action | 29 +- src/lib/8021x | 341 ++++++++---------- src/lib/auto.action | 85 ++--- src/lib/connections/bond | 41 +-- src/lib/connections/bridge | 53 ++- src/lib/connections/ethernet | 276 ++------------ src/lib/connections/pppoe | 55 ++- src/lib/connections/tunnel | 34 +- src/lib/connections/tuntap | 32 +- src/lib/connections/vlan | 34 +- src/lib/connections/wireless | 137 +++---- src/lib/globals | 159 ++++---- src/lib/ip | 215 +++++++++++ src/lib/network | 419 ++++----------------- src/lib/rfkill | 85 +++-- src/netctl | 232 +++++++----- src/netctl-auto | 137 ++++--- src/wifi-menu | 76 ++-- 43 files changed, 1674 insertions(+), 1945 deletions(-) create mode 100644 docs/netctl.special.7.txt create mode 100644 src/lib/ip mode change 100644 => 100755 src/lib/network diff --git a/contrib/bash-completion b/contrib/bash-completion index dab52ea..b47d92b 100644 --- a/contrib/bash-completion +++ b/contrib/bash-completion @@ -1,49 +1,30 @@ -# netcfg completion +# netctl completion -_netcfg () +_netctl() { - local cur prev opts lopts cmds prfls + local cur prev prof - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" + cur=${COMP_WORDS[COMP_CWORD]} + prev=${COMP_WORDS[COMP_CWORD-1]} + prof=$(find -L /etc/network.d -maxdepth 1 -type f -not -name '.*' -not -name '*~' -not -name '*.conf' -not -name '*.service' -printf "%f\n") - opts="-l -c -u -r -R -d -D -a -v -h" - lopts="--help --version" - cmds="list current check-iface up reconnect iface-recon down iface-down all-down all-suspend" - prfls="$(find -L /etc/network.d/ -maxdepth 1 -type f -not -name '*~' -not -name '*.conf' -not -name '.*' -printf '%f\n')" - - case "${prev}" in - -R|iface-recon|-D|iface-down) - COMPREPLY=( $( compgen -W "$(ls /run/network/interfaces/)" -- $cur ) ) - return 0 - ;; - -r|reconnect|-d|down) - COMPREPLY=( $( compgen -W "$(ls /run/network/profiles/)" -- $cur ) ) - return 0 - ;; - -c|check-iface|-u|up) - COMPREPLY=( $( compgen -W "${prfls}" -- $cur ) ) - return 0 - ;; - esac - - case "${cur}" in - --*) - COMPREPLY=( $( compgen -W "${lopts}" -- $cur ) ) - return 0 - ;; - -*) - COMPREPLY=( $( compgen -W "${opts} ${lopts}" -- $cur ) ) - return 0 - ;; - *) - ((COMP_CWORD == 1)) && \ - COMPREPLY=( $( compgen -W "${opts} ${lopts} ${cmds} ${prfls}" -- $cur ) ) + case $COMP_CWORD in + 1) + COMPREPLY=( $(compgen -W "--help --version list store restore stop-all start stop restart switch-to status enable disable reenable" -- $cur) ) + ;; + 2) + case $prev in + start|stop|restart|switch-to|status|enable|disable|reenable) + mapfile -t COMPREPLY < <(IFS=$'\n'; compgen -W "$prof" -- $cur) ;; + esac + ;; + *) + COMPREPLY=() + ;; esac +} && +complete -F _netctl netctl - return 0 -} -complete -F _netcfg netcfg +# ex: ts=4 sw=4 et filetype=sh diff --git a/docs/examples/bonding b/docs/examples/bonding index e8d4a7f..090892d 100644 --- a/docs/examples/bonding +++ b/docs/examples/bonding @@ -1,9 +1,6 @@ -CONNECTION="bond" -DESCRIPTION='Bond Interface' -INTERFACE='bond0' -IP='static' -ADDR="10.0.0.1" -NETMASK="255.0.0.0" -SLAVE_INTERFACES=("eth0" "eth2") -SKIPNOCARRIER="yes" - +Description='Bond Interface' +Interface='bond0' +Connection=bond +BindsToInterfaces=(eth0 eth2) +IP=static +Address="10.0.0.1/8" diff --git a/docs/examples/bridge b/docs/examples/bridge index bd422fa..f8d2915 100644 --- a/docs/examples/bridge +++ b/docs/examples/bridge @@ -1,9 +1,9 @@ -INTERFACE="br0" -CONNECTION="bridge" -DESCRIPTION="Example Bridge connection" -BRIDGE_INTERFACES="eth0 eth1 tap0" -IP="dhcp" +Description="Example Bridge connection" +Interface=br0 +Connection=bridge +BindsToInterfaces=(eth0 eth1 tap0) +IP=dhcp ## sets forward delay time -#FWD_DELAY=0 +#FWDDelay=0 ## sets max age of hello message -#MAX_AGE=10 +#MaxAge=10 diff --git a/docs/examples/ethernet-dhcp b/docs/examples/ethernet-dhcp index 0719632..5866238 100644 --- a/docs/examples/ethernet-dhcp +++ b/docs/examples/ethernet-dhcp @@ -1,9 +1,9 @@ -CONNECTION='ethernet' -DESCRIPTION='A basic dhcp ethernet connection using iproute' -INTERFACE='eth0' -IP='dhcp' +Description='A basic dhcp ethernet connection using iproute' +Interface=eth0 +Connection=ethernet +IP=dhcp ## for DHCPv6 -#IP6='dhcp' +#IP6=dhcp ## for IPv6 autoconfiguration -#IP6='stateless' +#IP6=stateless diff --git a/docs/examples/ethernet-iproute b/docs/examples/ethernet-iproute index d22dd17..972f5bb 100644 --- a/docs/examples/ethernet-iproute +++ b/docs/examples/ethernet-iproute @@ -1,7 +1,7 @@ -CONNECTION='ethernet' -DESCRIPTION='A more versatile static ethernet connection using iproute' -INTERFACE='eth0' -IP='static' +Description='A more versatile static ethernet connection using iproute' +Interface=eth0 +Connection=ethernet +IP=static # Any valid iproute command can be placed in this array -IPCFG=('addr add dev eth0 192.168.1.23/24 brd +' 'route add default via 192.168.1.1') +IPCustom=('addr add dev eth0 192.168.1.23/24 brd +' 'route add default via 192.168.1.1') DNS=('192.168.1.1') diff --git a/docs/examples/ethernet-static b/docs/examples/ethernet-static index ea88bde..0d6b5a2 100644 --- a/docs/examples/ethernet-static +++ b/docs/examples/ethernet-static @@ -1,17 +1,17 @@ -CONNECTION='ethernet' -DESCRIPTION='A basic static ethernet connection using iproute' -INTERFACE='eth0' -IP='static' -ADDR='192.168.1.23' -#ROUTES=('192.168.0.0/24 via 192.168.1.2') -GATEWAY='192.168.1.1' +Description='A basic static ethernet connection using iproute' +Interface=eth0 +Connection=ethernet +IP=static +Address='192.168.1.23' +#Routes=('192.168.0.0/24 via 192.168.1.2') +Gateway='192.168.1.1' DNS=('192.168.1.1') ## For IPv6 autoconfiguration #IP6=stateless ## For IPv6 static address configuration -#IP6='static' -#ADDR6=('1234:5678:9abc:def::1/64' '1234:3456::123/96') -#ROUTES6=('abcd::1234') -#GATEWAY6='1234:0:123::abcd' +#IP6=static +#Address6=('1234:5678:9abc:def::1/64' '1234:3456::123/96') +#Routes6=('abcd::1234') +#Gateway6='1234:0:123::abcd' diff --git a/docs/examples/pppoe b/docs/examples/pppoe index c11d125..74cc9ff 100644 --- a/docs/examples/pppoe +++ b/docs/examples/pppoe @@ -1,33 +1,33 @@ -CONNECTION='pppoe' -DESCRIPTION='Example PPPoE connection' -INTERFACE='eth0' -USER='example@yourprovider.com' -PASSWORD='very secret' +Description='Example PPPoE connection' +Interface=eth0 +Connection=pppoe +User='example@yourprovider.com' +Password='very secret' # Always keep a connection established -CONNECTION_MODE='persist' +ConnectionMode='persist' # Establish connection on demand -#CONNECTION_MODE='demand' -#IDLE_TIMEOUT=300 +#ConnectionMode='demand' +#IdleTimeout=300 # Use default route provided by the peer (default: true) -#DEFAULTROUTE=1 +#DefaultRoute=true # Use DNS provided by the peer (default: true) -#USEPEERDNS=1 +#UsePeerDNS=true # Override default LCP parameters from /etc/ppp/options -#LCP_ECHO_INTERVAL=15 -#LCP_ECHO_FAILURE=10 +#LCPEchoInterval=15 +#LCPEchoFailure=10 # PPPoE options - experts only # # PPPoE service name -#PPPOE_SERVICE='' +#PPPoEService='' # PPPoE access concentrator name -#PPPOE_AC='' +#PPPoEAC='' # Attach to existing session (sessid:macaddr) -#PPPOE_SESSION='' +#PPPoESession='' # Only connect to specified MAC address -#PPPOE_MAC='' +#PPPoEMAC='' # Enable IPv6 support -#PPPOE_IP6='yes' +#PPPoEIP6=yes diff --git a/docs/examples/tunnel-he-ipv6 b/docs/examples/tunnel-he-ipv6 index 81b18ad..2a19406 100644 --- a/docs/examples/tunnel-he-ipv6 +++ b/docs/examples/tunnel-he-ipv6 @@ -1,11 +1,10 @@ -CONNECTION='tunnel' -DESCRIPTION='An example ipv6 tunnel with Hurricane Electric' +Description='An example ipv6 tunnel with Hurricane Electric' +Interface=he-ipv6 +Connection=tunnel +Mode='sit' +Remote='216.66.80.26' +#Local='172.16.0.1' -INTERFACE='he-ipv6' -MODE='sit' -REMOTE='216.66.80.26' -#LOCAL='172.16.0.1' - -IP6='static' -ADDR6='2001:470:1f08:d87::2/64' -ROUTES6=('::/0') +IP6=static +Address6='2001:470:1f08:d87::2/64' +Routes6=('::/0') diff --git a/docs/examples/tuntap b/docs/examples/tuntap index 1563520..8ce78ac 100644 --- a/docs/examples/tuntap +++ b/docs/examples/tuntap @@ -1,11 +1,10 @@ -INTERFACE='tun0' -CONNECTION='tuntap' -MODE='tun' -USER='nobody' -GROUP='nobody' +Interface=tun0 +Connection=tuntap +Mode='tun' +User='nobody' +Group='nobody' ## Example IP configuration -#IP='static' -#SKIPNOCARRIER='yes' -#ADDR='10.10.1.2' +#IP=static +#Address='10.10.1.2' diff --git a/docs/examples/vlan-dhcp b/docs/examples/vlan-dhcp index 8c6ad23..c412618 100644 --- a/docs/examples/vlan-dhcp +++ b/docs/examples/vlan-dhcp @@ -1,5 +1,6 @@ -INTERFACE="eth0.55" -VLAN_PHYS_DEV="eth0" -VLAN_ID="55" -CONNECTION="vlan" -IP="dhcp" +Interface=eth0.55 +Connection=vlan +# The variable name is plural, but needs precisely one interface +BindsToInterfaces=eth0 +VLANID=55 +IP=dhcp diff --git a/docs/examples/vlan-static b/docs/examples/vlan-static index b7b9753..f9e1ae5 100644 --- a/docs/examples/vlan-static +++ b/docs/examples/vlan-static @@ -1,12 +1,12 @@ -INTERFACE="eth0.11" -VLAN_PHYS_DEV="eth0" -VLAN_ID="11" -CONNECTION="vlan" -IP="static" -ADDR="192.168.0.100" -NETMASK="255.255.255.0" -GATEWAY="192.168.0.1" +Interface=eth0.11 +Connection=vlan +# The variable name is plural, but needs precisely one interface +BindsToInterfaces=eth0 +VLANID=11 +IP=static +Address="192.168.0.100/24" +Gateway="192.168.0.1" DNS=("192.168.0.2") -HOSTNAME="myhost" -DOMAIN="mydomain.com" -SEARCH="mydomain.com" +Hostname="myhost" +DNSDomain="mydomain.com" +DNSSearch="mydomain.com" diff --git a/docs/examples/wireless-open b/docs/examples/wireless-open index db8d6ef..f4bf9bb 100644 --- a/docs/examples/wireless-open +++ b/docs/examples/wireless-open @@ -1,8 +1,8 @@ -CONNECTION='wireless' -DESCRIPTION='A simple opened wireless connection' -INTERFACE='wlan0' -SECURITY='none' +Description='A simple opened wireless connection' +Interface=wlan0 +Connection=wireless +Security=none ESSID='MyNetwork' IP='dhcp' # Uncomment this if your ssid is hidden -#HIDDEN=yes +#Hidden=yes diff --git a/docs/examples/wireless-wep b/docs/examples/wireless-wep index b16f65e..479b8a3 100644 --- a/docs/examples/wireless-wep +++ b/docs/examples/wireless-wep @@ -1,11 +1,12 @@ -CONNECTION='wireless' -DESCRIPTION='A simple WEP encrypted wireless connection' -INTERFACE='wlan0' -SECURITY='wep' +Description='A simple WEP encrypted wireless connection' +Interface=wlan0 +Connection=wireless +Security=wep ESSID='MyNetwork' -KEY='1234567890' +# Prepend hexadecimal keys with \" +Key=\"1234567890abcdef IP='dhcp' # Uncomment this if your ssid is hidden -#HIDDEN=yes -## Uncomment if you are using an ad-hoc connection -#ADHOC=1 +#Hidden=yes +# Uncomment if you are using an ad-hoc connection +#AdHoc=yes diff --git a/docs/examples/wireless-wep-string-key b/docs/examples/wireless-wep-string-key index ebc4b0a..12483c0 100644 --- a/docs/examples/wireless-wep-string-key +++ b/docs/examples/wireless-wep-string-key @@ -1,9 +1,9 @@ -CONNECTION='wireless' -DESCRIPTION='A simple WEP encrypted wireless connection' -INTERFACE='wlan0' -SECURITY='wep' +Description='A simple WEP encrypted wireless connection' +Interface=wlan0 +Connection=wireless +Security=wep ESSID='MyNetwork' -KEY='s:Wireless Key' +Key='Wireless Key' IP='dhcp' # Uncomment this if your ssid is hidden -#HIDDEN=yes +#Hidden=yes diff --git a/docs/examples/wireless-wpa b/docs/examples/wireless-wpa index e2511f3..16d17e9 100644 --- a/docs/examples/wireless-wpa +++ b/docs/examples/wireless-wpa @@ -1,14 +1,14 @@ -CONNECTION='wireless' -DESCRIPTION='A simple WPA encrypted wireless connection' -INTERFACE='wlan0' -SECURITY='wpa' +Description='A simple WPA encrypted wireless connection' +Interface=wlan0 +Connection=wireless +Security=wpa ESSID='MyNetwork' -## Uncomment if the supplied ESSID is hexadecimal -#ESSID_TYPE='hex' -KEY='WirelessKey' +# Prepend hexadecimal keys with \" +# If your key starts with ", write it as '""""' +Key='WirelessKey' IP='dhcp' # Uncomment this if your ssid is hidden -#HIDDEN=yes +#Hidden=yes diff --git a/docs/examples/wireless-wpa-config b/docs/examples/wireless-wpa-config index 955d845..e598dce 100644 --- a/docs/examples/wireless-wpa-config +++ b/docs/examples/wireless-wpa-config @@ -1,8 +1,8 @@ -CONNECTION='wireless' -DESCRIPTION='A wpa_supplicant configuration based wireless connection' -INTERFACE='wlan0' -SECURITY='wpa-config' -WPA_CONF='/etc/wpa_supplicant.conf' +Description='A wpa_supplicant configuration based wireless connection' +Interface=wlan0 +Connection=wireless +Security=wpa-config +WPAConfigFile='/etc/wpa_supplicant.conf' IP='dhcp' # Uncomment this if your ssid is hidden -#HIDDEN=yes +#Hidden=yes diff --git a/docs/examples/wireless-wpa-configsection b/docs/examples/wireless-wpa-configsection index d6cc8ad..dde9ccd 100644 --- a/docs/examples/wireless-wpa-configsection +++ b/docs/examples/wireless-wpa-configsection @@ -1,17 +1,18 @@ -CONNECTION='wireless' -INTERFACE=wlan0 -SECURITY='wpa-configsection' +Interface=wlan0 +Connection=wireless +Security=wpa-configsection # Uncomment this if your ssid is hidden -#HIDDEN=yes +#Hidden=yes IP='dhcp' -CONFIGSECTION=' - ssid="University" - key_mgmt=WPA-EAP - eap=TTLS - group=TKIP - pairwise=TKIP CCMP - anonymous_identity="anonymous" - identity="myusername" - password="mypassword" - priority=1 - phase2="auth=PAP"' +WPAConfigSection=( + 'ssid="University"' + 'key_mgmt=WPA-EAP' + 'eap=TTLS' + 'group=TKIP' + 'pairwise=TKIP CCMP' + 'anonymous_identity="anonymous"' + 'identity="myusername"' + 'password="mypassword"' + 'priority=1' + 'phase2="auth=PAP"' +) diff --git a/docs/examples/wireless-wpa-static b/docs/examples/wireless-wpa-static index 25da514..66b6970 100644 --- a/docs/examples/wireless-wpa-static +++ b/docs/examples/wireless-wpa-static @@ -1,12 +1,12 @@ -CONNECTION='wireless' -DESCRIPTION='A simple WPA encrypted wireless connection using a static IP' -INTERFACE='wlan0' -SECURITY='wpa' +Description='A simple WPA encrypted wireless connection using a static IP' +Interface=wlan0 +Connection=wireless +Security=wpa ESSID='MyNetwork' -KEY='WirelessKey' -IP='static' # Any other CONNECTION='ethernet' options may be used. -ADDR='192.168.1.23' -GATEWAY='192.168.1.1' +Key='WirelessKey' +IP=static +Address='192.168.1.23' +Gateway='192.168.1.1' DNS=('192.168.1.1') # Uncomment this if your ssid is hidden -#HIDDEN=yes +#Hidden=yes diff --git a/docs/netctl.1.txt b/docs/netctl.1.txt index 54fbd78..06638a2 100644 --- a/docs/netctl.1.txt +++ b/docs/netctl.1.txt @@ -1,91 +1,92 @@ -NETCFG(8) +NETCTL(1) ========= NAME ---- -netcfg - start/stop/control network profiles +netctl - Control the netctl network profile manager SYNOPSIS -------- -netcfg [_options_] +*netctl* {*COMMAND*} [+PROFILE+] -netcfg *profile* +*netctl* [--help | --version] DESCRIPTION ----------- -*netcfg* is used to configure and manage network connections via -profiles. It has pluggable support for a range of connection types, such -as wireless, ethernet, ppp. It is also capable of starting/stopping many -to one connections, that is, multiple connections within the same -profile, optionally with bonding. - -It may be run at boot, by enabling the 'netcfg' systemd service, or, on -legacy systems, by adding 'net-profiles' to +DAEMONS+ in '/etc/rc.conf'. -After boot time, it may be used to start profiles, simply by passing only -the profile name. - -When run without options, `netcfg profile` is equivalent to `netcfg -u -profile`. +*netctl* may be used to introspect and control the state of the systemd +services for the network profile manager. OPTIONS ------- -*-l, list*:: - List all available profiles -*current*:: - Report currently running profiles -*-c, check-iface* _profile_:: - Start the specified profile, only if it's interface is not currently up. -*-u, up* _profile_:: - Start the specified profile -*-r, reconnect* _profile_:: - Disconnect and reconnect the specified profile -*-R, iface-recon* _interface_:: - Reconnect profile active on specified interface -*-d, down* _profile_:: - Stop the specified profile -*-D, iface-down* _interface_:: - Stop the profile up on the specified interface. -*-a, all-down*:: - Stop all connected profiles -*all-suspend*:: - Suspend and store the name of all active profiles. -*all-resume*:: - Reconnect any profiles that have been suspended. -*-v, --version*:: - Display version information and exit -*-h, --help*:: - Display help message and exit - - -CONFIGURATION FILES -------------------- -'/etc/conf.d/netcfg':: - Parameters for startup. -'/etc/network.d/':: - User-defined profiles. - - -FILES ------ -'/usr/lib/network/connections/':: - Currently installed network profile types. -'/etc/network.d/examples/':: - Example profiles. -'/usr/share/doc/netcfg/contrib/':: - Inspirational scripts. - - -ENVIRONMENT VARIABLES ---------------------- -+NETCFG_DEBUG+:: - Set to 1 to activate debug output. +The following commands are understood: + +*list*:: + List all available profiles. Active profiles will be marked with a + `*'. + +*store*:: + Saves which profiles are currently active. + +*restore*:: + Loads the profiles that were active during the last invocation of + `*store*'. + +*stop-all*:: + Stops all active network profiles. + +*start [+PROFILE+]*:: + Start the network profile specified on the command line. + +*stop [+PROFILE+]*:: + Stop the network profile specified on the command line. + +*restart [+PROFILE+]*:: + Restart the network profile specified on the command line. If it is + not started yet, it will be started. + +*switch-to [+PROFILE+]*:: + Starts the network profile specified on the command line after + stopping all profiles that refer to the same interface. + +*status [+PROFILE+]*:: + Show terse runtime status information about a profile, followed by + its most recent log data from the journal. + +*enable [+PROFILE+]*:: + Enable the systemd unit for the profile specified. This will create + a unit configuration file. If the file already exists, the command + fails. No other profiles than the one specified will be enabled. + Changes to the general options in a profile specification will not + propagate to the unit configuration file automatically. After such + changes, it is necessary to `*reenable*' the profile. + +*disable [+PROFILE+]*:: + Disable the systemd unit for the profile specified. This will remove + the file created by `*enable*' even if it was customized, so be + carefull. + +*reenable [+PROFILE+]*:: + Reenable the systemd unit for the profile specified. This is + effectively a combination of `*disable*' and `*enable*'. + + +EXIT STATUS +----------- +On success 0 is returned, a non-zero failure code otherwise. + + +ENVIRONMENT +----------- +'$NETCTL_DEBUG':: + If set to `"yes"`, debugging output is generated. +'$NETCTL_STATE_FILE':: + The location of the state file. Defaults to + '/var/lib/netctl/netctl.state'. SEE ALSO -------- -*netcfg-profiles*(5) on how to configure netcfg. - -include::footer.txt[] +*netctl.profile*(5) *netctl.special*(7) *systemctl*(1) diff --git a/docs/netctl.profile.5.txt b/docs/netctl.profile.5.txt index f929e47..21ea52c 100644 --- a/docs/netctl.profile.5.txt +++ b/docs/netctl.profile.5.txt @@ -1,321 +1,362 @@ -NETCFG-PROFILES(5) -================== +NETCTL.PROFILE(5) +================= NAME ---- -netcfg-profiles - netcfg profiles documentation and syntax +netctl.profile - Profile options + + +SYNOPSIS +-------- +netctl.profile DESCRIPTION ----------- -The *netcfg*(8) profiles are plain text files that defines variables for -netcfg behavior. They must be compliant with *bash*(1) shell syntax and -usually do not execute any code. +Profiles for netctl live under '/etc/network.d/' and are plain text +files. The files consist of variable definitions following the bash +shell syntax and are not expected to execute any code. It is good to +omit as much quoting as possible. For a few WPA-related variables, +special quoting rules (see below) apply. -They are named '/etc/network.d/$\{profile_name}', where -+$\{profile_name\}+ must not contain a newline character and should not -start with the `@'-sign. +The name of the profile is the name of the file. Profile names must not +contain newlines and should not end in '.service' or '.conf'. Whenever a +profile is read, all executable scripts in '/etc/network.d/hooks/' and +any executable script in '/etc/network.d/interfaces/' with the name of +the interface for the profile are sourced. For each connection type, +there are example profile files in '/etc/network.d/examples/'. -OVERVIEW --------- -Profiles must define mandatory variables: +AVAILABLE CONNECTION TYPES +-------------------------- ++ethernet+:: + For wired connections. ++wireless+:: + For wireless connections. This connection type requires + *wpa_supplicant* to be available. ++bond+:: + Network bonding. This connection type requires *ifenslave* to be + available. ++bridge+:: + Network bridging. This connection type requires *brctl* to be + available. ++pppoe+:: + For PPPoE connections. ++tunnel+:: + For tunnel interfaces. ++tuntap+:: + For TUN/TAP interfaces. ++vlan+:: + For VLANs on ethernet-like connections. + + +GENERAL OPTIONS +--------------- +'Description=':: + A description of the profile. + +'Connection=' [mandatory for all profiles]:: + The connection type used by the profile. + +'Interface=' [mandatory for all profiles]:: + The name of the associated network interface. The interface name + should not be quoted. + +'BindsToInterfaces=()':: + An array of physical network interfaces that this profile needs + before it can be started. For `enabled' profiles, *systemd* will + wait for the presence of the specified interfaces before starting a + profile. If this variable is not specified, it defaults to the value + of 'Interface'. + +'After=()':: + An array of profile names that should be started before this profile + is started. This is only an ordering dependency and is not intended + to be a list of profiles that this profile requires. The meaning is + the same as 'After' in *systemd.unit*(5). + +'ExecUpPost=':: + A command that is executed after a connection is established. If the + specified command returns anything other than 0 (success), *netctl* + will abort and stop the profile. If the command should be allowed to + fail, add ``|| true`' to the end of it. + +'ExecDownPre=':: + A command that is executed after a connection is brought down. + Similar precautions should be taken as with 'ExecUpPost'. + + +IP OPTIONS +---------- +These options apply to all connections that set up an IP-enabled +network. In particular, these connection types are +ethernet+, ++wireless+, +bond+, +bridge+, +tunnel+, +tuntap+, and +vlan+. + +'IP=' [mandatory for IPv4]:: + One of `static', `dhcp', or `no', depending on the desired way of + obtaining an address. + +'IP6=' [mandatory for IPv6]:: + One of `static', `stateless', `dhcp-noaddr', `dhcp', `no' or left + out (empty) altogether. The difference between not specifying and + setting to `no' is in the handling of __router advertisement__ + packages, which is blocked by `no'. + +'Address=()' [requires 'IP=static']:: + An array of IP addresses, optionally suffixed with ``/`', + where netmask is an integer between 0 and 255. The default netmask + is 24. Leaving out brackets for arrays consisting of a single + element is accepted in the Bash syntax. + +'Gateway=' [requires 'IP=static']:: + An IP routing gateway address. + +'Routes=':: + An array of custom routes of the form + + `**
** via ****'. + +'Address6=()' [requires 'IP6=static']:: + An array of IPv6 addresses. Prefix length may be specified via + `1234:bcd::11/64' syntax. + +'Gateway6=' [requires 'IP6=static']:: + An IPv6 routing gateway address. + +'Routes6=':: + An array of custom routes of the form + + `**
** via ****'. + +'DHCPClient=' [requires a DHCP setting]:: + The name of the preferred DHCP client. Supported options are + `dhcpcd' and `dhclient'. Defaults to `dhcpcd'. + +'IPCustom=()':: + An array of argument lines to pass to `ip`. This can be used to + achieve complicated configurations within the framework of *netctl*. + +'Hostname=':: + A system hostname. + +'DNS=()':: + An array of DNS nameservers. Simply specify the IP addresses of each + of the DNS nameservers. -+INTERFACE+:: - The name of the associated network interface. -+DESCRIPTION+:: - A description of the profile. -+CONNECTION+:: - The connection type used by the profile. +'DNSDomain=':: + A ``domain`' line for '/etc/resolv.conf'. -Connections define how the network is set up for the profile and also -determine additional configuration variable that control their -behavior. The available connection types are determined by files in -'/usr/lib/network/connections/'. +'DNSSearch=':: + A ``search`' line for '/etc/resolv.conf'. +'DNSOptions=()':: + An array of ``options`' lines for '/etc/resolv.conf'. -Available connections ---------------------- -ethernet:: - Standard network configuration, suitable for wired connections. -wireless:: - Wireless connection, with *wpa_supplicant*(1) as configuration - back-end. -bond:: - Bonded network interfaces using *ifenslave*. -bridge:: - Network bridge setup using *brctl*(8). -tuntap:: - TUN/TAP interfaces. -tunnel:: - Tunnel interfaces. -vlan:: - VLAN setup. -openvpn:: - OpenVPN setup. -ppp:: - PPP connections setup. -pppoe:: - PPPoE connections setup. - -The configuration variable for these connection types is described in -the following sections. - - -Ethernet options reference --------------------------- +'TimeoutDHCP=':: + Maximum time, in seconds, to wait for DHCP to be successful. + Defaults to ``10`'. -Description -~~~~~~~~~~~ -This connection method uses the iproute suite of tools and dhcpcd to -gain an IP address. - -+IP+ (required for IPv4):: - Either `static' or `dhcp'. Set to `no' to have netcfg bring the interface - up but assign no addresses. Static requires at least one of +ADDR+ or - +IPCFG+. - -IPv4 options -~~~~~~~~~~~~ -+ADDR+ (requires +IP+ of `static'):: - A single IP address to configure a static IP. -+GATEWAY+ (requires +IP+ of `static'):: - Set specified gateway -+NETMASK+ (requires +IP+ of `static'):: - Set specified netmask. Defaults to 24. -+ROUTES+:: - An array of custom routes (of the form _address range_ via _gateway_) - -IPv6 options -~~~~~~~~~~~~ -+IP6+ (required for IPv6):: - Either `dhcp', `dhcp-noaddr', `stateless', `static'. Set to `no' to - disable IPv6. -+ADDR6+ (required when +IP6+ is `static'):: - An array of IPv6 addresses: prefix length may be specified via - `1234:bcd::11/64' syntax. -+GATEWAY6+ (requires +IP6+ of `static'):: - The gateway address for IPv6 routing. -+ROUTES6+:: - An array of custom routes (of the form _address range_ via _gateway_) -+DAD_TIMEOUT+:: - Time to wait for Duplicate Address Detection to succeed. Defaults to - 3 seconds. - -DNS configuration -^^^^^^^^^^^^^^^^^ -+DNS+:: - Array of DNS nameservers. Simply specify the IP's of each of the DNS - nameservers. -+DNS_OPTIONS+:: - Array of ``option'' lines for '/etc/resolv.conf' -+SEARCH+:: - ``search'' line for '/etc/resolv.conf' -+DOMAIN+:: - ``domain'' line for '/etc/resolv.conf' -+HOSTNAME+:: - Set the system hostname. Ensure any hostname is correctly referenced - in '/etc/hosts' - -DHCP configuration -^^^^^^^^^^^^^^^^^^ -+DHCP_OPTIONS+ (ipv4):: - String. Any extra arguments to pass to the dhcp client, presently - dhcpcd. -+DHCP_TIMEOUT+:: - Integer. Maximum time to try for a DHCP IP. Default is 10 seconds. -+DHCLIENT+:: - yes/no. Use dhclient instead of dhcpcd. Defaults to no -+DHCLIENT_OPTIONS+ (ipv4):: - String. Extra options to pass to dhclient for IPv4. -+DHCLIENT6_OPTIONS+ (ipv6):: - String. Extra options to pass to dhclient for IPv6. - -802.11x Authentication -^^^^^^^^^^^^^^^^^^^^^^ -+AUTH8021X+:: - Use 802.11x authentication. Enable with `yes'. -+WPA_CONF+ (required for an +AUTH8021X+ of `yes' only):: - Path to wpa_supplicant configuration. Defaults to - '/etc/wpa_supplicant.conf' -+WPA_OPTS+ (optional for an +AUTH8021X+ of `yes'):: - Extra arguments for wpa_supplicant not specified otherwise. Any option - here must specify wpa_supplicant driver. Defaults to _-Dwired_. - -Miscellaneous options -^^^^^^^^^^^^^^^^^^^^^ -+IPCFG+:: - 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. -+SKIPNOCARRIER+:: - `yes'/`no'. Don't abort interface setup if no carrier is found. - - -Examples -~~~~~~~~ - -Using ADDR and GATEWAY to set static IP and gateway -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------------- -IP="static" -ADDR="192.168.1.23" -GATEWAY="192.168.1.1" ---------------------- +'TimeoutDAD=':: + Maximum time, in seconds, to wait for IPv6's Duplicate Address + Detection to succeed. Defaults to ``3`'. -Using IPCFG to set a static IP and gateway with custom DNS -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -------------------------------------------------------------------------------------- -IP="static" -IPCFG=("addr add dev eth0 192.168.1.23/24 brd +" "route add default via 192.168.1.1") -DNS=("208.67.222.222" "208.67.220.220") -------------------------------------------------------------------------------------- +OPTIONS FOR `ethernet' CONNECTIONS +---------------------------------- +Next to the *ip options*, the following are understood for connections +of the `ethernet' type: -Wireless options reference --------------------------- +'SkipNoCarrier=':: + Whether or not the absence of a carrier (plugged-in cable) is + acceptable. Defaults to ``no`'. -Description -~~~~~~~~~~~ -This connection method uses wpa_supplicant to configure a wireless -network connection. This connection uses the 'ethernet' connection after -successful association and thus supports all of its options. - -Options -~~~~~~~ -+SECURITY+ (required for security of `wep', `wpa', `wpa-configsection' or `wpa-config'):: - One of `wpa', `wep', `none', `wpa-configsection' or `wpa-config'. - Defaults to `none'. -+KEY+ (required for +SECURITY+ of `wpa' or `wep' only):: - Wireless encryption key. -+ESSID+ (this or +AP+ is required):: - Name of network to connect to, or hexadecimal digits (see - `ESSID_TYPE') -+ESSID_TYPE+ (optional, defaults to `ascii'):: - Set to `ascii' or `hex', if set to `hex', +ESSID+ will be interpreted as - an hexadecimal +SSID+ and written unquoted to the wpa_supplicant - configuration file. -+AP+ (this or +ESSID+ is required):: - AP (BSSID) of the network to connect to. -+HIDDEN+ (optional):: - Define this to connect to hidden ESSIDs. -+ADHOC+ (optional):: - Define this to use ad-hoc mode for wireless. -+TIMEOUT+ (optional):: - Time to wait for association. Defaults to 15 seconds. -+SCAN+ (optional):: - `yes'/`no'. Scan for a wireless network rather than blindly attempting to - connect. Hidden SSID networks do not appear in a scan. -+PRIORITY+ (optional):: - Priority group for the network. The matched network with the highest - priority will be selected. Defaults to 0. - -WPA options -^^^^^^^^^^^ -+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. -+WPA_GROUP+:: - Group that has authority to configure wpa_supplicant via it's control - interface. Used in any configuration that is generated by netcfg. -+WPA_COUNTRY+ (optional, nl80211 based drivers):: - The country where the device will be used. This allows wpa_supplicant - to enforce any local regulatory limitations and will allow all - appropriate channels/frequencies for your device. -+WPA_DRIVER+ (optional):: - A comma-separated list of wpa_supplicant driver interfaces to try. - Defaults to `nl80211,wext'. - -rfkill (Radio Kill Switch) options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -+RFKILL+:: - hard/soft A switch with physical on/off state that cannot be - controlled via software is considered a *hard* switch. Any switch that - can be controlled via software is considered *soft*. -+RFKILL_NAME+:: - Some switches sysfs entries are not linked with the interface. To - match them up, configure the name from '/sys/class/rfkill/rfkillX/name' - here so that netcfg can identify which to control. - - -Options for `bridge' connections --------------------------------- -The options of `ethernet' connections apply to set up standard IP -connectivity. +'Auth8021X=':: + Set to ``yes`' to use 802.11x authentication. -+BRIDGE_INTERFACES+:: - List of network interfaces taking part in the bridge. -+FWD_DELAY+:: - Forward delay of the bridge, see *brctl*(8) -+MAX_AGE+:: - maxage parameter, see *brctl*(8) +'WPAConfigFile=':: + Path to a *wpa_supplicant* configuration file. Defaults to + '/etc/wpa_supplicant.conf'. +'WPADriver=':: + The *wpa_supplicant* driver to use for 802.11x authentication. + Defaults to ``wired`'. -Options for `tuntap' connections --------------------------------- -The options of `ethernet' connections apply to set up standard IP -connectivity. +'TimeoutCarrier=':: + Maximum time, in seconds, to wait for a carrier. Defaults to ``5`'. + +'TimeoutWPA=':: + Maximum time, in seconds, to wait for 802.11x authentication to + succeed. Defaults to ``15`'. + + +OPTIONS FOR `wireless' CONNECTIONS +---------------------------------- +Next to the *ip options*, the following are understood for connections +of the `wireless' type: + +'Security=':: + One of `none', `wep', `wpa', `wpa-configsection', or `wpa-config'. + Defaults to ``none`'. + +'ESSID=' [mandatory]:: + The name of the network to connect to. + Special quoting rules (see below) apply. + +'AP=':: + The BSSID (MAC address) of the access point to connect to. + +'Key=':: + The secret key to a WEP, or WPA encrypted network. + Special quoting rules (see below) apply. -+MODE+:: - Set to `tun' or `tap'. -+USER+:: - The owning user of the tun/tap interface. -+GROUP+:: - The owning group of the tun/tap interface. +'Hidden=':: + Whether or not the specified network is a hidden network. Defaults + to ``no`'. +'Scan=':: + Whether or not to scan for the presence of a network before + attempting to connect. Hidden networks do not appear in a scan. + Defaults to ``no`'. -Options for `ppp' connections ------------------------------ -+PEER+:: - The *pppd*(8) peer to use. -+PPP_TIMEOUT+:: - *pppd*(8) timeout. +'AdHoc=':: + Whether or not to use ad-hoc mode. Defaults to ``no`'. +'Country=':: + The country for which frequency regulations will be enforced. -Options for `vlan' connections +'Priority=':: + Priority group for the network. In case of automatic profile + selection, the matched network with the highest priority will be + selected. Defaults to ``0`'. + +'WPAGroup=':: + Group that has the authority to configure *wpa_supplicant* via its + control interface. Defaults to ``wheel`'. + +'WPAConfigSection=()' [mandatory for 'Security=wpa-configsection']:: + Array of lines that form a network block for *wpa_supplicant*. + +'WPAConfigFile=':: + Path to a *wpa_supplicant* configuration file. Defaults to + '/etc/wpa_supplicant.conf'. Used for 'Security=wpa-config'. + +'WPADriver=':: + The *wpa_supplicant* driver to use. Defaults to ``nl80211,wext`'. + +'TimeoutWPA=':: + Maximum time, in seconds, to wait for steps in the association and + authentication to succeed. Defaults to ``15`'. + +'RFKill=':: + The name of an *rfkill* device. When specified, the device is used + to block/unblock the interface when appropriate. Names can be found + in '/sys/class/rfkill/rfkillX/name'. It is also possible to set this + variable to ``auto`'. In that case an *rfkill* device that is + associated with the network interface is used. + + +OPTIONS FOR `bond' CONNECTIONS ------------------------------ -+INTERFACE+:: - The name of the virtual interface. -+VLAN_PHYS_DEV+:: - The name of the associated physical interface. -+VLAN_ID+:: - See *ip*(8). +The interfaces of 'BindsToInterfaces' are bound together in the +interface named by 'Interface'. All *ip options* are understood for +connections of the `bond' type. -Options for `tunnel' connections +OPTIONS FOR `bridge' CONNECTIONS -------------------------------- -Standard `ethernet' options apply for IP configuration. +The interfaces of 'BindsToInterfaces' take part in the bridge named by +'Interface'. Next to the *ip options*, the following are understood for +connections of the `bridge' type: + +'FwdDelay=':: + Forward delay of the bridge. See *brctl*(8) for details. + +'MaxAge=':: + Maximum age parameter. See *brctl*(8) for details. -+INTERFACE+:: - The name of the tunnel interface. -+MODE+:: - The tunnel type (e.g. `sit'). See *ip*(8) for available modes. -+LOCAL+:: - The address of the local end of the tunnel. -+REMOTE+:: - The address of the remote end of the tunnel. +OPTIONS FOR `tunnel' CONNECTIONS +---------------------------------- +The name of the tunnel interface is specified in 'Interface'. Next to +the *ip options*, the following are understood for connections of the +`tunnel' type: -Options for `bond' connections +'Mode=':: + The tunnel type (e.g. `sit'). See *ip*(8) for available modes. + +'Local=':: + The address of the local end of the tunnel. +'Remote=':: + The address of the remote end of the tunnel. + + +OPTIONS FOR `tuntap' CONNECTIONS +---------------------------------- +The name of the tuntap interface is specified in 'Interface'. Next to +the *ip options*, the following are understood for connections of the +`tuntap' type: + +'Mode=':: + Either ``tun`', or ``tap`'. + +'User=':: + The owning user of the tun/tap interface. + +'Group=':: + The owning group of the tun/tap interface. + + +OPTIONS FOR `vlan' CONNECTIONS ------------------------------ -Standard `ethernet' options apply for IP configuration. +The name of the vlan interface is specified in 'Interface'. The +underlying physical interface is specified in 'BindsToInterfaces'. +Hence, for vlan profiles, 'BindsToInterfaces' contains the name of a +single network interface. -+SLAVE_INTERFACES+ (Bash array):: - An array of names of interfaces to be bound together. +All options for connections of the `ethernet' type are understood for +connections of the `vlan' type. Additionally, connections of the `vlan' +type can set a vlan identifier using 'VLANID='. See *ip*(8) for details. -Options for `openvpn' connections ---------------------------------- -+OVPN_CONFIG+:: - Path to the *openvpn*(8) config file. -+OVPN_PID_FILE+:: - Path to the *openvpn*(8) PID file. -+OVPN_FLAGS+:: - Options to pass to *openvpn*(8) invocation. +SPECIAL QUOTING RULES +--------------------- +Configuration files for *wpa_supplicant* use non-standard quoting. +Therefore, non-standard quoting rules exist for some variables for +connections of the `wireless' type. In particular, these variables are +'ESSID', and 'Key'. + +A variable is considered *quoted* by *wpa_supplicant* if it is enclosed +in double quotes ("). A variable is considered *non-quoted* by +*wpa_supplicant* if it does not start with a double quote. Hexadecimal +values are specified *non-quoted* in configuration files of +*wpa_supplicant*. In *netctl*, variables are written to *wpa_supplicant* +configuration files *quoted* by default. When special quoting rules +apply, it is possible to specify an unquoted (hexadecimal) value using a +special syntax. + +The special quoting rules of *netctl* are as follows. A string that +starts with a literal double quote is considered *non-quoted*. Any other +string is considered *quoted*. It is possible to specify quoted strings +that start with a double quote by quoting manually. An extreme example +is the specification of a *quoted* double quote: '`X='""""'`'. On the +other end of the spectrum there is the *non-quoted* backslash: +'`X=\"\\`'. + +Further examples of *quoted* strings (all equivalent): +------------- +X=string +X="string" +X='""string"' +------------- + +Further examples of *non-quoted* strings (all equivalent): +------------ +X=\"string +X="\"string" +X='"string' +------------ + +A mnemonic is to think of the prefix ``\"`' as saying `non'-`quote'. SEE ALSO -------- -include::footer.txt[] +*netctl*(1) diff --git a/docs/netctl.special.7.txt b/docs/netctl.special.7.txt new file mode 100644 index 0000000..eabb4d3 --- /dev/null +++ b/docs/netctl.special.7.txt @@ -0,0 +1,55 @@ +NETCTL.SPECIAL(7) +================= + +NAME +---- +netctl.special - Special netctl systemd units + + +SYNOPSIS +-------- +netctl.service, netctl-auto.service, netctl-ifplugd.service + + +DESCRIPTION +----------- +Bundled with netctl come a few systemd units that are not controlled +through the netctl command. They can be used through the systemctl +utility of systemd. + + +SPECIAL UNITS +------------- +netctl.service:: + When started, this unit tries to start the profiles that were + running when the unit was last stopped. In some cases, the interface + a profile binds to might not be available yet, when netctl.service + tries to bring a profile up. A simple, hackish, solution is to do: +-------------------------------------------------------------------- +echo "[[ -t 0 ]] || sleep 3" > /etc/network.d/interfaces/ +chmod 755 /etc/network.d/interfaces/ +-------------------------------------------------------------------- + A more concise solution is to first enable a profile through netctl + and then disable it again through systemctl: +-------------------------------------------------------------------- +netctl enable +systemctl disable netctl@ +-------------------------------------------------------------------- + This way the unit configuration file for the profile remains in + existence, while the profile is not enabled. + +netctl-auto@.service:: + This unit issues a scan on the interface it is used for and tries to + start a profile for a network it finds. It is targeted to wireless + interfaces. + +netctl-ifplugd@.service:: + This unit starts ifplugd on the interface it is used for. It will + try to start a netctl profile whenever a cable is plugged into the + interface and stop the profile when the cable is unplugged. Note + that this unit does not provide network.target. + + +SEE ALSO +-------- +*netctl*(1), *netctl.profile*(5) diff --git a/services/netctl-auto@.service b/services/netctl-auto@.service index 81f2369..9a035da 100644 --- a/services/netctl-auto@.service +++ b/services/netctl-auto@.service @@ -1,12 +1,12 @@ [Unit] -Description=Automatic wireless network connection via netcfg +Description=Automatic wireless network connection using netctl profiles +Documentation=man:netctl.special(7) Before=network.target Wants=network.target [Service] -EnvironmentFile=/etc/conf.d/netcfg -ExecStart=/usr/bin/netcfg-wpa_actiond $WIRELESS_INTERFACE -ExecStop=/usr/bin/netcfg-wpa_actiond stop $WIRELESS_INTERFACE +ExecStart=/usr/bin/netctl-auto start %i +ExecStop=/usr/bin/netctl-auto stop %i RemainAfterExit=yes Type=forking diff --git a/services/netctl-ifplugd@.service b/services/netctl-ifplugd@.service index 8948ac6..05cb1cf 100644 --- a/services/netctl-ifplugd@.service +++ b/services/netctl-ifplugd@.service @@ -1,10 +1,9 @@ [Unit] -Description=Automatic wired network connection via netcfg +Description=Automatic wired network connection using netctl profiles +Documentation=man:netctl.special(7) [Service] -EnvironmentFile=/etc/conf.d/netcfg -ExecStart=/usr/bin/ifplugd -i $WIRED_INTERFACE -r /etc/ifplugd/netcfg.action -fIns -ExecStop=/usr/bin/netcfg iface-down $WIRED_INTERFACE +ExecStart=/usr/bin/ifplugd -i %i -r /etc/ifplugd/netctl.action -fIns [Install] WantedBy=multi-user.target diff --git a/services/netctl.service b/services/netctl.service index f400be0..593d36f 100644 --- a/services/netctl.service +++ b/services/netctl.service @@ -1,13 +1,12 @@ [Unit] -Description=Netcfg multi-profile daemon +Description=(Re)store the netctl profile state Before=network.target -Wants=network.target [Service] Type=oneshot RemainAfterExit=yes -ExecStart=/usr/bin/netcfg-daemon start -ExecStop=/usr/bin/netcfg-daemon stop +ExecStart=-/usr/bin/netctl restore +ExecStop=/usr/bin/netctl store KillMode=none [Install] diff --git a/services/netctl@.service b/services/netctl@.service index 57229f8..9bd99b6 100644 --- a/services/netctl@.service +++ b/services/netctl@.service @@ -1,13 +1,14 @@ [Unit] -Description=Netcfg networking service for profile %i -Before=network.target +Description=Networking for netctl profile %i +Documentation=man:netctl.profile(5) +Before=network.target netctl.service Wants=network.target [Service] Type=oneshot RemainAfterExit=yes -ExecStart=/usr/bin/netcfg check-iface %i -ExecStop=-/usr/bin/netcfg down %i +ExecStart=/usr/lib/network/network start %i +ExecStop=/usr/lib/network/network stop %i KillMode=none [Install] diff --git a/src/ifplugd.action b/src/ifplugd.action index ea3a16c..3a28505 100755 --- a/src/ifplugd.action +++ b/src/ifplugd.action @@ -1,8 +1,10 @@ #!/bin/bash # -# ifplugd.action script for netcfg +# ifplugd.action script for netctl -. /usr/lib/network/network +. /usr/lib/network/globals + +PROFILE_FILE="$STATE_DIR/ifplugd_$1.profile" case "$2" in up) @@ -14,12 +16,12 @@ case "$2" in declare -a preferred_profiles declare -a dhcp_profiles declare -a static_profiles - for profile in $(list_profiles); do + while read -r profile; do ( - echo "loading $profile" - load_profile "$profile" - [[ "$INTERFACE" == "$1" && "$CONNECTION" == "ethernet" ]] || continue - checkyesno "${AUTO_WIRED:-no}" && exit 1 # user preferred AUTO profile + echo "Reading profile '$profile'" + source "$PROFILE_DIR/$profile" + [[ "$Interface" == "$1" && "$Connection" == "ethernet" ]] || continue + is_yes "${AutoWired:-no}" && exit 1 # user preferred AUTO profile [[ "$IP" == "dhcp" ]] && exit 2 # dhcp profile exit 3 # static profile ) @@ -28,17 +30,20 @@ case "$2" in 2) dhcp_profiles+=("$profile");; 3) static_profiles+=("$profile");; esac - done + done < <(list_profiles) if [[ ${#preferred_profiles[@]} > 1 ]]; then - echo "AUTO_WIRED flag for $1 set in more than one profile (${preferred_profiles[*]})" + echo "AutoWired flag for '$1' set in more than one profile (${preferred_profiles[*]})" fi for profile in "${preferred_profiles[@]}" "${dhcp_profiles[@]}" "${static_profiles[@]}"; do - profile_up "$profile" && exit 0 + if "$SUBR_DIR/nework" start "$profile"; then + printf "%s" "$profile" > "$PROFILE_FILE" + exit 0 + fi done ;; down) - if check_iface "$1"; then - interface_down "$1" && exit 0 + if [[ -e "$PROFILE_FILE" ]]; then + "$SUBR_DIR/nework" stop "$(< "$PROFILE_FILE")" && rm -f "$PROFILE_FILE" fi ;; *) diff --git a/src/lib/8021x b/src/lib/8021x index d2ddfe4..60f3552 100644 --- a/src/lib/8021x +++ b/src/lib/8021x @@ -1,171 +1,129 @@ -# Usage: wpa_call $interface $call ... -# Wrapper around wpa_cli to deal with supplicant configurations that set a -# non-standard control path. -wpa_call() -{ - local args=("-i" "$1") +## /usr/lib/network/globals needs to be sourced before this file + + +## Wrapper around wpa_cli to deal with supplicant configurations that set a +## non-standard control path. +# $1: interface name +# $2...: call to the supplicant +wpa_call() { + local args=( "-i" "$1" ) shift - if [[ -n "$WPA_CTRL_DIR" ]]; then + if [[ $WPA_CTRL_DIR ]]; then args+=("-p" "$WPA_CTRL_DIR") - elif [[ -n "$WPA_CONF" ]] && grep -q "^[[:space:]]*ctrl_interface=" "$WPA_CONF"; then - WPA_CTRL_DIR=$(grep -m 1 "^[[:space:]]*ctrl_interface=" "$WPA_CONF") + elif [[ $WPAConfigFile ]] && grep -q "^[[:space:]]*ctrl_interface=" "$WPAConfigFile"; then + WPA_CTRL_DIR=$(grep -m1 "^[[:space:]]*ctrl_interface=" "$WPAConfigFile") WPA_CTRL_DIR=${WPA_CTRL_DIR#*ctrl_interface=} - if [[ "$WPA_CTRL_DIR" == DIR=* ]]; then + if [[ $WPA_CTRL_DIR == DIR=* ]]; then WPA_CTRL_DIR=${WPA_CTRL_DIR:4} WPA_CTRL_DIR=${WPA_CTRL_DIR%% GROUP=*} fi - args+=("-p" "$WPA_CTRL_DIR") + args+=( "-p" "$WPA_CTRL_DIR" ) fi - report_debug wpa_cli "${args[@]}" "$@" - wpa_cli "${args[@]}" "$@" + do_debug wpa_cli "${args[@]}" "$@" } -# Uses wpa_supplicant to check for association to a network -# wpa_check interface [timeout] -wpa_check() -{ - local timeout=0 INTERFACE="$1" TIMEOUT="${2:-15}" CONDITION="${3:-COMPLETED}" - # CONDITION is required as wired connections are ready at ASSOCIATED not COMPLETED FS#20150 - - while (( timeout < TIMEOUT )); do - ( # Sometimes wpa_supplicant isn't ready so silence errors for 2s only to avoid hiding real errors - if (( timeout < 2 )); then - eval $(wpa_call "$INTERFACE" status 2> /dev/null | grep -F "wpa_state=") - else - eval $(wpa_call "$INTERFACE" status | grep -F "wpa_state=") - fi - [[ "$wpa_state" = "$CONDITION" ]] - ) && return 0 - sleep 1 - (( ++timeout )) - done - echo "$wpa_state" - # wpa_cli -i "$INTERFACE" terminate >/dev/null 2>&1 # callers sometimes called stop_wpa, which does more but seems redundant - # termination should either be handled properly here, or by callers - stop_wpa "$INTERFACE" - return 1 +## Retrieves the state of an instance of the wpa supplicant +## Displays one of: DISCONNECTED, INTERFACE_DISABLED, INACTIVE, SCANNING, +## AUTHENTICATING, ASSOCIATING, ASSOCIATED, 4WAY_HANDSHAKE, +## GROUP_HANDSHAKE, COMPLETED +# $1: interface name +wpa_get_state() { + local state + state=$(wpa_call $1 status | grep -m1 "^wpa_state=") || return 1 + echo ${state#wpa_state=} } -start_wpa() -{ - local INTERFACE="$1" WPA_CONF="$2" WPA_DRIVER="$3" - shift 3 - local WPA_OPTS="$@" PIDFILE="/run/wpa_supplicant_${INTERFACE}.pid" - - if [[ -n "$WPA_CONF" ]]; then - WPA_CONF="-c$WPA_CONF" - else - WPA_CTRL_DIR="/run/wpa_supplicant" - WPA_CONF="-C$WPA_CTRL_DIR" - fi - - wpa_supplicant -B -P "$PIDFILE" -i "$INTERFACE" -D "$WPA_DRIVER" "$WPA_CONF" $WPA_OPTS - - # wait up to one second for the pid file to appear - timeout_wait 1 '[[ -f "$PIDFILE" ]]'; - return $? +## Waits until the wpa supplicant reaches a listed state +# $1: timeout +# $2: interface name +# $3...: accepted states +wpa_wait_until_state() { + local timeout=$1 interface=$2 states=( "${@:3}" ) + timeout_wait "$timeout" \ + 'in_array "$(wpa_get_state "$interface")" "${states[@]}"' } -stop_wpa() -{ - local INTERFACE="$1" - # we need this as long as wpa_cli has a different default than netcfg - [[ -z "$WPA_CTRL_DIR" && -z "$WPA_CONF" ]] && WPA_CTRL_DIR="/run/wpa_supplicant" - - # done if wpa_supplicant is already terminated for this interface - [[ -e "$WPA_CTRL_DIR/$INTERFACE" ]] || return - - wpa_call "$INTERFACE" terminate > /dev/null - - # wait up to one second for the pid file to be removed - timeout_wait 1 '[[ ! -f "/run/wpa_supplicant_${INTERFACE}.pid" ]]' || \ - kill "$(< "/run/wpa_supplicant_${INTERFACE}.pid")" &> /dev/null & +## Waits while the wpa supplicant is in a listed state +# $1: timeout +# $2: interface name +# $3...: rejected states +wpa_wait_while_state() { + local timeout=$1 interface=$2 states=( "${@:3}" ) + timeout_wait "$timeout" \ + '! in_array "$(wpa_get_state "$interface")" "${states[@]}"' } -wpa_reconfigure() { - wpa_call "$1" reconfigure > /dev/null - return $? -} +## Start an instance of the wpa supplicant +# $1: interface name +# $2: interface driver(s) +# $3: configuration file +wpa_start() { + local interface=$1 driver=$2 configuration=$3 + local pidfile="/run/wpa_supplicant_$interface.pid" -wpa_check_current_essid() { - # usage: wpa_check_current_essid $interface $essid - # check that wpa_supplicant is connected to the right essid - local INTERFACE=$1 ESSID=$2 status - status=$(wpa_call "$INTERFACE" status | grep "^ssid=") - if (( $? == 0 )) && [[ "$status" == "ssid=$ESSID" ]]; then - return 0 + if [[ $configuration ]]; then + configuration="-c$configuration" else + WPA_CTRL_DIR="/run/wpa_supplicant" + configuration="-C$WPA_CTRL_DIR" + fi + + do_debug wpa_supplicant -B -P "$pidfile" -i "$interface" -D "$driver" \ + "$configuration" $WPAOptions + + # Wait up to one second for the pid file to appear + if ! timeout_wait 1 '[[ -f "$pidfile" ]]'; then + # Remove the configuration file if it was generated + configuration="$STATE_DIR/wpa_supplicant_$interface.conf" + [[ -f $configuration && -O $configuration ]] && rm -f "$configuration" return 1 fi } -wpa_find_essid() { - # usage: wpa_find_essid $INTERFACE $ESSID - # look for existence of a given essid. Assumes wpa_supplicant is - # running - result=$(wpa_supplicant_scan_and_find "$1" 5 "$2") - ret=$? - echo $result - report_debug wpa_find_essid "\"$result\"" - return $ret -} +## Stop an instance of the wpa supplicant +# $1: interface name +wpa_stop() { + local interface=$1 config_file="$STATE_DIR/wpa_supplicant_$1.conf" + # We need this as long as wpa_cli has a different default than netctl + if [[ -z $WPA_CTRL_DIR && -z $WPAConfigFile ]]; then + WPA_CTRL_DIR="/run/wpa_supplicant" + fi -wpa_find_ap() { - # usage: wpa_find_essid $INTERFACE $ESSID - # look for existence of a given essid. Assumes wpa_supplicant is - # running - bssid=${2,,} # set to lowercase - result=$(wpa_supplicant_scan_and_find "$1" 1 "$bssid") - ret=$? - echo $result - report_debug wpa_find_ap "\"$result\"" - return $ret -} + # Done if wpa_supplicant is already terminated for this interface + [[ -z $WPA_CTR_DIR || -e "$WPA_CTRL_DIR/$interface" ]] || return -wpa_supplicant_scan_and_find() { - #usage: wpa_supplicant_scan_and_find $INTERFACE $FIELD $ITEM - # field = 1 for bssid, 5 for essid - # item = string to lookup - local INTERFACE="$1" FIELD="$2" ITEM="$3" RETRIES=5 scan_ok=0 try - for ((try=0; try < $RETRIES; try++)); do - local found - wpa_call "$INTERFACE" scan > /dev/null - sleep 2 - found=$(wpa_call "$INTERFACE" scan_results | tail -n+2 | cut -f "$FIELD" | grep -F -x -m 1 -- "$ITEM") - (( $? == 0 )) && scan_ok=1 - - # ITEM has been found, echo it - if [[ -n "$found" ]]; then - echo "$found" - return 0 - fi - done - if (( $scan_ok != 1 )); then - report_debug wpa_supplicant_scan_and_find "unable to retrieve scan results" + wpa_call "$interface" terminate > /dev/null + [[ -f $config_file && -O $config_file ]] && rm -f "$config_file" + + # Wait up to one second for the pid file to be removed + if ! timeout_wait 1 '[[ ! -f "/run/wpa_supplicant_$interface.pid" ]]'; then + kill "$(< "/run/wpa_supplicant_$interface.pid")" &> /dev/null fi - return 1 } +## Scan for networks within range +# $1: interface name +# $2: fields of the wpa_supplicant scan_results wpa_supplicant_scan() { - local INTERFACE="$1" fields="$2" spawned_wpa=0 essids + local interface=$1 fields=$2 spawned_wpa=0 essids # temp file used, as keeping ESSID's with spaces in their name in arrays # is hard, obscure and kinda nasty. This is simpler and clearer. - [[ -z "$INTERFACE" ]] && return 1 + [[ $interface ]] || return 1 essids=$(mktemp --tmpdir essid.XXXXXXXX) - if [[ "$(wpa_call "$INTERFACE" ping 2> /dev/null)" != "PONG" ]]; then - start_wpa "$INTERFACE" "" "${WPA_DRIVER:-nl80211,wext}" || return 1 + if [[ "$(wpa_call "$interface" ping 2> /dev/null)" != "PONG" ]]; then + wpa_start "$interface" "${WPADriver:-nl80211,wext}" || return 1 spawned_wpa=1 fi - wpa_call "$INTERFACE" scan > /dev/null + wpa_call "$interface" scan > /dev/null # Wait at least 3 seconds for scan results sleep 3 - # Sometimes, that is not enough (FS#29946) - timeout_wait 7 '! wpa_call "$INTERFACE" status | grep -F -q "wpa_state=SCANNING"' - wpa_call "$INTERFACE" scan_results | + # Sometimes, that is not enough + wpa_wait_while_state 7 "$interface" "SCANNING" + wpa_call "$interface" scan_results | tail -n+2 | sort -rn -k3 | sort -u -k5 | @@ -179,97 +137,100 @@ wpa_supplicant_scan() { # Re-sort by strength as the removal disorders the list # Cut to the AP/essid fields only - (( $spawned_wpa == 1 )) && stop_wpa "$INTERFACE" + (( spawned_wpa == 1 )) && wpa_stop "$interface" - # File of 0 length, ie. no ssid's. + # File of 0 length: no ssid's if [[ ! -s "$essids" ]]; then rm -f "$essids" return 1 fi echo "$essids" - return 0 } -# Requires already loaded profile -make_wpa_config_file() { - local WPA_CONFD="$STATE_DIR/wpa.$1" - - # make empty tmp dir with correct permissions, rename it - check_make_state_dir - mkdir -p /run/wpa_supplicant - rm -rf "$WPA_CONFD" - mv -f "$(mktemp -d --tmpdir=$STATE_DIR)" "$WPA_CONFD" || return 1 - echo "ctrl_interface=/run/wpa_supplicant" >> "$WPA_CONFD/wpa.conf" - echo "ctrl_interface_group=${WPA_GROUP:-wheel}" >> "$WPA_CONFD/wpa.conf" - [[ $WPA_COUNTRY ]] && echo "country=$WPA_COUNTRY" >> "$WPA_CONFD/wpa.conf" - [[ -n "$ADHOC" ]] && echo "ap_scan=2" >> "$WPA_CONFD/wpa.conf" - echo "$WPA_CONFD/wpa.conf" +## Print a string within quotes, unless it starts with the "-modifier +## Quoted: string "string" '""string"' +## Non-quoted: \"string "\"string" '"string' +# $1: string +wpa_quote() { + local string=$1 + if [[ $string == \"* ]]; then + printf '%s' "${string:1}" + else + printf '"%s"' "$string" + fi } -# Requires already loaded profile -make_wpa_config() { - case $SECURITY in - none|wep|wpa) - case "${ESSID_TYPE:-ascii}" in - ascii) - echo "ssid=\"$ESSID\"" - ;; - hex) - # Hex ESSID is written unquoted and in lowercase (FS#24333) - echo "ssid=${ESSID,,}" - ;; - *) - report_fail "ESSID_TYPE must be set to 'ascii' or 'hex'." - return 1 - ;; - esac - if [[ -n "$AP" ]]; then - echo "bssid=${AP,,}" - fi - [[ -n "$ADHOC" ]] && echo "mode=1" +## Create a configuration file for wpa_supplicant without any network blocks +# $1: interface name +wpa_make_config_file() { + local config_file="$STATE_DIR/wpa_supplicant_$1.conf" + + if [[ -e $config_file ]]; then + report_debug "The anticipated filename '$config_file' is not available" + return 1 + fi + mkdir -p "$STATE_DIR" /run/wpa_supplicant + if ! : > "$config_file"; then + report_debug "Could not create the configuration file '$config_file'" + return 1 + fi + chmod 600 "$config_file" + + echo "ctrl_interface=/run/wpa_supplicant" >> "$config_file" + echo "ctrl_interface_group=${WPAGroup:-wheel}" >> "$config_file" + [[ $Country ]] && echo "country=$Country" >> "$config_file" + if is_yes "${AdHoc:-no}"; then + echo "ap_scan=2" >> "$config_file" + fi + echo "$config_file" +} + +## Generate a network block for wpa_supplicant +# $Security: type of wireless security +wpa_make_config_block() { + case $Security in + none|wep|wpa) + echo "ssid=$(wpa_quote "$ESSID")" + [[ $AP ]] && echo "bssid=${AP,,}" + is_yes "${AdHoc:-no}" && echo "mode=1" ;; - wpa-configsection) - echo "$CONFIGSECTION" + wpa-configsection) + printf "%s\n" "${WPAConfigSection[@]}" + return ;; - *) + *) + report_error "Unsupported security setting: '$Security'" return 1 ;; esac # Key management - case $SECURITY in - none) + case $Security in + none) echo "key_mgmt=NONE" ;; - wep) + wep) echo "key_mgmt=NONE" echo "wep_tx_keyidx=0" - if [[ ${KEY:0:2} == "s:" ]]; then # TODO: does wpa_supplicant handle this as expected? - echo "wep_key0=\"${KEY:2}\"" - else - echo "wep_key0=$KEY" - fi + echo "wep_key0=$(wpa_quote "$Key")" ;; - wpa) + wpa) echo "proto=RSN WPA" - if [[ "${#KEY}" -eq 64 ]]; then - echo "psk=$KEY" + if [[ "${#Key}" -eq 64 ]]; then + echo "psk=$Key" else - echo "psk=\"$KEY\"" + echo "psk=$(wpa_quote "$Key")" fi ;; esac # Hidden SSID - if checkyesno ${HIDDEN:-no}; then - echo "scan_ssid=1" - fi + is_yes "${Hidden:-no}" && echo "scan_ssid=1" # Priority group for the network - if [[ -n "$PRIORITY" ]]; then - echo "priority=$PRIORITY" - fi + [[ $Priority ]] && echo "priority=$Priority" } -# vim: ft=sh ts=4 et sw=4 tw=0: + +# vim: ft=sh ts=4 et sw=4: diff --git a/src/lib/auto.action b/src/lib/auto.action index 1f29364..00a4d14 100755 --- a/src/lib/auto.action +++ b/src/lib/auto.action @@ -1,56 +1,57 @@ #! /bin/bash +. /usr/lib/network/globals +. "$SUBR_DIR/ip" + interface="$1" ssid="$2" profile="$3" action="$4" +PROFILE_FILE="$STATE_DIR/wpa_actiond_$interface.profile" -. /usr/lib/network/network +# Is it possible that we don't get a profile?! [[ "$profile" ]] && load_profile "$profile" +# TODO: copy some from 'network' case $action in - CONNECT) - if [[ -z $profile ]]; then - # Load interface specific config - [[ -f "$IFACE_DIR/$interface" ]] && source "$IFACE_DIR/$interface" - dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" -K $DHCP_OPTIONS "$interface" - exit $? - fi - if ! DHCPCD_INTERNAL_OPTIONS="-K" $CONN_DIR/ethernet up "$profile"; then - exit 1 # what to do if fail? - fi - - set_profile up "$profile" - - if ! ( eval $POST_UP ); then # JP: sandbox the eval - # failing POST_UP will take interface down - "$CONN_DIR/$ethernet" down "$profile" - exit 1 - fi - ;; - DISCONNECT) - if [[ -z $profile ]]; then - dhcpcd -k "$interface" - exit $? + CONNECT) + if [[ -z $profile ]]; then + if [[ -x "$PROFILE_DIR/interfaces/$interface" ]]; then + source "$PROFILE_DIR/interfaces/$interface" fi - if ! ( eval $PRE_DOWN ); then # JP: sandbox the eval - exit 1 - fi - if ! "$CONN_DIR/ethernet" down "$profile"; then - exit 1 - fi - if ! ( eval $POST_DOWN ); then # JP: sandbox the eval - exit 1 - fi - set_profile down "$profile" - ;; - LOST|REESTABLISHED) - # Not handled. - exit 0 - ;; - *) - # ??? + dhcpcd -qL -t "${TimeoutDHCP:-10}" $DHCPOptions -K "$interface" + exit $? + fi + DHCPOptions+=" -K" + ip_set || exit 1 + printf "%s" "$profile" > "$PROFILE_FILE" + # JP: sandbox the eval + if ! ( eval $ExecUpPost ); then + # Failing ExecUpPost will take the connection down + netctl-auto stop "$interface" exit 1 - ;; + fi + ;; + DISCONNECT) + if [[ -z $profile ]]; then + dhcpcd -k "$interface" + exit $? + fi + # JP: sandbox the eval + if ! ( eval $ExecDownPre ); then + exit 1 + fi + ip_unset && rm -f "$PROFILE_FILE" + ;; + LOST|REESTABLISHED) + # Not handled. + exit 0 + ;; + *) + # ??? + exit 1 + ;; esac + +# vim: ft=sh ts=4 et sw=4: diff --git a/src/lib/connections/bond b/src/lib/connections/bond index bc5aa95..09e51c6 100644 --- a/src/lib/connections/bond +++ b/src/lib/connections/bond @@ -1,40 +1,35 @@ -#! /bin/bash -. /usr/lib/network/network +# Contributed by: Byron Williams + +. "$SUBR_DIR/ip" + IFENSLAVE="/sbin/ifenslave" bond_up() { - load_profile "$1" - - if [[ -e "/sys/class/net/$INTERFACE" ]]; then - report_fail "Interface $INTERFACE already exists." - exit 1 + if is_interface "$Interface"; then + report_error "Interface '$Interface' already exists" + return 1 else - ip link add dev $INTERFACE type bond + ip link add dev "$Interface" type bond fi - bring_interface up "$INTERFACE" + bring_interface_up "$Interface" - for slave in "${SLAVE_INTERFACES[@]}"; do - bring_interface up "$slave" - $IFENSLAVE $INTERFACE $slave + for slave in "${BindsToInterfaces[@]}"; do + bring_interface_up "$slave" + $IFENSLAVE "$Interface" "$slave" done - "$CONN_DIR/ethernet" up "$1" - return 0 + ip_set } bond_down() { - load_profile "$1" - - for slave in "${SLAVE_INTERFACES[@]}"; do - $IFENSLAVE $INTERFACE -d $slave + for slave in "${BindsToInterfaces[@]}"; do + $IFENSLAVE "$Interface" -d "$slave" done - "$CONN_DIR/ethernet" down "$1" - ip link delete "$INTERFACE" - return 0 + ip_unset + bring_interface_down "$Interface" + ip link delete "$Interface" } -bond_$1 "$2" -exit $? # vim: set ts=4 et sw=4: diff --git a/src/lib/connections/bridge b/src/lib/connections/bridge index 6b3ab67..929a76b 100644 --- a/src/lib/connections/bridge +++ b/src/lib/connections/bridge @@ -1,47 +1,42 @@ -#! /bin/bash -. /usr/lib/network/network +# Contributed by: Thomas Bächler + +. "$SUBR_DIR/ip" + BRCTL="/usr/sbin/brctl" bridge_up() { - local bridge_interface - load_profile "$1" - - if [[ -e "/sys/class/net/$INTERFACE" ]]; then - if [[ ! -d "/sys/class/net/$INTERFACE/brif" ]]; then - report_fail "Interface $INTERFACE already exists and is not a bridge." - exit 1 + if is_interface "$Interface"; then + if [[ ! -d "/sys/class/net/$Interface/brif" ]]; then + report_error "Interface '$Interface' already exists and is not a bridge" + return 1 fi else - $BRCTL addbr "$INTERFACE" + $BRCTL addbr "$Interface" fi - for bridge_client in $BRIDGE_INTERFACES; do - ip link set "$bridge_client" promisc on up - ip addr flush dev "$bridge_client" - $BRCTL addif "$INTERFACE" "$bridge_client" + for member in "${BindsToInterfaces[@]}"; do + ip link set "$member" promisc on up + ip addr flush dev "$member" + $BRCTL addif "$Interface" "$member" done # Set options - [[ "$FWD_DELAY" ]] && $BRCTL setfd "$INTERFACE" "$FWD_DELAY" - [[ "$MAX_AGE" ]] && $BRCTL setmaxage "$INTERFACE" "$MAX_AGE" + [[ "$FwdDelay" ]] && $BRCTL setfd "$Interface" "$FwdDelay" + [[ "$MaxAge" ]] && $BRCTL setmaxage "$Interface" "$MaxAge" - "$CONN_DIR/ethernet" up "$1" - return 0 + bring_interface_up "$Interface" + ip_set } bridge_down() { - local bridge_interface - load_profile "$1" - - for bridge_client in $BRIDGE_INTERFACES; do - ip link set "$bridge_client" promisc off down - $BRCTL delif "$INTERFACE" "$bridge_client" + for member in "${BindsToInterfaces[@]}"; do + ip link set "$member" promisc off down + $BRCTL delif "$Interface" "$member" done - "$CONN_DIR/ethernet" down "$1" - $BRCTL delbr "$INTERFACE" - return 0 + ip_unset + bring_interface_down "$Interface" + $BRCTL delbr "$Interface" } -bridge_$1 "$2" -exit $? + # vim: set ts=4 et sw=4: diff --git a/src/lib/connections/ethernet b/src/lib/connections/ethernet index 487adf8..0fff668 100644 --- a/src/lib/connections/ethernet +++ b/src/lib/connections/ethernet @@ -1,279 +1,75 @@ -#! /bin/bash -# Source file for the 'ethernet' connection -# ethernet_up $profile -# ethernet_down $profile -# ethernet_status +# Ethernet connection support for netctl -. /usr/lib/network/network +. "$SUBR_DIR/ip" -report_iproute() -{ - report_fail "$*" - bring_interface down "$INTERFACE" - exit 1 -} ethernet_up() { - load_profile "$1" - SYSCTL_INTERFACE="${INTERFACE/.//}" - - if ! is_interface "$INTERFACE"; then - report_iproute "Interface $INTERFACE does not exist" + if ! is_interface "$Interface"; then + report_error "Interface '$Interface' does not exist" + return 1 fi # Disable IPv6 before bringing the interface up to prevent SLAAC - if [[ "$IP6" == "no" ]]; then - sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.disable_ipv6=1" + if [[ $IP6 == "no" ]]; then + sysctl -q -w "net.ipv6.conf.${Interface/.//}.disable_ipv6=1" fi - report_debug ethernet_up bring_interface up "$INTERFACE" - bring_interface up "$INTERFACE" + if ! bring_interface_up "$Interface"; then + report_error "Failed to bring interface '$Interface' up" + return 1 + fi - if ! checkyesno "${SKIPNOCARRIER:-no}"; then + if ! is_yes "${SkipNoCarrier:-no}"; then # Some cards are plain slow to come up. Don't fail immediately. - if ! timeout_wait "${CARRIER_TIMEOUT:-5}" '(( $(< "/sys/class/net/$INTERFACE/carrier") ))'; then - report_iproute "No connection" + if ! timeout_wait "${TimeoutCarrier:-5}" '(( $(< "/sys/class/net/$Interface/carrier") ))'; then + report_error "No connection on interface '$Interface'" + bring_interface_down "$Interface" + return 1 fi fi - if checkyesno "${AUTH8021X:-no}"; then + if is_yes "${Auth8021X:-no}"; then . "$SUBR_DIR/8021x" - [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf" - [[ -z "$WPA_DRIVER" ]] && WPA_DRIVER="wired" + : ${WPAConfigFile:=/etc/wpa_supplicant.conf} + : ${WPADriver:=wired} + : ${TimeoutWPA:=15} - report_debug ethernet_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS" - if ! start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"; then - report_fail "wpa_supplicant did not start, possible configuration error" + if ! wpa_start "$Interface" "$WPADriver" "$WPAConfigFile"; then + report_error "The WPA supplicant did not start for interface '$Interface'" + bring_interface_down "$Interface" return 1 fi - if ! wpa_check "$INTERFACE" "$TIMEOUT" "ASSOCIATED"; then - bring_interface down "$INTERFACE" - report_fail "WPA Authentication/Association Failed" + if ! wpa_wait_until_state "$TimeoutWPA" "$Interface" "ASSOCIATED"; then + wpa_stop "$Interface" + bring_interface_down "$Interface" + report_error "WPA Authentication/Association Failed" return 1 fi fi - if [[ -z "$IP" && -z "$IP6" ]]; then - report_iproute "At least one of IP or IP6 should be specified" + if ! ip_set; then + stop_80211x + bring_interface_down "$Interface" return 1 fi - - case "$IP" in - dhcp) - if checkyesno "${DHCLIENT:-no}"; then - rm -r "/run/dhclient-${INTERFACE}.pid" >/dev/null 2>&1 - report_debug ethernet_up dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf "/run/dhclient-$INTERFACE.pid" "$INTERFACE" - if ! dhclient -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf "/run/dhclient-${INTERFACE}.pid" ${DHCLIENT_OPTIONS} "$INTERFACE"; then - report_fail "DHCP IP lease attempt failed." - stop_80211x - return 1 - fi - else - # Clear remaining pid files. - rm -f "/run/dhcpcd-$INTERFACE".{pid,cache} >/dev/null 2>&1 - # If using own dns, tell dhcpcd to NOT replace resolv.conf - [[ -n "$DNS" ]] && DHCP_OPTIONS="-C resolv.conf $DHCP_OPTIONS" - # Start dhcpcd - report_debug ethernet_up dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCPCD_INTERNAL_OPTIONS $DHCP_OPTIONS "$INTERFACE" - dhcpcd -qL -t "${DHCP_TIMEOUT:-10}" $DHCPCD_INTERNAL_OPTIONS $DHCP_OPTIONS "$INTERFACE" 2>&1 | report_debug "$(cat)" - if [[ "$PIPESTATUS" -ne 0 ]]; then - report_fail "DHCP IP lease attempt failed." - stop_80211x - return 1 - fi - fi - ;; - static) - if [[ -n "$ADDR" ]]; then - [[ -z $NETMASK ]] && NETMASK=24 - report_debug ethernet_up ip addr add "$ADDR/$NETMASK" brd + dev "$INTERFACE" - if ! ip addr add "$ADDR/$NETMASK" brd + dev "$INTERFACE"; then - report_iproute "Could not configure interface" - fi - fi - if [[ -n "$GATEWAY" ]]; then - report_debug ethernet_up ip route add default via "$GATEWAY" dev "$INTERFACE" - if ! ip route add default via "$GATEWAY" dev "$INTERFACE"; then - report_iproute "Adding gateway $GATEWAY failed" - fi - fi - ;; - ""|no) - ;; - *) - report_iproute "IP must be either 'dhcp', 'static' or 'no'" - ;; - esac - - if [[ -n "$IP" && -n "$ROUTES" ]]; then - for route in "${ROUTES[@]}"; do - report_debug ethernet_up ip route add $route dev "$INTERFACE" - if ! ip route add $route dev "$INTERFACE"; then - report_iproute "Adding route '$route' failed" - fi - done - fi - - # Load ipv6 module if necessary (FS#25530) - case "$IP6" in - dhcp*|stateless|static) - [[ -d "/proc/sys/net/ipv6" ]] || modprobe ipv6 - ;; - no) - [[ -d "/proc/sys/net/ipv6" ]] && sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=0" - ;; - "") # undefined IP6 does not prevent RA's from being received -> nop - ;; - *) - report_iproute "IP6 must be 'dhcp', 'dhcp-noaddr', 'stateless', 'static' or 'no'" - ;; - esac - - case "$IP6" in - dhcp*) - if ! type dhclient &>/dev/null; then - report_fail "You need to install dhclient to use DHCPv6." - stop_80211x - return 1 - fi - sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=1" - if [[ "$IP6" == "dhcp-noaddr" ]]; then - DHCLIENT6_OPTIONS="-S ${DHCLIENT6_OPTIONS}" - fi - _DHCLIENT_PIDFILE="/run/dhclient6-${INTERFACE}.pid" - rm -r ${_DHCLIENT_PIDFILE} &>/dev/null - report_debug ethernet_up dhclient -6 -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf ${_DHCLIENT_PIDFILE} "$INTERFACE" - if ! dhclient -6 -q -e TIMEOUT="${DHCP_TIMEOUT:-10}" -pf ${_DHCLIENT_PIDFILE} ${DHCLIENT6_OPTIONS} "$INTERFACE"; then - report_fail "DHCPv6 IP lease attempt failed." - stop_80211x - return 1 - fi - ;; - stateless) - sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=1" - ;; - static) - sysctl -q -w "net.ipv6.conf.$SYSCTL_INTERFACE.accept_ra=0" - if [[ -n "$ADDR6" ]]; then - for addr in "${ADDR6[@]}"; do - report_debug ethernet_up ip -6 addr add $addr dev "$INTERFACE" - if ! ip -6 addr add $addr dev "$INTERFACE"; then - report_iproute "Could not add address '$addr' to interface" - fi - done - fi - ;; - esac - - if [[ -n "$IP6" ]]; then - # Wait for DAD to finish (FS#28887) - report_debug ethernet_up ip -6 addr show dev "$INTERFACE" tentative - if ! timeout_wait "${DAD_TIMEOUT:-3}" '[[ -z "$(ip -6 addr show dev "$INTERFACE" tentative)" ]]'; then - report_iproute "Duplicate Address Detection is taking too long" - fi - - # Add static IPv6 routes - if [[ -n "$ROUTES6" ]]; then - for route in "${ROUTES6[@]}"; do - report_debug ethernet_up ip -6 route add $route dev "$INTERFACE" - if ! ip -6 route add $route dev "$INTERFACE"; then - report_iproute "Adding route '$route' failed" - fi - done - fi - - # Set a custom gateway after waiting for DAD to finish - if [[ "$IP6" == "static" && -n "$GATEWAY6" ]]; then - report_debug ethernet_up ip -6 route replace default via "$GATEWAY6" dev "$INTERFACE" - if ! ip -6 route replace default via "$GATEWAY6" dev "$INTERFACE"; then - report_iproute "Adding gateway $GATEWAY6 failed" - fi - fi - fi - - if [[ -n "$IPCFG" ]]; then - for line in "${IPCFG[@]}"; do - report_debug ethernet_up ip "$line" - if ! ip $line; then - report_iproute "Could not configure interface ($line)." - fi - done - fi - - # Set hostname - if [[ -n "$HOSTNAME" ]]; then - report_debug ethernet_up hostname "$HOSTNAME" - if ! echo "$HOSTNAME" >/proc/sys/kernel/hostname; then - report_iproute "Cannot set hostname to $HOSTNAME" - fi - fi - - # Generate a new resolv.conf - if [[ -n "$DNS" ]]; then - : >/etc/resolv.conf - [[ -n "$DOMAIN" ]] && echo "domain $DOMAIN" >>/etc/resolv.conf - [[ -n "$SEARCH" ]] && echo "search $SEARCH" >>/etc/resolv.conf - for dns in "${DNS[@]}"; do - echo "nameserver $dns" >>/etc/resolv.conf - done - for dnsoption in "${DNS_OPTIONS[@]}"; do - echo "options $dnsoption" >>/etc/resolv.conf - done - fi - - return 0 } ethernet_down() { - load_profile "$1" - - if [[ "$IP" == "dhcp" ]]; then - if checkyesno "${DHCLIENT:-no}"; then - if [[ -f "/run/dhclient-$INTERFACE.pid" ]]; then - report_debug ethernet_down dhclient -q -x "$INTERFACE" -pf "/run/dhclient-$INTERFACE.pid" - dhclient -q -x "$INTERFACE" -pf "/run/dhclient-$INTERFACE.pid" &>/dev/null - #dhclient -q -r "$INTERFACE" &>/dev/null - fi - else - if [[ -f "/run/dhcpcd-$INTERFACE.pid" ]]; then - report_debug ethernet_down dhcpcd -qk "$INTERFACE" - dhcpcd -qk "$INTERFACE" &>/dev/null - fi - fi - fi - if [[ "$IP6" == dhcp* ]]; then - if [[ -f "/run/dhclient6-$INTERFACE.pid" ]]; then - report_debug ethernet_down dhclient -6 -q -x "$INTERFACE" -pf "/run/dhclient6-$INTERFACE.pid" - dhclient -6 -q -x "$INTERFACE" -pf "/run/dhclient6-$INTERFACE.pid" &>/dev/null - report_debug ethernet_down /bin/kill $(< /run/dhclient6-$INTERFACE.pid) - /bin/kill $(< /run/dhclient6-$INTERFACE.pid) &>/dev/null - fi - fi - + ip_unset stop_80211x - - if [[ "$CONNECTION" == "wireless" ]]; then - report_debug ethernet_down bring_interface flush "$INTERFACE" - bring_interface flush "$INTERFACE" - else - report_debug ethernet_down bring_interface down "$INTERFACE" - bring_interface down "$INTERFACE" - fi - return 0 + bring_interface_down "$Interface" } # Stop wpa_supplicant if neccessary stop_80211x() { - if checkyesno "${AUTH8021X:-no}"; then + if is_yes "${Auth8021X:-no}"; then . "$SUBR_DIR/8021x" - [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf" - report_debug ethernet_down stop_wpa "$INTERFACE" - stop_wpa "$INTERFACE" + : ${WPAConfigFile:=/etc/wpa_supplicant.conf} + do_debug wpa_stop "$Interface" fi } -ethernet_$1 "$2" -exit $? + # vim: set ts=4 et sw=4: diff --git a/src/lib/connections/pppoe b/src/lib/connections/pppoe index 17fe42d..b24b503 100644 --- a/src/lib/connections/pppoe +++ b/src/lib/connections/pppoe @@ -1,5 +1,4 @@ -#! /bin/bash -. /usr/lib/network/network +# Contributed by: Thomas Bächler _quotestring() { echo "\"${1/\"/\\\"}\"" @@ -7,60 +6,58 @@ _quotestring() { pppoe_up() { local cfg - load_profile "$1" - mkdir -p "$STATE_DIR/pppoe.${INTERFACE}.$1/" - chmod 700 "$STATE_DIR/pppoe.${INTERFACE}.$1/" - cfg="$STATE_DIR/pppoe.${INTERFACE}.$1/options" + mkdir -p "$STATE_DIR/pppoe.${Interface}.$1/" + chmod 700 "$STATE_DIR/pppoe.${Interface}.${Profile}/" + cfg="$STATE_DIR/pppoe.${Interface}.${Profile}/options" : > "${cfg}" chmod 600 "${cfg}" echo "plugin rp-pppoe.so" >> "${cfg}" - echo "nic-${INTERFACE}" >> "${cfg}" + echo "nic-${Interface}" >> "${cfg}" echo "noauth" >> "${cfg}" - if checkyesno ${DEFAULTROUTE:-1}; then + if is_yes "${DefaultRoute:-yes}"; then echo "defaultroute" >> "${cfg}" else echo "nodefaultroute" >> "${cfg}" fi - if checkyesno ${USEPEERDNS:-1}; then + if is_yes "${UsePeerDNS:-yes}"; then echo "usepeerdns" >> "${cfg}" fi - echo "linkname $(_quotestring "$1")" >> "${cfg}" + echo "linkname $(_quotestring "${Profile}")" >> "${cfg}" echo "maxfail 5" >> "${cfg}" echo "updetach" >> "${cfg}" - if [[ ${CONNECTION_MODE} == demand ]]; then + if [[ ${ConnectionMode} == demand ]]; then echo "demand" >> "${cfg}" - echo "idle ${IDLE_TIMEOUT}" >> "${cfg}" + echo "idle ${IdleTimeout}" >> "${cfg}" else echo "persist" >> "${cfg}" fi - echo "user $(_quotestring "${USER}")" >> "${cfg}" - echo "password $(_quotestring "${PASSWORD}")" >> "${cfg}" - [[ -n ${LCP_ECHO_INTERVAL} ]] && echo "lcp-echo-interval ${LCP_ECHO_INTERVAL}" >> "${cfg}" - [[ -n ${LCP_ECHO_FAILURE} ]] && echo "lcp-echo-failure ${LCP_ECHO_FAILURE}" >> "${cfg}" - [[ -n ${PPPOE_SERVICE} ]] && echo "rp_pppoe_service $(_quotestring "${PPPOE_SERVICE}")" >> "${cfg}" - [[ -n ${PPPOE_AC} ]] && echo "rp_pppoe_ac $(_quotestring "${PPPOE_AC}")" >> "${cfg}" - [[ -n ${PPPOE_SESSION} ]] && echo "rp_pppoe_sess $(_quotestring "${PPPOE_SESSION}")" >> "${cfg}" - [[ -n ${PPPOE_MAC} ]] && echo "pppoe-mac $(_quotestring "${PPPOE_MAC}")" >> "${cfg}" - [[ ${PPPOE_IP6} == yes ]] && echo "+ipv6" >> "${cfg}" + echo "user $(_quotestring "${User}")" >> "${cfg}" + echo "password $(_quotestring "${Password}")" >> "${cfg}" + [[ -n ${LCPEchoInterval} ]] && echo "lcp-echo-interval ${LCPEchoInterval}" >> "${cfg}" + [[ -n ${LCPEchoFailure} ]] && echo "lcp-echo-failure ${LCPEchoFailure}" >> "${cfg}" + [[ -n ${PPPoEService} ]] && echo "rp_pppoe_service $(_quotestring "${PPPoEService}")" >> "${cfg}" + [[ -n ${PPPoEAC} ]] && echo "rp_pppoe_ac $(_quotestring "${PPPoEAC}")" >> "${cfg}" + [[ -n ${PPPoESession} ]] && echo "rp_pppoe_sess $(_quotestring "${PPPoESession}")" >> "${cfg}" + [[ -n ${PPPoEMAC} ]] && echo "pppoe-mac $(_quotestring "${PPPoEMAC}")" >> "${cfg}" + [[ ${PPPoEIP6} == yes ]] && echo "+ipv6" >> "${cfg}" - /sbin/ip link set dev "${INTERFACE}" up + /sbin/ip link set dev "${Interface}" up /usr/sbin/pppd file "${cfg}" if [[ $? -ne 0 ]]; then rm "${cfg}" - rmdir "$STATE_DIR/pppoe.${INTERFACE}.$1/" - report_fail "Couldn't make pppd connection." + rmdir "$STATE_DIR/pppoe.${Interface}.${Profile}/" + report_error "Couldn't make pppd connection." return 1 fi } pppoe_down() { - load_profile "$1" local cfg - cfg="$STATE_DIR/pppoe.${INTERFACE}.$1/options" - PIDFILE="/var/run/ppp-$1.pid" + cfg="$STATE_DIR/pppoe.${Interface}.${Profile}/options" + PIDFILE="/var/run/ppp-${Profile}.pid" if [[ -e $PIDFILE ]]; then read PID < "$PIDFILE" @@ -68,10 +65,8 @@ pppoe_down() { fi rm "${cfg}" - rmdir "$STATE_DIR/pppoe.${INTERFACE}.$1/" + rmdir "$STATE_DIR/pppoe.${Interface}.${Profile}/" } -pppoe_$1 "$2" -exit $? # vim: ft=sh ts=4 et sw=4: diff --git a/src/lib/connections/tunnel b/src/lib/connections/tunnel index 6cefc5c..f202371 100644 --- a/src/lib/connections/tunnel +++ b/src/lib/connections/tunnel @@ -1,34 +1,28 @@ -#! /bin/bash -. /usr/lib/network/network +# Contributed by: Kyle Fuller -tunnel_up() { - load_profile "$1" +. "$SUBR_DIR/ip" - if [[ -e "/sys/class/net/$INTERFACE" ]]; then - report_fail "Interface $INTERFACE already exists." - exit 1 +tunnel_up() { + if is_interface "$Interface"; then + report_error "Interface '$Interface' already exists" + return 1 else - ip tunnel add "$INTERFACE" mode "$MODE" remote "$REMOTE" + ip tunnel add "$Interface" mode "$Mode" remote "$Remote" fi - if [[ -n "$LOCAL" ]]; then - ip tunnel change "$INTERFACE" local "$LOCAL" + if [[ -n "$Local" ]]; then + ip tunnel change "$Interface" local "$Local" fi - "$CONN_DIR/ethernet" up "$1" - return 0 + bring_interface_up "$Interface" + ip_set } tunnel_down() { - load_profile "$1" - - "$CONN_DIR/ethernet" down "$1" - ip tunnel del "$INTERFACE" - - return 0 + ip_unset + bring_interface_down "$Interface" + ip tunnel del "$Interface" } -tunnel_$1 "$2" -exit $? # vim: set ts=4 et sw=4: diff --git a/src/lib/connections/tuntap b/src/lib/connections/tuntap index 6985c8c..1ff5203 100644 --- a/src/lib/connections/tuntap +++ b/src/lib/connections/tuntap @@ -1,28 +1,24 @@ -#! /bin/bash -. /usr/lib/network/network +# Contributed by: Rémy Oudompheng -tuntap_up() { - load_profile "$1" +. "$SUBR_DIR/ip" - if [[ -e /sys/class/net/$INTERFACE ]]; then - report_fail "Interface $INTERFACE already exists." - exit 1 +tuntap_up() { + if is_interface "$Interface"; then + report_error "Interface '$Interface' already exists" + return 1 else - ip tuntap add dev "$INTERFACE" mode "$MODE" \ - user "$USER" group "$GROUP" + ip tuntap add dev "$Interface" mode "$Mode" \ + user "$User" group "$Group" fi - IP=${IP-no} "$CONN_DIR/ethernet" up "$1" - return 0 + bring_interface_up "$Interface" + IP=${IP-no} ip_set } tuntap_down() { - load_profile "$1" - - "$CONN_DIR/ethernet" down "$1" - ip tuntap del dev "$INTERFACE" mode "$MODE" - return 0 + ip_unset + bring_interface_down "$Interface" + ip tuntap del dev "$Interface" mode "$Mode" } -tuntap_$1 "$2" -exit $? + # vim: set ts=4 et sw=4 tw=0: diff --git a/src/lib/connections/vlan b/src/lib/connections/vlan index 75c7fa9..86d1a2d 100644 --- a/src/lib/connections/vlan +++ b/src/lib/connections/vlan @@ -1,28 +1,26 @@ -#! /bin/bash -. /usr/lib/network/network +# Contributed by: Thomas S Hatch -vlan_up() { - load_profile "$1" +. "$CONN_DIR/ethernet" - if [[ -e "/sys/class/net/$INTERFACE" ]]; then - report_fail "Interface $INTERFACE already exists." - exit 1 +vlan_up() { + if [[ ${#BindsToInterfaces} -ne 1 ]]; then + report_error "No unique physical device for VLAN interface '$Interface' specified" + return 1 + fi + if is_interface "$Interface"; then + report_error "Interface '$Interface' already exists" + return 1 else - bring_interface up "$VLAN_PHYS_DEV" - ip link add link "$VLAN_PHYS_DEV" name "$INTERFACE" type vlan id "$VLAN_ID" + bring_interface_up "$BindsToInterfaces" + ip link add link "$BindsToInterfaces" name "$Interface" type vlan id "$VLANID" fi - "$CONN_DIR/ethernet" up "$1" - return 0 + + ethernet_up } vlan_down() { - load_profile "$1" - - "$CONN_DIR/ethernet" down "$1" - ip link delete "$INTERFACE" - return 0 + ethernet_down + ip link delete "$Interface" } -vlan_$1 "$2" -exit $? # vim: set ts=4 et sw=4: diff --git a/src/lib/connections/wireless b/src/lib/connections/wireless index 135bec7..a3b324b 100644 --- a/src/lib/connections/wireless +++ b/src/lib/connections/wireless @@ -1,116 +1,89 @@ -#! /bin/bash -. /usr/lib/network/network +# Wireless connection support for netctl + . "$SUBR_DIR/8021x" +. "$SUBR_DIR/ip" . "$SUBR_DIR/rfkill" -wireless_up() { - PROFILE="$1" - load_profile "$PROFILE" - # Default settings - SECURITY=${SECURITY:-none} - WPA_DRIVER=${WPA_DRIVER:-nl80211,wext} +wireless_up() { + local config_file - enable_rf $INTERFACE $RFKILL $RFKILL_NAME || return 1 + if ! is_interface "$Interface"; then + report_error "Interface '$Interface' does not exist" + return 1 + fi - # Check if interface exists - is_interface "$INTERFACE" || { report_fail "interface $INTERFACE does not exist"; return 1; } + # Default settings + : ${Security:=none} + : ${WPADriver:=nl80211,wext} + : ${TimeoutWPA:=15} + + if [[ $RFKill ]]; then + enable_rf "$Interface" "$RFKill" || return 1 + fi - # Kill any lingering wpa_supplicants. - stop_wpa "$INTERFACE" &> /dev/null + # Kill any lingering WPA supplicants + WPAConfigFile= wpa_stop "$Interface" &> /dev/null - # Start wpa_supplicant - if [[ "$SECURITY" = "wpa-config" ]]; then - WPA_CONF="${WPA_CONF:-/etc/wpa_supplicant.conf}" + if [[ $Security == "wpa-config" ]]; then + : ${WPAConfigFile:=/etc/wpa_supplicant.conf} + config_file=$WPAConfigFile else - WPA_CONF=$(make_wpa_config_file $INTERFACE) + config_file=$(wpa_make_config_file "$Interface") + if [[ -z $config_file ]]; then + report_error "Could not create a wpa config file for interface '$Interface'" + bring_interface_down "$Interface" + return 1 + fi + printf "%s\n" "network={" "$(wpa_make_config_block)" "}" >> "$config_file" fi - report_debug wireless_up start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS" - if ! start_wpa "$INTERFACE" "$WPA_CONF" "$WPA_DRIVER" "$WPA_OPTS"; then - report_fail "wpa_supplicant did not start, possible configuration error" + + # Start the WPA supplicant + if ! do_debug wpa_start "$Interface" "$WPADriver" "$config_file"; then + report_error "The WPA supplicant did not start for interface '$Interface'" + bring_interface_down "$Interface" return 1 fi - # Scan for network's existence first - if checkyesno "${SCAN:-no}"; then - report_debug wireless_up scanning - local OLDESSID="$ESSID" - if [[ -n "$AP" ]]; then - BSSID=$(wpa_find_ap "$INTERFACE" "$AP") - else - ESSID=$(wpa_find_essid "$INTERFACE" "$ESSID") - fi - if [[ $? -gt 0 ]]; then - report_fail "Wireless network \"$OLDESSID\" not present." - report_debug wireless_up stop_wpa "$INTERFACE" - stop_wpa "$INTERFACE" + if is_yes "${Scan:-no}"; then + if ! wpa_wait_while_state "$TimeoutWPA" "$Interface" "DISCONNECTED" "SCANNING"; then + report_error "Wireless network '$ESSID' (or access point) not present" + wpa_stop "$Interface" + bring_interface_down "$interface" return 1 fi fi - - # Build configuration file - case "$SECURITY" in - wpa-config) - ;; - none|wep|wpa|wpa-configsection) - printf "%s\n" "network={" "$(make_wpa_config)" "}" >> "$WPA_CONF" - report_debug wireless_up "Configuration generated at $WPA_CONF" - report_debug wireless_up wpa_reconfigure "$INTERFACE" - if ! wpa_reconfigure "$INTERFACE"; then - report_fail "WPA configuration failed!" - stop_wpa "$INTERFACE" - return 1 - fi - ;; - *) - report_fail "Invalid SECURITY setting: $SECURITY" - ;; - esac - + # Bring interface up after starting wpa_supplicant # This is important since cards such as iwl3945 do not support # mode switching when they are already up. - report_debug wireless_up ifup - bring_interface up "$INTERFACE" || return 1 + bring_interface_up "$Interface" || return 1 - report_debug wireless_up wpa_check - if ! wpa_check "$INTERFACE" "$TIMEOUT"; then - report_fail "WPA Authentication/Association Failed" + if ! wpa_wait_until_state "$TimeoutWPA" "$Interface" "COMPLETED"; then + report_error "WPA association/authentication failed for interface '$Interface'" + wpa_stop "$Interface" + bring_interface_down "$Interface" return 1 fi - if ! "$CONN_DIR/ethernet" up "$PROFILE"; then - wireless_down "$PROFILE" YES + if ! ip_set; then + wpa_stop "$Interface" + bring_interface_down "$Interface" return 1 fi } -# wireless_down PROFILE [ LEAVE ifconfig up? default no ] wireless_down() { - local PROFILE="$1" - load_profile "$PROFILE" - - "$CONN_DIR/ethernet" down "$PROFILE" - - # The config file can contain a non-standard control socket path - if [[ "$SECURITY" = "wpa-config" ]]; then - WPA_CONF="${WPA_CONF:-/etc/wpa_supplicant.conf}" + ip_unset + if [[ $Security == "wpa-config" ]]; then + : ${WPAConfigFile:=/etc/wpa_supplicant.conf} fi - report_debug wireless_down stop_wpa "$INTERFACE" - stop_wpa "$INTERFACE" - rm -rf "$STATE_DIR/wpa.$INTERFACE" - - bring_interface down "$INTERFACE" - - # Handle wireless kill switches - # Any reason why a hardware switch should be considered on interface down? - if [[ "$RFKILL" == "soft" ]]; then - set_rf_state "$INTERFACE" disabled $RFKILL_NAME || return 1 + wpa_stop "$Interface" + bring_interface_down "$Interface" || return 1 + if [[ $RFKill ]]; then + disable_rf "$Interface" "$RFKill" fi } -wireless_$1 "$2" "$3" -exit $? # vim: ft=sh ts=4 et sw=4 tw=0: - diff --git a/src/lib/globals b/src/lib/globals index 491f9d6..8277a40 100644 --- a/src/lib/globals +++ b/src/lib/globals @@ -1,136 +1,121 @@ -# /usr/lib/networks/globals -# -# All +x files in /usr/lib/network/hooks will be sourced when this file is. -# Hook files can override any of the utility functions defined here for custom -# behavior (such as logging error messages to syslog). This lets us keep netcfg -# simple but gives it the flexibility for users to make modular use of it to do -# more complex things - - -### Globals PROFILE_DIR="/etc/network.d" -IFACE_DIR="$PROFILE_DIR/interfaces" SUBR_DIR="/usr/lib/network" -HOOKS_DIR="$SUBR_DIR/hooks" CONN_DIR="$SUBR_DIR/connections" STATE_DIR="/run/network" - +STATE_FILE="${NETCTL_STATE_FILE:-/var/lib/netctl/netctl.state}" ### Logging/Error reporting -function report_err { +report_notice() { echo "$*" } -function report_notice { +report_error() { echo "$*" } -function report_debug { - checkyesno "$NETCFG_DEBUG" && echo "DEBUG: $*" >&2 +report_debug() { + is_yes "${NETCTL_DEBUG:-no}" && echo "DEBUG: $*" >&2 } -function report_try { - # This needs -n and a trailing space. - echo -n ":: $* " - REPORT_TRYING=1 +exit_error() { + report_error "$@" >&2 + exit 1 } -function report_fail { - if [[ -n "$*" ]]; then - if (( REPORT_TRYING )); then - echo "- $* [fail]" - REPORT_TRYING= - else - echo "$*" - fi - elif (( REPORT_TRYING )); then - echo "[fail]" - REPORT_TRYING= - fi -} -function report_success { - if [[ -n "$*" ]]; then - # This needs -n and a trailing space. - echo -n "- $* " - fi - echo "[done]" - REPORT_TRYING= +### Variable management + +## Check if a variable occurs in an array +# $1: the variable to find +# $2...: the array elements +in_array() { + local hay needle=$1 + shift + for hay; do + [[ $hay == "$needle" ]] && return 0 + done + return 1 } -### For calling scripts only; don't use in library functions -function exit_stderr { echo "$*" >&2; exit 1; } -function exit_err { report_err "$*"; exit 1; } -function exit_fail { report_fail "$*"; exit 1; } - - -### From FreeBSD's /etc/rc.subr -## -# checkyesno var -# Test $1 variable, and warn if not set to YES or NO. -# Return 0 if it's "yes" (et al), nonzero otherwise. -# To default to yes, do: "checkyesno ${VAR:-yes}". -# -function checkyesno() { - local _value="$1" - #debug "checkyesno: $1 is set to $_value." - case "$_value" in - - # "yes", "true", "on", or "1" - [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) +## Check if a variable denotes a positive truth value +# $1: the variable to check, use is_yes ${VAR:-yes} to set a default +is_yes() { + case ${1,,} in + yes|true|on|1) return 0 ;; - - # "no", "false", "off", or "0" - [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + no|false|off|0) return 1 ;; - *) - #warn "\$${1} is not set properly - see rc.conf(5)." + *) + report_error "Not a valid truth value: '$1'" return 1 ;; esac } -## Check if variable is a member of an array -# $1: the variable to find -# $2...: the array elements -function inarray() { - local item search="$1" - shift - for item in "$@"; do - if [[ "$item" == "$search" ]]; then - return 0 - fi - done - return 1 + +### Control flow + +## Show what we evaluate when debugging, but always evaluate +do_debug() { + report_debug "${FUNCNAME[1]}:" "$@" + "$@" +} + +## Exit if we are not effectively root +# $1: program name (optional) +ensure_root() { + (( EUID == 0 )) || exit_error "${1-$0} needs root privileges" } ## Waits until a statement succeeds or a timeout occurs # $1: timeout in seconds # $2...: condition command -function timeout_wait() { - local timeout="$1" - (( timeout *= 10 )) +timeout_wait() { + local timeout=$1 + (( timeout *= 5 )) shift while ! eval "$*"; do (( timeout-- > 0 )) || return 1 - sleep 0.1 + sleep 0.2 done return 0 } -### Load all +x files in $HOOKS_DIR -function load_hooks() { +### Profile management + +## List all acceptable profiles names (assume they don't contain newlines) +list_profiles() { + # JP: follow aliases with -L, also skip profiles that end with '.conf' (so + # profile.conf can be the wpa.conf file for profile) + find -L "$PROFILE_DIR/" -maxdepth 1 -type f -not -name '.*' -not -name '*~' -not -name '*.conf' -not -name '*.service' -printf "%f\n" +} + +## Sources all hooks, a profile and any interface hook +# $1: profile name +load_profile() { local hook - for hook in $(find -L "$HOOKS_DIR/" -maxdepth 1 -type f -executable | sort -u); do + if [[ ! -r "$PROFILE_DIR/$1" ]]; then + exit_error "Profile '$1' does not exist or is not readable" + fi + while read -r hook; do source "$hook" - done + done < <(find -L "$PROFILE_DIR/hooks" -maxdepth 1 -type f -executable -not -name '.*' -not -name '*~' | sort -u) + source "$PROFILE_DIR/$1" + if [[ -z $Interface ]]; then + exit_error "Profile '$1' does not specify an interface" + fi + if [[ ! -r "$CONN_DIR/${Connection:-/dev/null/nonexistent}" ]]; then + exit_error "Profile '$1' does not specify a valid connection" + fi + if [[ -x "$PROFILE_DIR/interfaces/$Interface" ]]; then + source "$PROFILE_DIR/interfaces/$Interface" + fi } -load_hooks # vim: ft=sh ts=4 et sw=4: diff --git a/src/lib/ip b/src/lib/ip new file mode 100644 index 0000000..02d99f4 --- /dev/null +++ b/src/lib/ip @@ -0,0 +1,215 @@ +## /usr/lib/network/globals needs to be sourced before this file + + +## Add resolv.conf entries for an interface +# $1: interface name +# $2...: entries, one line per variable +resolvconf_add() { + local interface="$1" + shift + printf "%s\n" "$@" | resolvconf -a "$interface" +} + + +## Set up an IP configuration +# $Interface: interface name +# $IP: type of IPv4 configuration +# $IP6: type of IPv6 configuration +ip_set() { + local addr line route interface_sysctl=${Interface/.//} + + if [[ -z $IP && -z $IP6 ]]; then + report_error "Neither IP, nor IP6 was specified" + return 1 + fi + + case $IP in + dhcp) + case ${DHCPClient:-dhcpcd} in + dhcpcd) + rm -f "/run/dhcpcd-$Interface".{pid,cache} + # If using own dns, tell dhcpcd to NOT replace resolv.conf + [[ $DNS ]] && DhcpcdOptions+=" -C resolv.conf" + do_debug dhcpcd -qL -t "${TimeoutDHCP:-10}" $DHCPOptions "$Interface" 2>&1 | report_debug "$(cat)" + # The first array value of PIPESTATUS is the exit status of dhcpcd + if (( PIPESTATUS != 0 )); then + report_error "DHCP IP lease attempt failed on interface '$Interface'" + return 1 + fi + ;; + dhclient) + rm -f "/run/dhclient-${Interface}.pid" + if ! do_debug dhclient -q -e "TIMEOUT=${TimeoutDHCP:-10}" -pf "/run/dhclient-$Interface.pid" $DhclientOptions "$Interface"; then + report_error "DHCP IP lease attempt failed on interface '$Interface'" + return 1 + fi + ;; + *) + report_error "Unsupported DHCP client: '$DHCPClient'" + return 1 + ;; + esac + ;; + static) + if [[ $Address ]]; then + for addr in "${Address[@]}"; do + [[ $addr == */* ]] || addr+="/24" + if ! do_debug ip addr add "$addr" brd + dev "$Interface"; then + report_error "Could not add address '$addr' to interface '$Interface'" + return 1 + fi + done + fi + if [[ $Gateway ]]; then + if ! do_debug ip route add default via "$Gateway" dev "$Interface"; then + report_error "Could not set gateway '$Gateway' on interface '$Interface'" + return 1 + fi + fi + ;; + ""|no) + ;; + *) + report_error "IP must be either 'dhcp', 'static' or 'no'" + return 1 + ;; + esac + + # Add static IP routes + if [[ $IP && $Routes ]]; then + for route in "${Routes[@]}"; do + if ! do_debug ip route add $route dev "$Interface"; then + report_error "Could not add route '$route' to interface '$Interface'" + return 1 + fi + done + fi + + # Load ipv6 module if necessary + case "$IP6" in + dhcp*|stateless|static) + [[ -d "/proc/sys/net/ipv6" ]] || modprobe ipv6 + ;; + no) + [[ -d "/proc/sys/net/ipv6" ]] && sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=0" + ;; + "") # undefined IP6 does not prevent RA's from being received -> nop + ;; + *) + report_error "IP6 must be 'dhcp', 'dhcp-noaddr', 'stateless', 'static' or 'no'" + return 1 + ;; + esac + + case "$IP6" in + dhcp*) + if ! type dhclient &>/dev/null; then + report_error "You need to install dhclient to use DHCPv6" + return 1 + fi + sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=1" + [[ $IP6 == "dhcp-noaddr" ]] && Dhclient6Options+=" -S" + rm -f "/run/dhclient6-${Interface}.pid" + if ! do_debug dhclient -6 -q -e "TIMEOUT=${TimeoutDHCP:-10}" -pf "$Pidfile" $Dhclient6Options "$Interface"; then + report_error "DHCPv6 IP lease attempt failed on interface '$Interface'" + return 1 + fi + ;; + stateless) + sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=1" + ;; + static) + sysctl -q -w "net.ipv6.conf.$interface_sysctl.accept_ra=0" + if [[ -n $Address6 ]]; then + for addr in "${Address6[@]}"; do + if ! do_debug ip -6 addr add $addr dev "$Interface"; then + report_error "Could not add address '$addr' to interface '$Interface'" + fi + done + fi + ;; + esac + + if [[ $IP6 ]]; then + # Wait for Duplicate Address Detection to finish + if ! timeout_wait "${TimeoutDAD:-3}" '[[ -z "$(ip -6 addr show dev "$Interface" tentative)" ]]'; then + report_error "Duplicate Address Detection is taking too long on interface '$Interface'" + return 1 + fi + + # Add static IPv6 routes + if [[ $Routes6 ]]; then + for route in "${Routes6[@]}"; do + if ! do_debug ip -6 route add $route dev "$Interface"; then + report_error "Could not add route '$route' to interface '$Interface'" + return 1 + fi + done + fi + + # Set a custom gateway after DAD has finished + if [[ $IP6 == "static" && $Gateway6 ]]; then + if ! do_debug ip -6 route replace default via "$Gateway6" dev "$Interface"; then + report_error "Could not set gateway '$Gateway6' on interface '$Interface'" + return 1 + fi + fi + fi + + if [[ $IPCustom ]]; then + for line in "${IPCustom[@]}"; do + if ! do_debug ip $line; then + report_error "Could not configure interface ($line)" + return 1 + fi + done + fi + + if [[ $Hostname ]]; then + if ! do_debug hostnamectl set-hostname "$Hostname"; then + report_error "Cannot set the hostname to '$Hostname'" + return 1 + fi + fi + + if [[ $DNS ]]; then + resolvconf_add "$Interface" \ + "${DNSDomain/#/domain }" \ + "${DNSSearch/#/search }" \ + "${DNS[@]/#/nameserver }" \ + "${DNSOptions[@]/#/options }" + fi +} + + +## Clean up the dynamic part of an IP configuration +# $Interface: interface name +# $IP: type of IPv4 configuration +# $IP6: type of IPv6 configuration +ip_unset() { + if [[ "$IP" == "dhcp" ]]; then + case $DHCPClient in + dhcpcd) + if [[ -f "/run/dhcpcd-$Interface.pid" ]]; then + do_debug dhcpcd -qk "$Interface" >/dev/null + fi + ;; + dhclient) + if [[ -f "/run/dhclient-$Interface.pid" ]]; then + # Alternatively, use -r instead of -x to also release the lease + do_debug dhclient -q -x "$Interface" -pf "/run/dhclient-$Interface.pid" >/dev/null + fi + ;; + esac + fi + if [[ "$IP6" == dhcp* ]]; then + if [[ -f "/run/dhclient6-$Interface.pid" ]]; then + do_debug dhclient -6 -q -x "$Interface" -pf "/run/dhclient6-$Interface.pid" >/dev/null + fi + fi + + [[ $DNS ]] && resolvconf -d "$Interface" +} + + +# vim: ft=sh ts=4 et sw=4: diff --git a/src/lib/network b/src/lib/network old mode 100644 new mode 100755 index 1aa384c..1117737 --- a/src/lib/network +++ b/src/lib/network @@ -1,368 +1,95 @@ -### Globals -. /usr/lib/network/globals -# will load hooks - -## Loads a profile. -# $1: profile name -load_profile() -{ - unset ROUTES - [[ -z "$1" ]] && return 1 - if [[ ! -f "$PROFILE_DIR/$1" ]]; then - report_err "Profile \"$1\" does not exist" - return 1 - fi - report_debug "Loading profile $1" - INTERFACE=$(. "$PROFILE_DIR/$1"; echo "$INTERFACE") - report_debug "Configuring interface $INTERFACE" - if [[ -z "$INTERFACE" ]]; then - report_err "Profile missing an interface to configure" - return 1 - fi - if [[ -f "$IFACE_DIR/$INTERFACE" ]]; then - report_debug "Interface level configuration enabled: $IFACE_DIR/$INTERFACE" - . "$IFACE_DIR/$INTERFACE" - fi - . "$PROFILE_DIR/$1" # we want profile settings to override, so need to source profile again - if [[ ! -f "$CONN_DIR/$CONNECTION" ]]; then - report_err "$CONNECTION is not a valid connection, check spelling or look at examples" - return 1 - fi -} - -################## -# Profile up/down -################## - -## Take all registered profiles down. -all_down() -{ - find "$STATE_DIR/profiles/" -maxdepth 1 -type f -printf '%f\n' \ - | while read prof; do - profile_down "$prof" - done -} +#! /bin/bash -## Create the state dir and sub directories if they don't already exist. -check_make_state_dir() -{ - [[ ! -d "$STATE_DIR" ]] && mkdir -p "$STATE_DIR"/{interfaces,profiles} - for d in interfaces profiles suspend; do - [[ ! -d "$STATE_DIR/$d" ]] && mkdir "$STATE_DIR/$d" - done -} +. /usr/lib/network/globals -## Save the list of running profiles and take them down if needed -# $1: interface name or "all" -# $2: take associated profiles down (optional, default="yes") -interface_suspend() -{ - report_debug interface_suspend "$@" - check_make_state_dir - find "$STATE_DIR/profiles/" -maxdepth 1 -type f -printf '%f\n' \ - | while read prof; do - # the pipe to "while read" will create a subshell - INTERFACE=$(. "$STATE_DIR/profiles/$prof"; echo "$INTERFACE") - if [[ "$1" == all || "$1" == "$INTERFACE" ]]; then - report_notice "suspending interface $INTERFACE with profile $prof" - cp "$STATE_DIR/profiles/$prof" "$STATE_DIR/suspend/" - if checkyesno "${2:-yes}"; then - profile_down "$prof" - fi - fi - done -} - -## Save the list of all running profiles and take them down -all_suspend() { - interface_suspend all +## Check if a string represents a network interface +# $1: potential interface name +is_interface() { + # Strip any old school alias specifier + [[ -d "/sys/class/net/${1%%:?*}" ]] } -## Restore saved profiles (for resume purposes). -# $@: a list of interfaces not to resume (e.g., because they're disabled) -all_resume() -{ - report_debug all_resume "$@" - find "$STATE_DIR/suspend/" -maxdepth 1 -type f -printf '%f\n' \ - | while read prof; do - # the pipe to "while read" will create a subshell - INTERFACE=$(. "$STATE_DIR/suspend/$prof"; echo "$INTERFACE") - if [[ $# -eq 0 || ! " $* " =~ " $INTERFACE " ]]; then - report_notice "resuming interface $INTERFACE with profile $prof" - profile_up "$prof" - rm -f "$STATE_DIR/suspend/$prof" # if profile_up succeeds, it will have already removed this - fi - done +## Check if an interface is up +# $1: interface name +interface_is_up() { + local flags + read flags < "/sys/class/net/${1%%:?*}/flags" + # IFF_UP is defined as 0x1 in linux/if.h + (( flags & 0x1 )) } -## Puts up a profile. -# $1: the profile name -profile_up() -{ - ( - # Keep inside subshell so that options from one profile don't cross to others - # exit 1 used in a subshell is effectively exiting a new process - check_make_state_dir - - local status PROFILE="$1" # save PROFILE in a variable so that it's available to PRE_UP/POST_DOWN etc hooks - - load_profile "$PROFILE" || exit 1 - - if check_profile "$PROFILE"; then - report_err "$PROFILE already connected" +## Activate an interface +# $1: interface name +bring_interface_up() { + local interface=$1 + ip link set dev "$interface" up &>/dev/null + timeout_wait "${TimeoutUp:-5}" 'interface_is_up "$interface"' +} + +## Deactivate an interface +# $1: interface name +bring_interface_down() { + local interface=$1 + ip addr flush dev "$interface" &>/dev/null + ip link set dev "$interface" down &>/dev/null + # We reuse the up timeout (down normally is faster) + timeout_wait "${TimeoutUp:-5}" '! interface_is_up "$interface"' +} + + +if [[ $# -ne 2 || $1 != @(start|stop) ]]; then + exit_error "Usage: $0 {start|stop} " +fi +ensure_root netctl +# Ensure we are not in a transient directory +cd / + +# Expose the profile name +Profile=$2 +load_profile "$Profile" +source "$CONN_DIR/$Connection" +case $1 in + start) + report_notice "Starting network profile '$Profile'..." + if is_interface "$Interface" && interface_is_up "$Interface" && \ + ! is_yes "${ForceConnect:-no}"; then + report_error "The interface of network profile '$Profile' is already up" exit 1 fi - - # EXCLUSIVE, network.d/profile: Individual profile is mutually exclusive - if checkyesno "$EXCLUSIVE"; then - all_down - fi - - report_try "$PROFILE up" - - status=$(check_iface "$INTERFACE") - report_debug "status reported to profile_up as: $status" - case "$status" in - external) - report_fail "Interface $INTERFACE externally controlled" - exit 1 - ;; - disabled) - report_fail "Interface $INTERFACE is disabled" - exit 1 - ;; - "") - ;; - *) - if checkyesno "$CHECK"; then - report_fail "Interface $INTERFACE already in use" - exit 1 - - # not necessary to sandbox this call or reload PROFILE afterwards - elif ! interface_down "$INTERFACE"; then - report_fail - exit 1 - fi - ;; - esac - - if ! ( eval $PRE_UP ); then # JP: sandbox the eval so variables don't bleed into current function - report_debug profile_up "PRE_UP failed" - report_fail + if ! "${Connection}_up"; then + report_error "Failed to bring the network up for profile '$Profile'" exit 1 fi - - if ! "$CONN_DIR/$CONNECTION" up "$PROFILE"; then - report_debug profile_up "connect failed" - report_fail - # "$CONN_DIR/$CONNECTION" down "$PROFILE" # JP: should we do this to make sure? + # JP: sandbox the eval + if ! ( eval $ExecUpPost ); then + report_error "ExecUpPost failed for network profile '$Profile'" + # Failing ExecUpPost will take the connection down + "${Connection}_down" exit 1 fi - - if ! ( eval $POST_UP ); then # JP: sandbox the eval - report_debug profile_up "POST_UP failed" - report_fail - # failing POST_UP will take interface down - "$CONN_DIR/$CONNECTION" down "$PROFILE" + report_notice "Started network profile '$Profile'" + ;; + stop) + report_notice "Stopping network profile '$Profile'..." + # JP: sandbox the eval + if ! ( eval $ExecDownPre ); then + report_error "ExecDownPre failed for network profile '$Profile'" + # Failing ExecDownPre will leave the profile active exit 1 fi - - set_profile up "$PROFILE" - unset EXCLUSIVE - - # Successfully running a new profile; erase any suspended profiles on this interface - local iface="$INTERFACE" - find "$STATE_DIR/suspend/" -maxdepth 1 -type f -printf '%f\n' \ - | while read prof; do - # the pipe to "while read" will create a subshell - INTERFACE=$(. "$STATE_DIR/suspend/$prof"; echo "$INTERFACE") - if [[ "$iface" == "$INTERFACE" ]]; then - rm "$STATE_DIR/suspend/$prof" - fi - done - - report_success - ); return $? -} - -## Puts a profile down. -# $1: the profile name -profile_down() -{ - ( - check_make_state_dir - - local status PROFILE="$1" # save PROFILE in a variable so that it's available to PRE_UP/POST_DOWN etc hooks - - load_profile "$PROFILE" || exit 1 - - status=$(check_iface "$INTERFACE") - report_debug "status reported to profile_down as: $status" - - if [[ "$status" != "$PROFILE" ]]; then - # if interface not available to be controlled by netcfg, then - # any profiles should have been removed by check_iface - # else we get here if another profile is running - report_err "Profile not connected" + if ! "${Connection}_down"; then + report_error "Failed to bring the network down for profile '$Profile'" exit 1 fi - - report_try "$PROFILE down" - if [[ "$(check_iface "$INTERFACE")" == "external" ]]; then - report_fail "$interface was connected by another application" + if is_interface "$Interface" && interface_is_up "$Interface" && \ + ! is_yes "${ForceConnect:-no}"; then + report_error "The interface of network profile '$Profile' did not go down" exit 1 fi + report_notice "Stopped network profile '$Profile'" + ;; +esac - if ! ( eval $PRE_DOWN ); then # JP: sandbox the eval - report_debug profile_down "PRE_DOWN failed" - # true # JP: did we want failing PRE_DOWN to leave the profile active? - report_fail - exit 1 - fi - - if ! "$CONN_DIR/$CONNECTION" down "$PROFILE"; then - report_debug profile_up "disconnect failed" - report_fail - exit 1 - fi - - if ! ( eval $POST_DOWN ); then # JP: sandbox the eval - report_debug profile_down "POST_DOWN failed" - report_fail - exit 1 - fi - - set_profile down "$PROFILE" - report_success - ); return $? -} - -# interface_down interface -# take interface down -# -interface_down() -{ - local profile=$(check_iface "$1") - case "$profile" in - ""|disabled) return 0 ;; - external) return 1 ;; - *) profile_down "$profile" ;; - esac -} - -# interface_reconnect interface -# reconnects the profile active on interface -interface_reconnect() -{ - local profile=$(check_iface "$1") - case "$profile" in - ""|disabled|external) - return 1 - ;; - *) - profile_down "$profile" - profile_up "$profile" - ;; - esac -} - -## -# check_iface interface -# Return 0 if interface unavailable (in use by a profile or externally, or disabled) -# Return 1 if interface down and available to be used -# -check_iface() { - if [[ -f "$STATE_DIR/interfaces/$1" ]]; then - cat "$STATE_DIR/interfaces/$1" - return 0 - else - return 1 - fi -} - -# list_profiles -# Outputs a list of all profiles -list_profiles() { - # JP: follow aliases with -L, also skip profiles that start with '.' or end with '~' or '.conf' (so profile.conf can be the wpa.conf file for profile) - find -L "$PROFILE_DIR/" -maxdepth 1 -type f -not -name '*~' -not -name '*.conf' -not -name '.*' -printf "%f\n" -} - -# check_profile profile -# Return 0 if profile registered as being up -# Return 1 if profile not registered -# -check_profile() { - [[ -f "$STATE_DIR/profiles/$1" && ! -f "$STATE_DIR/suspend/$1" ]] && return 0 - return 1 -} - -### Status setting functions -## -# set_profile up/down profile -# Set profile state, either up or down -# -set_profile() { - local INTERFACE - if [[ "$1" == "up" ]]; then - INTERFACE=$(. "$PROFILE_DIR/$2"; echo "$INTERFACE") - cp "$PROFILE_DIR/$2" "$STATE_DIR/profiles/" - set_iface up "$INTERFACE" "$2" - elif [[ "$1" == "down" && -f "$STATE_DIR/profiles/$2" ]]; then # JP: skip if profile not already up - INTERFACE=$(. "$STATE_DIR/profiles/$2"; echo "$INTERFACE") - rm "$STATE_DIR/profiles/$2" - set_iface down "$INTERFACE" "$2" - fi -} - -# set_iface up/down interface [profile] -# Set interface status to up/down -# optionally link it to a profile. -# -set_iface() { - local PROFILE="${3:-external}" - if [[ "$1" == "up" ]]; then - echo "$PROFILE" > "$STATE_DIR/interfaces/$2" - elif [[ "$1" == "down" ]]; then - rm -f "$STATE_DIR/interfaces/$2" # JP: add -f so we don't complain if the interface isn't up - fi -} - -is_interface() { - local INTERFACE="$1" - if [[ ! -e "/sys/class/net/$INTERFACE" ]]; then - if ! echo "$INTERFACE" | grep -F -q ":"; then - return 1 - fi - fi - return 0 -} - -interface_is_up() { - local flags - read flags < "/sys/class/net/$1/flags" - # IFF_UP is defined as 0x1 in linux/if.h - (( flags & 0x1 )) -} - -## Changes a network interface state. -# $1: up, flush, or down. -# $2: the interface name -bring_interface() -{ - local INTERFACE="$2" - case "$1" in - up) - ip link set dev "$INTERFACE" up &>/dev/null - timeout_wait "${UP_TIMEOUT:-5}" 'interface_is_up "$INTERFACE"' || return 1 - ;; - flush|down) - ip addr flush dev "$INTERFACE" &>/dev/null - ;;& - down) - ip link set dev "$INTERFACE" down &>/dev/null - ;; - esac -} # vim: ft=sh ts=4 et sw=4: diff --git a/src/lib/rfkill b/src/lib/rfkill index 1832dc1..996e463 100644 --- a/src/lib/rfkill +++ b/src/lib/rfkill @@ -1,61 +1,60 @@ -set_rf_state() { - local INTERFACE="$1" state="$2" RFKILL_NAME="$3" +## /usr/lib/network/globals needs to be sourced before this file - if [[ "$RFKILL" == "hard" ]]; then - report_fail "Cannot set state on hardware rfkill switch" - return 1 - fi - local path=$(get_rf_path "$INTERFACE" "$RFKILL_NAME") || return 1 - case "$state" in - enabled) - echo 0 > "$path/soft" - ;; - disabled) - echo 1 > "$path/soft" - ;; - esac -} +## Determine the system interface of an rfkill device +# $1: interface name +# $2: rfkill name get_rf_path() { - local INTERFACE="$1" RFKILL_NAME="$2" path + local interface=$1 rfkill_name=${2:-auto} path - if [[ -n "$RFKILL_NAME" ]]; then + if [[ $rfkill_name == "auto" ]]; then + path=$(find -L "/sys/class/net/$interface/" -maxdepth 2 -type d -name "rfkill*" 2> /dev/null | head -n 1) + if [[ $path ]]; then + echo "$path" + return 0 + fi + report_error "No rfkill switch available on interface '$interface'" + else for path in /sys/class/rfkill/*; do - if [[ "$(< "$path/name")" == "$RFKILL_NAME" ]]; then + if [[ $(< "$path/name") == "$rfkill_name" ]]; then echo "$path" return 0 fi done - report_fail "no rfkill switch with name $RFKILL_NAME" - else - path=$(find -L "/sys/class/net/$INTERFACE/" -maxdepth 2 -type d -name "rfkill*" 2> /dev/null | head -n 1) - if [[ -n "$path" ]]; then - echo "$path" - return 0 - fi - report_fail "no rfkill switch available on interface $INTERFACE" + report_error "No rfkill switch with name '$rfkill_name'" fi return 1 } +## Unblock transmission through a wireless device +# $1: interface name +# $2: rfkill name enable_rf() { - local INTERFACE="$1" RFKILL="$2" RFKILL_NAME="$3" path hard soft - - # Enable rfkill if necessary, or fail if it is hardware - if [[ -n "$RFKILL" ]]; then - path=$(get_rf_path "$INTERFACE" "$RFKILL_NAME") || return 1 - read hard < "$path/hard" - read soft < "$path/soft" - - if (( hard )); then - report_fail "radio is disabled on $INTERFACE" - return 1 - elif (( soft )); then - set_rf_state "$INTERFACE" enabled "$RFKILL_NAME" || return 1 - timeout_wait 1 "(( ! \$(< \"$path/soft\") ))" - fi + local interface=$1 rfkill=$2 path hard soft + + path=$(get_rf_path "$interface" "$rfkill") || return 1 + read hard < "$path/hard" + read soft < "$path/soft" + + if (( hard )); then + report_error "Transmission is hard-blocked on interface '$interface'" + return 1 + elif (( soft )); then + do_debug echo 0 > "$path/soft" + timeout_wait 1 '(( ! $(< "$path/soft") ))' fi } -# vim: ft=sh ts=4 et sw=4: +## Block transmission through a wireless device +# $1: interface name +# $2: rfkill name +disable_rf() { + local interface=$1 rfkill=$2 path + + path=$(get_rf_path "$interface" "$rfkill") || return 1 + do_debug echo 1 > "$path/soft" + timeout_wait 1 '(( $(< "$path/soft") ))' +} + +# vim: ft=sh ts=4 et sw=4: diff --git a/src/netctl b/src/netctl index f1d79e8..0a82f89 100755 --- a/src/netctl +++ b/src/netctl @@ -1,106 +1,150 @@ -#!/bin/bash +#! /bin/bash -. /usr/lib/network/network +. /usr/lib/network/globals -NETCFG_VER=2-notpackaged +NETCTL_VERSION=notpackaged -version() -{ - echo "netcfg v$NETCFG_VER" -} -usage() -{ - version +usage() { cat << END -Usage: - Start specified profile: netcfg profile - Other functions: netcfg argument profile -Arguments: - current Report currently running profiles --a, all-down Take all active profiles down --c, check-iface Do not start profile if interface is already up --d, down Take specified profile down --D, iface-down Take down profile active on specified interface --h, help This help message --l, list List all available profiles --r, reconnect Disconnect and reconnect specified profile --R, iface-recon Reconnect profile active on specified interface --u, up Start specified profile --v, version Output version information and exit - all-resume Resume previously suspended profiles and reconnect them - all-suspend Store a list of current running profiles and suspend them +Usage: netctl {COMMAND} [PROFILE] + [--help|--version] + +Commands: + list List available profiles + store Save which profiles are active + restore Load saved profiles + stop-all Stops all profiles. + start [PROFILE] Start a profile + stop [PROFILE] Stop a profile + restart [PROFILE] Restart a profile + switch-to [PROFILE] Switch to a profile + status [PROFILE] Show runtime status of a profile + enable [PROFILE] Enable the systemd unit for a profile + disable [PROFILE] Disable the systemd unit for a profile + reenable [PROFILE] Reenable the systemd unit for a profile END } -# TODO: Re-add ROOT check and rewrite with getopts from BashFAQ - -case "$1" in - --version|-v|version) - version - exit 0;; - --help|-h|help) - usage - exit 0;; - list|-l) - list_profiles - exit 0;; - current|-s|status) - if [[ -d "$STATE_DIR/profiles/" ]]; then - ls "$STATE_DIR/profiles/" - exit 0 - else - exit_stderr "No active profiles." - fi;; -esac +list() { + local indicators=( '*' ' ' ) + list_profiles | while read -r Profile; do + systemctl is-active --quiet "netctl@$Profile.service" &> /dev/null + # Make the return variable boolean + [[ $? -eq 0 ]]; printf '%s %s\n' "${indicators[$?]}" "$Profile" + done +} + +store() { + systemctl list-units --type=service --full --no-legend --no-pager | \ + cut -d\ -f1 | grep "^netctl@" > "$STATE_FILE" +} + +restore() { + if [[ ! -r $STATE_FILE ]]; then + exit_error "Could not read state file '$STATE_FILE'" + fi + mapfile -t Units < "$STATE_FILE" + do_debug systemctl start "${Units[@]}" +} + +stop_all() { + # We cannot pipe to mapfile, as the end of a pipe is inside a subshell + mapfile -t Profiles < <(list_profiles) + do_debug systemctl stop "${Profiles[@]/#/netctl@}" 2> \ + >(grep -Fv "not loaded" >&2) +} + +switch_to() { + cd "$PROFILE_DIR" + if [[ ! -r $1 ]]; then + exit_error "Profile '$1' does not exist or is not readable" + fi + # We assume interface names are not quoted + # Using read removes leading whitespace + read InterfaceLine < \ + <(grep -om1 "^[[:space:]]*Interface=[[:alnum:]:._-]\+" "$1") + if [[ -z $InterfaceLine ]]; then + exit_error "Profile '$1' does not specify an interface" + fi + mapfile -t AllProfiles < <(list_profiles) + mapfile -t Profiles < <(grep -Fl "$InterfaceLine" "${AllProfiles[@]}") + do_debug systemctl stop "${Profiles[@]/#/netctl@}" 2> \ + >(grep -Fv "not loaded" >&2) + do_debug systemctl start "netctl@$1" +} + +unit_enable() { + local unit="/etc/systemd/system/netctl@$1.service" + if [[ -e $unit ]]; then + report_error "A unit file for profile '$1' already exists" + return 1 + fi + load_profile "$1" + echo ".include /usr/lib/systemd/system/netctl@.service" > "$unit" + echo -e "\n[Unit]" >> "$unit" + [[ -n $Description ]] && echo "Description=$Description" >> "$unit" + : ${BindsToInterfaces=$Interface} + printf 'BindsTo=sys-subsystem-net-devices-%s.device\n' \ + "${BindsToInterfaces[@]}" >> "$unit" + if [[ -n $After ]]; then + printf 'After="netctl@%s.service"\n' "${After[@]//\"/\\\"}" >> "$unit" + fi + systemctl daemon-reload + systemctl reenable "netctl@$1.service" +} -if [[ $(id -u) -gt 0 ]]; then - exit_stderr "This script should be run as root." -fi - -# Ensure cwd is not in a transient directory, which may prevent unmounting due to netcfg children -cd / - -case "$1" in - -c|check-iface|-u|up) - CHECK="YES" - profile_up "$2";; - -d|down) - profile_down "$2";; - -D|iface-down) - interface_down "$2";; - -a|all-down) - all_down;; - -r|reconnect) - profile_down "$2" - profile_up "$2";; - -R|iface-recon) - interface_reconnect "$2";; - all-resume) - all_resume;; - all-suspend) - all_suspend;; - clean) - rm "$STATE_DIR/interfaces"/* 2> /dev/null - rm "$STATE_DIR/profiles"/* 2> /dev/null - rm "$STATE_DIR/suspend"/* 2> /dev/null - rm "$STATE_DIR/netcfg-daemon" 2> /dev/null - killall wpa_supplicant 2> /dev/null - killall dhcpcd 2> /dev/null - killall dhclient 2> /dev/null - ;; - -*|--*) - usage - exit 1;; - *) - if [[ -n "$1" ]]; then - profile_up "$1" - else - usage - exit 1 - fi - ;; +unit_disable() { + local unit="/etc/systemd/system/netctl@$1.service" + if systemctl is-enabled --quiet "netctl@$1.service"; then + systemctl disable "netctl@$1.service" + fi + if [[ ! -f $unit ]]; then + report_error "No regular unit file found for profile '$1'" + return 1 + fi + do_debug rm "$unit" + systemctl daemon-reload +} + + +case $# in + 1) + case $1 in + --version) + report_notice "netctl version $NETCTL_VERSION";; + --help) + usage;; + list) + list;; + store|restore) + ensure_root "$(basename "$0")" + "$1";; + stop-all) + stop_all;; + *) + exit_error "$(usage)";; + esac;; + 2) + case $1 in + start|stop|restart|status) + systemctl $1 "netctl@$2";; + switch-to) + ensure_root "$(basename "$0")" + switch_to "$2";; + enable|disable) + ensure_root "$(basename "$0")" + "unit_$1" "$2";; + reenable) + ensure_root "$(basename "$0")" + unit_disable "$2" + unit_enable "$2";; + *) + exit_error "$(usage)";; + esac;; + *) + exit_error "$(usage)";; esac -exit $? + # vim: ft=sh ts=4 et sw=4: diff --git a/src/netctl-auto b/src/netctl-auto index c6aaf67..3452969 100755 --- a/src/netctl-auto +++ b/src/netctl-auto @@ -1,87 +1,74 @@ #! /bin/bash -. /usr/lib/network/network + +. /usr/lib/network/globals . "$SUBR_DIR/8021x" . "$SUBR_DIR/rfkill" -. /etc/conf.d/netcfg AUTOWIFI="/usr/sbin/wpa_actiond -p /run/wpa_supplicant" -ACTION_SCRIPT="/usr/bin/netcfg-wpa_actiond-action" +ACTION_SCRIPT="/usr/lib/network/auto.action" -case $1 in - help) - echo "netcfg-wpa_actiond " - echo "netcfg-wpa_actiond stop " - exit - ;; - stop) - [[ -z $2 ]] && echo "Please specify an interface to stop" && exit 1 - interface=$2 - PIDFILE="/run/wpa_actiond_${interface}.pid" - [[ -f "$IFACE_DIR/$interface" ]] && source "$IFACE_DIR/$interface" - netcfg -D "$interface" - timeout_wait 1 '[[ ! -f "$PIDFILE" ]]' || kill "$(< "$PIDFILE")" - # only try to disable software rfkill switches (FS#25514) - if [[ "$RFKILL" == "soft" ]]; then - set_rf_state "$interface" disabled $RFKILL_NAME || exit $? - fi - exit - ;; - *) - interface=$1; shift - PIDFILE="/run/wpa_actiond_${interface}.pid" - EXTRA_AUTOWIFI_OPTIONS="$*" - ;; -esac - -if [[ -z $interface ]]; then - echo "No interface specified" - exit 1 +if [[ $# != 2 || $1 != @(start|stop) ]]; then + exit_error "Usage: netctl-auto [start|stop] " fi -# Load interface specific config -[[ -f "$IFACE_DIR/$interface" ]] && source "$IFACE_DIR/$interface" - -if [[ -f "$CONN_DIR/interfaces/$interface" ]]; then - netcfg -D "$interface" -fi - -if [[ -n "$RFKILL" ]]; then # Enable radio if necessary - enable_rf "$interface" "$RFKILL" "$RFKILL_NAME" || exit $? -fi - -WPA_CONF="$(make_wpa_config_file "$interface")" - -if [[ -n "${AUTO_PROFILES}" ]]; then - for prof in "${AUTO_PROFILES[@]}"; do echo "$prof"; done -else - list_profiles -fi | while read profile; do - echo "$profile" - ( - load_profile "$profile" - - [[ $CONNECTION != "wireless" ]] && exit 1 - [[ $INTERFACE != $interface ]] && exit 1 - # Exclude wpa-config, the wpa_conf is 'complete' and doesn't fit in this scheme - [[ -z "$SECURITY" ]] && SECURITY="none" - [[ $SECURITY == "wpa-config" ]] && exit 1 +INTERFACE=$2 +PIDFILE="$STATE_DIR/wpa_actiond_$INTERFACE.pid" +PROFILE_FILE="$STATE_DIR/wpa_actiond_$INTERFACE.profile" +shift 2 - printf "%s\n" "network={" "$(make_wpa_config)" "id_str=\"$profile\"" "}" >> "$WPA_CONF" - ) -done - - -[[ -z $WPA_DRIVER ]] && WPA_DRIVER="nl80211,wext" -WPA_OPTS="-W $WPA_OPTS" - -# Kill any existing wpa_supplicant on this interface -stop_wpa "$interface" &> /dev/null - -if start_wpa "$interface" "$WPA_CONF" "$WPA_DRIVER" $WPA_OPTS; then - if $AUTOWIFI -i "$interface" -P "$PIDFILE" -a "$ACTION_SCRIPT" $EXTRA_AUTOWIFI_OPTIONS; then - exit 0 +case $1 in + start) + if [[ -e "/run/wpa_supplicant_$INTERFACE.pid" ]]; then + exit_error "The interface ($INTERFACE) is already in use" fi -fi + if [[ -x "$PROFILE_DIR/interfaces/$INTERFACE" ]]; then + source "$PROFILE_DIR/interfaces/$INTERFACE" + fi + [[ $RFKill ]] && enable_rf "$INTERFACE" "$RFKill" || exit 1 + + WPA_CONF=$(wpa_make_config_file "$INTERFACE") + list_profiles | while read -r profile; do + report_notice "$profile" + ( + source "$PROFILE_DIR/$profile" + is_yes "${ExcludeAuto:-no}"&& exit 1 + : ${Security:=none} + [[ $Interface != "$INTERFACE" ]] && exit 1 + [[ $Connection != "wireless" ]] && exit 1 + # Exclude wpa-config, the wpa_conf is 'complete' and doesn't fit in this scheme + [[ $Security == "wpa-config" ]] && exit 1 + + printf "%s\n" "network={" "$(wpa_make_config_block)" "id_str=\"$profile\"" "}" >> "$WPA_CONF" + ) + done + + # Kill any lingering WPA supplicants + WPAConfigFile= wpa_stop "$INTERFACE" &> /dev/null + + # Start the WPA supplicant + : ${WPADriver:=nl80211,wext} + WPAOptions+=" -W" + if wpa_start "$INTERFACE" "$WPADriver" "$WPA_CONF"; then + if $AUTOWIFI -i "$INTERFACE" -P "$PIDFILE" -a "$ACTION_SCRIPT" "$@"; then + exit 0 + fi + fi + exit 1 + ;; + stop) + if [[ -e $PROFILE_FILE ]]; then + "$SUBR_DIR/network" stop "$(< "$PROFILE_FILE")" && rm -f "$PROFILE_FILE" + else + if [[ -x "$PROFILE_DIR/interfaces/$INTERFACE" ]]; then + source "$PROFILE_DIR/interfaces/$INTERFACE" + fi + wpa_stop "$INTERFACE" + ip link set dev "$INTERFACE" down + [[ $RFKill ]] && disable_rf "$INTERFACE" "$RFKill" + fi + timeout_wait 1 '[[ ! -f "$PIDFILE" ]]' || kill "$(< "$PIDFILE")" + ;; +esac -exit 1 +# vim: ft=sh ts=4 et sw=4: diff --git a/src/wifi-menu b/src/wifi-menu index f46db0d..8c8189a 100755 --- a/src/wifi-menu +++ b/src/wifi-menu @@ -1,24 +1,21 @@ #! /bin/bash -. /usr/lib/network/network +. /usr/lib/network/globals . "$SUBR_DIR/8021x" -. /etc/conf.d/netcfg + usage() { cat << END -Usage: wifi-menu [-o | --obscure] [-h | --help] [interface] +Usage: wifi-menu [-h | --help] [-o | --obscure] [interface] Interactively connect to a wireless network. Arguments: + -h, --help Show this help. -o, --obscure Show asterisks for the characters of the password and store the password as a hexadecimal string. - -h, --help Show this help. - interface The wireless interface to use. - (default: WIRELESS_INTERFACE from /etc/conf.d/netcfg) - -For choosing from all available profiles, use netcfg-menu. + interface The wireless interface to use (default: wlan0). END } @@ -30,10 +27,10 @@ init_profiles() while read profile; do essid=$( unset INTERFACE ESSID - . "$PROFILE_DIR/$profile" &> /dev/null - if [[ "$INTERFACE" = "$1" && -n "$ESSID" ]]; then + source "$PROFILE_DIR/$profile" > /dev/null + if [[ "$Interface" = "$1" && -n "$ESSID" ]]; then printf "%s" "$ESSID" - if [[ "$DESCRIPTION" =~ "Automatically generated" ]]; then + if [[ "$Description" =~ "Automatically generated" ]]; then return 2 else return 1 @@ -61,8 +58,8 @@ init_entries() while IFS=$'\t' read signal flags ssid; do ENTRIES[i++]="--" # $ssid might look like an option to dialog. ENTRIES[i++]=$ssid - if inarray "$ssid" "${ESSIDS[@]}"; then - if inarray "$(ssid_to_profile "$ssid")" "${GENERATED[@]}"; then + if in_array "$ssid" "${ESSIDS[@]}"; then + if in_array "$(ssid_to_profile "$ssid")" "${GENERATED[@]}"; then ENTRIES[i]="+" # Automatically generated else ENTRIES[i]="*" # Handmade @@ -124,13 +121,13 @@ create_profile() fi fi cat << EOF > "$PROFILE_DIR/$PROFILE" -CONNECTION='wireless' -DESCRIPTION='Automatically generated profile by wifi-menu' -INTERFACE='$INTERFACE' -SECURITY='$security' +Description='Automatically generated profile by wifi-menu' +Interface=$INTERFACE +Connection=wireless +Security=$security ESSID=$(printf "%q" "$1") IP='dhcp' -${key+KEY=$key} +${key+Key=$key} EOF printf "%s" "$PROFILE" return 0 @@ -142,17 +139,14 @@ connect_to_ssid() { local msg PROFILE=$(ssid_to_profile "$1") - if [[ $? -eq 0 ]]; then - clear - check_profile "$PROFILE" && profile_down "$PROFILE" - else + if [[ $? -ne 0 ]]; then PROFILE=$(create_profile "$1") RETURN=$? (( RETURN == 0 )) || return $RETURN SPAWNED_PROFILE=1 - clear fi - if ! profile_up "$PROFILE"; then + clear + if ! netctl restart "$PROFILE"; then if (( SPAWNED_PROFILE )); then msg=" CONNECTING FAILED @@ -183,40 +177,35 @@ while [[ "$1" = -* ]]; do esac done if [[ $# -gt 1 ]]; then - report_err "Too many arguments" + report_error "Too many arguments" usage exit 255 fi -if [[ $(id -u) -ne 0 ]]; then - exit_stderr "This script needs to be run with root privileges" -fi +ensure_root "$(basename "$0")" if ! type dialog &> /dev/null; then - exit_stderr "Please install 'dialog' to use wifi-menu" + exit_error "Please install 'dialog' to use wifi-menu" fi -INTERFACE=${1-$WIRELESS_INTERFACE} +INTERFACE=${1-wlan0} if [[ -z "$INTERFACE" ]]; then - report_err "Missing interface specification" + report_error "Missing interface specification" usage exit 255 fi cd / # We do not want to spawn anything that can block unmounting -is_interface "$INTERFACE" || exit_fail "No such interface: $INTERFACE" -if ! interface_is_up "$INTERFACE"; then - [[ -f "$IFACE_DIR/$INTERFACE" ]] && . "$IFACE_DIR/$INTERFACE" - bring_interface up "$INTERFACE" || exit_fail "Interface unavailable" - SPAWNED_INTERFACE=1 +if [[ ! -d "/sys/class/net/$INTERFACE" ]]; then + exit_error "No such interface: $INTERFACE" fi -report_try "Scanning for networks" +echo -n "Scanning for networks... " CONNECTION=$(wpa_call "$INTERFACE" status 2> /dev/null | grep -m 1 "^ssid=") CONNECTION=${CONNECTION#ssid=} NETWORKS=$(wpa_supplicant_scan "$INTERFACE" 3,4,5) if [[ $? -eq 0 ]]; then trap 'rm -f "$NETWORKS"' EXIT - report_success + echo "done" init_profiles "$INTERFACE" init_entries "$NETWORKS" MSG="Select the network you wish to use @@ -233,7 +222,7 @@ Flags description: RETURN=$? fi else - report_fail + echo "failed" RETURN=3 fi @@ -244,20 +233,19 @@ case $RETURN in clear ;; 3) # No networks found - report_err "No networks found" + report_error "No networks found" ;; 4) # Invalid passphrase length (WEP keys have tighter restrictions) clear - report_err "Passphrase must be 8..63 characters" + report_error "Passphrase must be 8..63 characters" ;; 255) # ESC or error clear - report_err "Aborted" + report_error "Aborted" ;; *) # Should not happen - report_err "Unexpected return code from dialog: $RETURN" + report_error "Unexpected return code from dialog: $RETURN" RETURN=7 ;; esac -(( RETURN && SPAWNED_INTERFACE )) && bring_interface down "$INTERFACE" exit $RETURN -- cgit v1.2.3-24-g4f1b