From 8e9e71f817288aaaf232546f52d7cf14f79c4760 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Tue, 7 Jun 2005 04:49:12 +0000 Subject: [PATCH] Support code for the OpenBSD dhclient. This significantly changes the way interfaces are configured. Some key points: - At startup, all interfaces are configured through /etc/rc.d/netif. - ifconfig_ variables my now mix real ifconfig commands the with DHCP and WPA directives. For example, this allows media configuration prior to running dhclient. - /etc/rc.d/dhclient is not run at startup except by netif to start dhclient on specific interfaces. - /etc/pccard_ether calls "/etc/rc.d/netif start " to do most of it's work. - /etc/pccard_ether no longer takes additional arguments to pass to ifconfig. Instead, ifconfig_ variables are now honored in favor of pccard_ifconfig when available. - /etc/pccard_ether will only run on interfaces specified in removable_interfaces, even if pccard_ifconfig is set. --- etc/defaults/rc.conf | 1 + etc/devd.conf | 15 ++- etc/network.subr | 111 ++++++++++++++- etc/pccard_ether | 314 +++++++++++-------------------------------- etc/rc.d/dhclient | 100 +++----------- etc/rc.d/netif | 4 +- 6 files changed, 223 insertions(+), 322 deletions(-) diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index 790b473d3b92..97771988b169 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -42,6 +42,7 @@ pccard_ether_delay="5" # Delay before trying to start dhclient in pccard_ether powerd_enable="NO" # Run powerd to lower our power usage. powerd_flags="" # Flags to powerd (if enabled). removable_interfaces="" # Removable network interfaces for /etc/pccard_ether. +removable_route_flush="YES" # Flush routes when removing an interface tmpmfs="AUTO" # Set to YES to always create an mfs /tmp, NO to never tmpsize="20m" # Size of mfs /tmp if created tmpmfs_flags="-S" # Extra mdmfs options for the mfs /tmp diff --git a/etc/devd.conf b/etc/devd.conf index 064658514840..6968a8b8daeb 100644 --- a/etc/devd.conf +++ b/etc/devd.conf @@ -32,7 +32,7 @@ options { # override these general rules. # -# For ethernet like devices, the default is to run dhclient. Due to +# For ethernet like devices start configuring the interface. Due to # a historical accident, this script is called pccard_ether. # attach 0 { @@ -45,6 +45,19 @@ detach 0 { action "/etc/pccard_ether $device-name stop"; }; +# +# Try to start dhclient on Ethernet like interfaces when the link comes +# up. Only devices that are configured to support DHCP will actually +# run it. No link down rule exists because dhclient automaticly exits +# when the link goes down. +# +notify 0 { + match "system" "IFNET"; + match "subsystem" "$ethernet-nic-regex"; + match "type" "LINK_UP"; + action "/etc/rc.d/dhclient start $subsystem"; +}; + # An entry like this might be in a different file, but is included here # as an example of how to override things. Normally 'ed50' would match # the above attach/detach stuff, but the value of 100 makes it diff --git a/etc/network.subr b/etc/network.subr index dfd2febf9aff..a3059dd8e3ea 100644 --- a/etc/network.subr +++ b/etc/network.subr @@ -34,16 +34,30 @@ # Evaluate ifconfig(8) arguments for interface $if and # run ifconfig(8) with those arguments. It returns 0 if # arguments were found and executed or 1 if the interface -# had no arguments. +# had no arguments. Pseudo arguments DHCP and WPA are handled +# here. # ifconfig_up() { - eval ifconfig_args=\$ifconfig_$1 + _cfg=1 + + ifconfig_args=`ifconfig_getargs $1` if [ -n "${ifconfig_args}" ]; then ifconfig $1 ${ifconfig_args} - return 0 + _cfg=0 fi - return 1 + + if wpaif $1; then + #/etc/rc.d/wpa_supplicant start $1 + _cfg=0 # XXX: not sure this should count + fi + + if dhcpif $1; then + /etc/rc.d/dhclient start $1 + _cfg=0 + fi + + return ${cfg} } # ifconfig_down if @@ -74,9 +88,98 @@ ifconfig_down() done IFS="$oldifs" + if wpaif $1; then + #/etc/rc.d/wpa_supplicant stop $1 + fi + + if dhcpif $1; then + /etc/rc.d/dhclient stop $1 + _cfg=0 + fi + return $_ret } +# _ifconfig_getargs if +# Echos the arguments for the supplied interface to stdout. +# returns 1 if empty. In general, ifconfig_getargs should be used +# outside this file. +_ifconfig_getargs() +{ + _ifn=$1 + if [ -z "$_ifn" ]; then + return 1 + fi + + eval _args=\$ifconfig_$1 + if [ -z "$_args" -a -n "${pccard_ifconfig}" ]; then + for _if in ${removable_interfaces} ; do + if [ "$_if" = "$_ifn" ] ; then + _args=${pccard_ifconfig} + break + fi + done + fi + + echo $_args +} + +# ifconfig_getargs if +# Takes the result from _ifconfig_getargs and removes pseudo +# args such as DHCP and WPA. +ifconfig_getargs() +{ + _tmpargs=`_ifconfig_getargs $1` + if [ $? -eq 1 ]; then + return 1 + fi + _args= + + for _arg in $_tmpargs; do + case $_arg in + [Dd][Hh][Cc][Pp]) + ;; + [Ww][Pp][Aa]) + ;; + *) + _args="$_args $_arg" + ;; + esac + done + + echo $_args +} + +# dhcpif if +# Returns 0 if the interface is a DHCP interface and 1 otherwise. +dhcpif() +{ + _tmpargs=`_ifconfig_getargs $1` + for _arg in $_tmpargs; do + case $_arg in + [Dd][Hh][Cc][Pp]) + return 0 + ;; + esac + done + return 1 +} + +# wpaif if +# Returns 0 if the interface is a WPA interface and 1 otherwise. +wpaif() +{ + _tmpargs=`_ifconfig_getargs $1` + for _arg in $_tmpargs; do + case $_arg in + [Ww][Pp][Aa]) + return 0 + ;; + esac + done + return 1 +} + # ifalias_up if # Configure aliases for network interface $if. # It returns 0 if at least one alias was configured or diff --git a/etc/pccard_ether b/etc/pccard_ether index 8c7b6716eace..99c3204e1f05 100755 --- a/etc/pccard_ether +++ b/etc/pccard_ether @@ -2,271 +2,115 @@ # # $FreeBSD$ # -# pccard_ether interfacename [start|stop] [ifconfig option] +# pccard_ether interfacename [start|stop] # -# example: pccard_ether fxp0 start link0 +# example: pccard_ether fxp0 start # +. /etc/rc.subr . /etc/network.subr -stop_dhcp() { - # If dhclient is already running, record - # its interfaces. - if [ -x /usr/bin/grep ]; then - eval _active_list=\"`/bin/ps -axwww | \ - /usr/bin/grep dhclient | \ - /usr/bin/grep -v grep | \ - /usr/bin/sed -e 's|^.*dhclient||' | \ - /usr/bin/awk '{for (i=1;i<=NF;i++) \ - { if ($i~/[a-zA-Z].[0-9]$/) \ - { printf(" %s",$i) } }}'` \ - \" - fi - - # Get the rc.conf list of dhcp configured interfaces - static_dhcp_list="`list_net_interfaces dhcp`" - - # Get the current ifconfig list of interfaces - _aprefix= - _nlist= - for _if in ${_active_list} ; do - _test_if=`ifconfig ${_if} 2>&1` - case "$_test_if" in - "ifconfig: interface $_if does not exist") - ;; - ${interface}) - # Don't record the same device twice. - ;; - *) - # - # Catch devices which were specified before, - # but have not been part of the rc. We need - # them again for the restart. - # - for _cif in ${static_dhcp_list} ; do - case "$_cif" in - ${_if}) - # Nothing to add - ;; - *) - # Found interface beside rc.conf - _nlist="${_nlist}${_aprefix}${_if}" - ;; - esac - done - _dhcplist="${_dhcplist}${_aprefix}${_if}" - [ -z "$_aprefix" ] && _aprefix=' ' - ;; - esac - done - - if [ -s /var/run/dhclient.pid ]; then - pidfile="/var/run/dhclient.pid" - else - return - fi - /sbin/dhclient -r ${interface} - rm -f ${pidfile} - case ${startstop} in - [Ss][Tt][Oo][Pp]) - if [ -z "${_nlist}" ]; then - sh /etc/rc.d/dhclient start - else - start_dhcp_keep_current - fi - ;; - *) - ;; - esac +usage() +{ + err 3 'USAGE: $0 interface (start|stop)' } -start_dhcp() { - stop_dhcp - case ${pccard_ether_delay} in - [Nn][Oo]) - ;; - [0-9]*) - sleep ${pccard_ether_delay} - ;; - esac - [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program" - [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags" - if [ -x "${dhclient_program}" ]; then - interfaces=`echo $_dhcplist ${interface} | xargs -n 1 echo | sort -u` - ${dhclient_program} ${dhclient_flags} ${interfaces} - else - echo "${dhclient_program}: DHCP client software not available" - fi -} - -# Called after detaching a card, if dhclient has been -# used for more than one interface. -start_dhcp_keep_current() { - [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program" - [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags" - if [ -x "${dhclient_program}" ]; then - ${dhclient_program} ${dhclient_flags} \ - ${_dhcplist} - else - echo "${dhclient_program}: DHCP client software not available" - fi -} - -# Suck in the configuration variables -# -if [ -r /etc/defaults/rc.conf ]; then - . /etc/defaults/rc.conf - source_rc_confs -elif [ -r /etc/rc.conf ]; then - . /etc/rc.conf -fi - -interface=$1 +ifn=$1 shift startstop=$1 shift -case ${pccard_ifconfig} in -[Nn][Oo] | '') - expr "${removable_interfaces}" : ".*${interface}" > /dev/null || exit 0 - ;; -*) - # Backward compatible - eval ifconfig_${interface}=\${pccard_ifconfig} - ;; -esac +# Ignore interfaces not in removable_interfaces +expr "${removable_interfaces}" : ".*${ifn}" > /dev/null || exit 0 + +if [ -n "$1" ]; then + usage +fi + +setup_routes() +{ + # Add default route into $static_routes + case ${defaultrouter} in + [Nn][Oo] | '') + ;; + *) + static_routes="default ${static_routes}" + route_default="default ${defaultrouter}" + ;; + esac + + # Add private route for this interface into $static_routes + eval ifx_routes=\$static_routes_${ifn} + if [ -n "${ifx_routes}" ]; then + static_routes="${ifx_routes} ${static_routes}" + fi + + # Set up any static routes if specified + if [ -n "${static_routes}" ]; then + for i in ${static_routes}; do + eval route_args=\$route_${i} + route add ${route_args} + done + fi +} + +remove_routes() +{ + # Delete static route if specified + eval ifx_routes=\$static_routes_${ifn} + if [ -n "${ifx_routes}" ]; then + for i in ${ifx_routes}; do + eval route_args=\$route_${i} + route delete ${route_args} + done + fi +} + +load_rc_config pccard_ether case ${startstop} in [Ss][Tt][Aa][Rr][Tt] | '') if [ -x /usr/bin/grep ]; then - if ifconfig ${interface} | grep -s netmask > /dev/null 2>&1; then + if ifconfig $ifn | grep -s netmask > /dev/null 2>&1; then # Interface is already up, so ignore it. exit 0 fi fi - if [ -r /etc/start_if.${interface} ]; then - . /etc/start_if.${interface} + /etc/rc.d/netif start $ifn + + # Do route configuration if needed. + # XXX: should probably do this by calling rc.d/routing. + if [ -n "`ifconfig_getargs $ifn`" ]; then + if ! dhcpif $ifn; then + setup_routes + fi fi - eval ifconfig_args=\$ifconfig_${interface} - case ${ifconfig_args} in - [Nn][Oo] | '') - ;; - [Dd][Hh][Cc][Pp]) - # Start up the DHCP client program - start_dhcp - ;; - *) - # Do the primary ifconfig if specified - ifconfig ${interface} ${ifconfig_args} $* - - # Check to see if aliases need to be added - alias=0 - while : - do - eval ifx_args=\$ifconfig_${interface}_alias${alias} - if [ -n "${ifx_args}" ]; then - ifconfig ${interface} ${ifx_args} alias - alias=`expr ${alias} + 1` - else - break; - fi - done - - # Do ipx address if specified - eval ifx_args=\$ifconfig_${interface}_ipx - if [ -n "${ifx_args}" ]; then - ifconfig ${interface} ${ifx_args} - fi - - # Add default route into $static_routes - case ${defaultrouter} in - [Nn][Oo] | '') - ;; - *) - static_routes="default ${static_routes}" - route_default="default ${defaultrouter}" - ;; - esac - - # Add private route for this interface into $static_routes - eval ifx_routes=\$static_routes_${interface} - if [ -n "${ifx_routes}" ]; then - static_routes="${ifx_routes} ${static_routes}" - fi - - # Set up any static routes if specified - if [ -n "${static_routes}" ]; then - for i in ${static_routes}; do - eval route_args=\$route_${i} - route add ${route_args} - done - fi - ;; - esac - # IPv6 setup - case ${ipv6_enable} in - [Yy][Ee][Ss]) - if [ -r /etc/network.subr ]; then - . /etc/network.subr - network6_interface_setup ${interface} - fi - ;; - esac + if checkyesno ipv6_enable; then + network6_interface_setup $ifn + fi ;; + # Stop the interface -*) - if [ -r /etc/stop_if.${interface} ]; then - . /etc/stop_if.${interface} +[Ss][Tt][Oo][Pp]) + if [ -n "`ifconfig_getargs $ifn`" ]; then + if ! dhcpif $ifn; then + remove_routes + fi fi - eval ifconfig_args=\$ifconfig_${interface} - case ${ifconfig_args} in - [Nn][Oo] | '') - ;; - [Dd][Hh][Cc][Pp]) - # Stop the DHCP client for this interface - stop_dhcp - ;; - *) - # Delete static route if specified - eval ifx_routes=\$static_routes_${interface} - if [ -n "${ifx_routes}" ]; then - for i in ${ifx_routes}; do - eval route_args=\$route_${i} - route delete ${route_args} - done - fi + /etc/rc.d/netif stop $ifn - # Delete aliases if exist - alias=0 - while : - do - eval ifx_args=\$ifconfig_${interface}_alias${alias} - if [ -n "${ifx_args}" ]; then - ifconfig ${interface} ${ifx_args} alias delete - alias=`expr ${alias} + 1` - else - break; - fi - done - ;; - esac - - # Remove the network interface and cleaning ARP table - ifconfig ${interface} delete + # clean ARP table arp -d -a # Clean the routing table - case ${removable_route_flush} in - [Nn][Oo]) - ;; - *) - # flush beforehand, just in case.... - route -n flush -inet - ;; - esac + if checkyesno removable_route_flush; then + route -n flush -inet > /dev/null + fi ;; +*) + usage esac diff --git a/etc/rc.d/dhclient b/etc/rc.d/dhclient index 5d284277cdf1..2e56f1f35b6a 100755 --- a/etc/rc.d/dhclient +++ b/etc/rc.d/dhclient @@ -7,10 +7,7 @@ # PROVIDE: dhclient # REQUIRE: netif ipfw ipfilter mountcritlocal cleanvar # BEFORE: NETWORKING -# KEYWORD: nojail -# -# Note that there no syslog logging of dhclient messages at boot because -# dhclient needs to start before services that syslog depends upon do. +# KEYWORD: nojail nostart # . /etc/rc.subr @@ -18,96 +15,39 @@ name="dhclient" rcvar= -pidfile="/var/run/${name}.pid" -start_precmd="dhclient_prestart" -start_postcmd="dhclient_poststart" -stop_precmd="dhclient_prestop" -stop_postcmd="dhclient_poststop" +start_cmd="dhclient_start" +stop_cmd="dhclient_stop" -dhclient_common() +dhclient_start() { - dhcp_list="`list_net_interfaces dhcp`" - if [ -z "$dhcp_list" ]; then - return 1 - fi - - # Determine the scope of the command - # - _cooked_list="$dhcp_list" - if [ -n "$_cmdifn" ]; then - eval _cooked_list=\"`expr "$dhcp_list" : ".*\($_cmdifn\).*"`\" - if [ -z "$_cooked_list" ]; then - err 1 "No such network interface: $_cmdifn" + # prevent unnecessicary restarts + # XXX: should use a pidfile + if [ -x /usr/bin/pgrep ]; then + pids=`/usr/bin/pgrep -f "dhclient: $ifn(\$| .*)"` + if [ -n "$pids" ]; then + echo "${name} ${ifn}: already running?" + exit 0 fi fi -} - -dhclient_prestart() -{ - if [ $dhclient_common_error -eq 1 ]; then - return 1 - fi - for ifn in ${_cooked_list}; do - ifscript_up ${ifn} - done if checkyesno background_dhclient; then - rc_flags="${rc_flags} -nw" + rc_flags="${rc_flags} -b" fi - rc_flags="${rc_flags} ${_cooked_list}" - return 0 + ${dhclient_program} ${rc_flags} $ifn } -dhclient_poststart() +dhclient_stop() { - for ifn in ${_cooked_list}; do - ifalias_up ${ifn} - ipx_up ${ifn} - ifconfig ${ifn} - done + ifconfig $ifn down # cause dhclient to die } -dhclient_prestop() -{ - if [ $dhclient_common_error -eq 1 ]; then - return 1 - fi - for ifn in ${_cooked_list}; do - ipx_down ${ifn} - ifalias_down ${ifn} - done - echo -n "Releasing DHCP leases:" - for ifn in $_cooked_list ; do - ${command} -r $ifn - if [ $? -eq 0 ]; then - echo -n " $ifn" - else - _fail="$_fail $ifn" - fi - done - echo '.' - debug "The following leases failed to release: $_fail" -} - -dhclient_poststop() -{ - for ifn in ${_cooked_list}; do - ifscript_down ${ifn} - done -} - -if [ -n "$2" ]; then - _cmdifn="$2" - stop_cmd=":" -fi +ifn="$2" load_rc_config $name -dhclient_common_error=0 -dhclient_common || dhclient_common_error=1; -if [ -n "$_cooked_list" ]; then - if [ -s $pidfile ]; then - stop_cmd=":" - fi + +if ! dhcpif $ifn; then + return 1 fi + run_rc_command "$1" diff --git a/etc/rc.d/netif b/etc/rc.d/netif index 58a9476b3a83..88bccb78b9ab 100644 --- a/etc/rc.d/netif +++ b/etc/rc.d/netif @@ -102,8 +102,8 @@ network_common() fi [ -n "$2" ] && _verbose=yes - # Get a list of network interfaces. Do not include dhcp interfaces. - _ifn_list="`list_net_interfaces nodhcp`" + # Get a list of network interfaces. + _ifn_list="`list_net_interfaces`" # Set the scope of the command (all interfaces or just one). #