xref: /freebsd/libexec/rc/rc.d/netwait (revision ec6ad605ecea5c4a76d2e744df0265cc3f3a01b9)
1#!/bin/sh
2#
3# PROVIDE: netwait
4# REQUIRE: devd ipfw pf routing
5#
6# The netwait script helps handle three situations:
7#  - Systems with USB or other late-attaching network hardware which
8#    is initialized by devd events.  The script waits for all the
9#    interfaces named in the netwait_if list to appear.
10#  - Systems with IPv6 addresses, especially jails, where we need to
11#    wait for DAD to complete before starting daemons, as they will
12#    otherwise fail to bind to IN6ADDR_ANY.
13#  - Systems with statically-configured IP addresses in rc.conf(5).
14#    The IP addresses in the netwait_ip list are pinged.  The script
15#    waits for any single IP in the list to respond to the ping.  If your
16#    system uses DHCP, you should probably use synchronous_dhclient="YES"
17#    in your /etc/rc.conf instead of netwait_ip.
18# Either or both of the wait lists can be used (at least one must be
19# non-empty if netwait is enabled).
20
21. /etc/rc.subr
22
23name="netwait"
24desc="Wait for network devices or the network being up"
25rcvar="netwait_enable"
26
27start_cmd="${name}_start"
28stop_cmd=":"
29
30netwait_start()
31{
32	local ip rc count output link wait_if got_if any_error
33
34	if [ -z "${netwait_if}" ] && [ -z "${netwait_ip}" ] &&
35	   ! checkyesno netwait_dad ; then
36		err 1 "Nothing to wait for"
37	fi
38
39	if ! [ "${netwait_if_timeout:=0}" -ge 1 ]; then
40		err 1 "netwait_if_timeout must be >= 1"
41	fi
42	if ! check_kern_features inet6; then
43		netwait_dad="NO"
44	elif ! [ "${netwait_dad_timeout:=0}" -ge 1 ]; then
45		netwait_dad_timeout=$(($(sysctl -n net.inet6.ip6.dad_count)+1))
46	fi
47	if ! [ "${netwait_timeout:=0}" -ge 1 ]; then
48		err 1 "netwait_timeout must be >= 1"
49	fi
50
51	any_error=false
52
53	if [ -n "${netwait_if}" ]; then
54		for wait_if in ${netwait_if}; do
55			echo -n "Waiting for ${wait_if}"
56			link=""
57			got_if=false
58			count=1
59			# Handle SIGINT (Ctrl-C); force abort of while loop
60			trap break SIGINT
61			while [ ${count} -le ${netwait_if_timeout} ]; do
62				if output=`/sbin/ifconfig ${wait_if} 2>/dev/null`; then
63					if ! ${got_if}; then
64						echo -n ", interface present"
65						got_if=true
66					fi
67					link=`expr "${output}" : '.*[[:blank:]]status: \(no carrier\)'`
68					if [ -z "${link}" ]; then
69						echo ', got link.'
70						break
71					fi
72				fi
73				sleep 1
74				count=$((count+1))
75			done
76			# Restore default SIGINT handler
77			trap - SIGINT
78			if ! ${got_if}; then
79				echo ", wait failed: interface never appeared."
80				any_error=true
81			elif [ -n "${link}" ]; then
82				echo ", wait failed: interface still has no link."
83				any_error=true
84			fi
85		done
86	fi
87
88	if checkyesno netwait_dad; then
89		got_dad=false
90		# Handle SIGINT (Ctrl-C); force abort of while loop
91		trap break SIGINT
92
93		echo -n "Waiting for DAD to complete"
94		count=1
95		while [ ${count} -le ${netwait_dad_timeout} ]; do
96			if ! ifconfig | grep -q 'inet6.*tentative'; then
97				echo ', done.'
98				got_dad=true
99				break
100			fi
101			sleep 1
102			count=$((count+1))
103		done
104
105		# Restore default SIGINT handler
106		trap - SIGINT
107
108		if ! ${got_dad}; then
109			echo ', timed out.'
110			any_error=true
111		fi
112	fi
113
114	if [ -n "${netwait_ip}" ]; then
115		got_ip=false
116		# Handle SIGINT (Ctrl-C); force abort of for loop
117		trap break SIGINT
118
119		for ip in ${netwait_ip}; do
120			echo -n "Waiting for ${ip} to respond to ICMP ping"
121
122			count=1
123			while [ ${count} -le ${netwait_timeout} ]; do
124				/sbin/ping -t 1 -c 1 -o ${ip} >/dev/null 2>&1
125				rc=$?
126
127				if [ $rc -eq 0 ]; then
128					echo ', got response.'
129					got_ip=false
130					break 2
131				fi
132				count=$((count+1))
133			done
134			echo ', failed: No response from host.'
135		done
136
137		# Restore default SIGINT handler
138		trap - SIGINT
139
140		if ! ${got_ip}; then
141			any_error=true
142		fi
143	fi
144
145	if ${any_error}; then
146		warn "Continuing with startup, but be aware you may not have "
147		warn "a fully functional networking layer at this point."
148	fi
149}
150
151load_rc_config $name
152
153# doesn't make sense to run in a svcj: config setting
154netwait_svcj="NO"
155
156run_rc_command "$1"
157