xref: /freebsd/usr.sbin/bsdconfig/share/media/tcpip.subr (revision 7323adac99d399e58bdec71236a0db9ee6bfb6d2)
1*7323adacSDevin Teskeif [ ! "$_MEDIA_TCPIP_SUBR" ]; then _MEDIA_TCPIP_SUBR=1
2*7323adacSDevin Teske#
3*7323adacSDevin Teske# Copyright (c) 2012-2013 Devin Teske
4*7323adacSDevin Teske# All Rights Reserved.
5*7323adacSDevin Teske#
6*7323adacSDevin Teske# Redistribution and use in source and binary forms, with or without
7*7323adacSDevin Teske# modification, are permitted provided that the following conditions
8*7323adacSDevin Teske# are met:
9*7323adacSDevin Teske# 1. Redistributions of source code must retain the above copyright
10*7323adacSDevin Teske#    notice, this list of conditions and the following disclaimer.
11*7323adacSDevin Teske# 2. Redistributions in binary form must reproduce the above copyright
12*7323adacSDevin Teske#    notice, this list of conditions and the following disclaimer in the
13*7323adacSDevin Teske#    documentation and/or other materials provided with the distribution.
14*7323adacSDevin Teske#
15*7323adacSDevin Teske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*7323adacSDevin Teske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
17*7323adacSDevin Teske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*7323adacSDevin Teske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*7323adacSDevin Teske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*7323adacSDevin Teske# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*7323adacSDevin Teske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*7323adacSDevin Teske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*7323adacSDevin Teske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*7323adacSDevin Teske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*7323adacSDevin Teske# SUCH DAMAGE.
26*7323adacSDevin Teske#
27*7323adacSDevin Teske# $FreeBSD$
28*7323adacSDevin Teske#
29*7323adacSDevin Teske############################################################ INCLUDES
30*7323adacSDevin Teske
31*7323adacSDevin TeskeBSDCFG_SHARE="/usr/share/bsdconfig"
32*7323adacSDevin Teske. $BSDCFG_SHARE/common.subr || exit 1
33*7323adacSDevin Teskef_dprintf "%s: loading includes..." media/tcpip.subr
34*7323adacSDevin Teskef_include $BSDCFG_SHARE/struct.subr
35*7323adacSDevin Teskef_include $BSDCFG_SHARE/device.subr
36*7323adacSDevin Teskef_include $BSDCFG_SHARE/dialog.subr
37*7323adacSDevin Teskef_include $BSDCFG_SHARE/variable.subr
38*7323adacSDevin Teske
39*7323adacSDevin TeskeBSDCFG_LIBE="/usr/libexec/bsdconfig"
40*7323adacSDevin Teskef_include_lang $BSDCFG_LIBE/include/messages.subr
41*7323adacSDevin Teske
42*7323adacSDevin TeskeTCP_HELPFILE=$BSDCFG_LIBE/include/tcp.hlp
43*7323adacSDevin TeskeNETWORK_DEVICE_HELPFILE=$BSDCFG_LIBE/include/network_device.hlp
44*7323adacSDevin Teske
45*7323adacSDevin Teske############################################################ GLOBALS
46*7323adacSDevin Teske
47*7323adacSDevin Teske#
48*7323adacSDevin Teske# Path to resolv.conf(5).
49*7323adacSDevin Teske#
50*7323adacSDevin Teske: ${RESOLV_CONF:="/etc/resolv.conf"}
51*7323adacSDevin Teske
52*7323adacSDevin Teske#
53*7323adacSDevin Teske# Path to nsswitch.conf(5).
54*7323adacSDevin Teske#
55*7323adacSDevin Teske: ${NSSWITCH_CONF:="/etc/nsswitch.conf"}
56*7323adacSDevin Teske
57*7323adacSDevin Teske#
58*7323adacSDevin Teske# Path to hosts(5)
59*7323adacSDevin Teske#
60*7323adacSDevin Teske: ${ETC_HOSTS:="/etc/hosts"}
61*7323adacSDevin Teske
62*7323adacSDevin Teske#
63*7323adacSDevin Teske# Structure of dhclient.leases(5) lease { ... } entry
64*7323adacSDevin Teske#
65*7323adacSDevin Teskef_struct_define DHCP_LEASE \
66*7323adacSDevin Teske	interface		\
67*7323adacSDevin Teske	fixed_address		\
68*7323adacSDevin Teske	filename		\
69*7323adacSDevin Teske	server_name		\
70*7323adacSDevin Teske	script			\
71*7323adacSDevin Teske	medium			\
72*7323adacSDevin Teske	host_name		\
73*7323adacSDevin Teske	subnet_mask		\
74*7323adacSDevin Teske	routers			\
75*7323adacSDevin Teske	domain_name_servers	\
76*7323adacSDevin Teske	domain_name		\
77*7323adacSDevin Teske	broadcast_address	\
78*7323adacSDevin Teske	dhcp_lease_time		\
79*7323adacSDevin Teske	dhcp_message_type	\
80*7323adacSDevin Teske	dhcp_server_identifier	\
81*7323adacSDevin Teske	dhcp_renewal_time	\
82*7323adacSDevin Teske	dhcp_rebinding_time	\
83*7323adacSDevin Teske	renew			\
84*7323adacSDevin Teske	rebind			\
85*7323adacSDevin Teske	expire
86*7323adacSDevin Teske
87*7323adacSDevin Teske############################################################ FUNCTIONS
88*7323adacSDevin Teske
89*7323adacSDevin Teske# f_validate_hostname $hostname
90*7323adacSDevin Teske#
91*7323adacSDevin Teske# Returns zero if the given argument (a fully-qualified hostname) is compliant
92*7323adacSDevin Teske# with standards set-forth in RFC's 952 and 1123 of the Network Working Group:
93*7323adacSDevin Teske#
94*7323adacSDevin Teske# RFC 952 - DoD Internet host table specification
95*7323adacSDevin Teske# http://tools.ietf.org/html/rfc952
96*7323adacSDevin Teske#
97*7323adacSDevin Teske# RFC 1123 - Requirements for Internet Hosts - Application and Support
98*7323adacSDevin Teske# http://tools.ietf.org/html/rfc1123
99*7323adacSDevin Teske#
100*7323adacSDevin Teske# See http://en.wikipedia.org/wiki/Hostname for a brief overview.
101*7323adacSDevin Teske#
102*7323adacSDevin Teske# The return status for invalid hostnames is one of:
103*7323adacSDevin Teske# 	255	Entire hostname exceeds the maximum length of 255 characters.
104*7323adacSDevin Teske# 	 63	One or more individual labels within the hostname (separated by
105*7323adacSDevin Teske# 	   	dots) exceeds the maximum of 63 characters.
106*7323adacSDevin Teske# 	  1	One or more individual labels within the hostname contains one
107*7323adacSDevin Teske# 	   	or more invalid characters.
108*7323adacSDevin Teske# 	  2	One or more individual labels within the hostname starts or
109*7323adacSDevin Teske# 	   	ends with a hyphen (hyphens are allowed, but a label cannot
110*7323adacSDevin Teske# 	   	begin or end with a hyphen).
111*7323adacSDevin Teske# 	  3	One or more individual labels within the hostname are null.
112*7323adacSDevin Teske#
113*7323adacSDevin Teske# f_dialog_validate_hostname $hostname
114*7323adacSDevin Teske#
115*7323adacSDevin Teske# If the hostname is determined to be invalid, the appropriate error will be
116*7323adacSDevin Teske# displayed using the f_show_msg function.
117*7323adacSDevin Teske#
118*7323adacSDevin Teskef_validate_hostname()
119*7323adacSDevin Teske{
120*7323adacSDevin Teske	local fqhn="$1"
121*7323adacSDevin Teske
122*7323adacSDevin Teske	# Return error if the hostname exceeds 255 characters
123*7323adacSDevin Teske	[ ${#fqhn} -gt 255 ] && return 255
124*7323adacSDevin Teske
125*7323adacSDevin Teske	local IFS="." # Split on `dot'
126*7323adacSDevin Teske	for label in $fqhn; do
127*7323adacSDevin Teske		# Return error if the label exceeds 63 characters
128*7323adacSDevin Teske		[ ${#label} -gt 63 ] && return 63
129*7323adacSDevin Teske
130*7323adacSDevin Teske		# Return error if the label is null
131*7323adacSDevin Teske		[ "$label" ] || return 3
132*7323adacSDevin Teske
133*7323adacSDevin Teske		# Return error if label begins/ends with dash
134*7323adacSDevin Teske		case "$label" in -*|*-) return 2; esac
135*7323adacSDevin Teske
136*7323adacSDevin Teske		# Return error if the label contains any invalid chars
137*7323adacSDevin Teske		case "$label" in *[!0-9a-zA-Z-]*) return 1; esac
138*7323adacSDevin Teske	done
139*7323adacSDevin Teske
140*7323adacSDevin Teske	return $SUCCESS
141*7323adacSDevin Teske}
142*7323adacSDevin Teske
143*7323adacSDevin Teske# f_inet_atoi $ipv4_address [$var_to_set]
144*7323adacSDevin Teske#
145*7323adacSDevin Teske# Convert an IPv4 address or mask from dotted-quad notation (e.g., `127.0.0.1'
146*7323adacSDevin Teske# or `255.255.255.0') to a 32-bit unsigned integer for the purpose of network
147*7323adacSDevin Teske# and broadcast calculations. For example, one can validate that two addresses
148*7323adacSDevin Teske# are on the same network:
149*7323adacSDevin Teske#
150*7323adacSDevin Teske# 	f_inet_atoi 1.2.3.4 ip1num
151*7323adacSDevin Teske# 	f_inet_atoi 1.2.4.5 ip2num
152*7323adacSDevin Teske# 	f_inet_atoi 255.255.0.0 masknum
153*7323adacSDevin Teske# 	if [ $(( $ip1num & $masknum )) -eq \
154*7323adacSDevin Teske# 	     $(( $ip2num & $masknum )) ]
155*7323adacSDevin Teske# 	then
156*7323adacSDevin Teske# 		: IP addresses are on same network
157*7323adacSDevin Teske# 	fi
158*7323adacSDevin Teske#
159*7323adacSDevin Teske# See f_validate_ipaddr() below for an additional example usage, on calculating
160*7323adacSDevin Teske# network and broadcast addresses.
161*7323adacSDevin Teske#
162*7323adacSDevin Teske# If $var_to_set is missing or NULL, the converted IP address is printed to
163*7323adacSDevin Teske# standard output for capturing in a sub-shell (which is less-recommended
164*7323adacSDevin Teske# because of performance degredation; for example, when called in a loop).
165*7323adacSDevin Teske#
166*7323adacSDevin Teskef_inet_atoi()
167*7323adacSDevin Teske{
168*7323adacSDevin Teske	local __addr="$1" __var_to_set="$2" __num=0
169*7323adacSDevin Teske	if f_validate_ipaddr "$__addr"; then
170*7323adacSDevin Teske		__num=$( IFS=.;  set -- $__addr; \
171*7323adacSDevin Teske			echo $(( ($1 << 24) + ($2 << 16) + ($3 << 8) + $4 )) )
172*7323adacSDevin Teske	fi
173*7323adacSDevin Teske	if [ "$__var_to_set" ]; then
174*7323adacSDevin Teske		setvar "$__var_to_set" $__num
175*7323adacSDevin Teske	else
176*7323adacSDevin Teske		echo $__num
177*7323adacSDevin Teske	fi
178*7323adacSDevin Teske}
179*7323adacSDevin Teske
180*7323adacSDevin Teske# f_validate_ipaddr $ipaddr [$netmask]
181*7323adacSDevin Teske#
182*7323adacSDevin Teske# Returns zero if the given argument (an IP address) is of the proper format.
183*7323adacSDevin Teske#
184*7323adacSDevin Teske# The return status for invalid IP address is one of:
185*7323adacSDevin Teske# 	1	One or more individual octets within the IP address (separated
186*7323adacSDevin Teske# 	 	by dots) contains one or more invalid characters.
187*7323adacSDevin Teske# 	2	One or more individual octets within the IP address are null
188*7323adacSDevin Teske# 	 	and/or missing.
189*7323adacSDevin Teske# 	3	One or more individual octets within the IP address exceeds the
190*7323adacSDevin Teske# 	 	maximum of 255 (or 2^8, being an octet comprised of 8 bits).
191*7323adacSDevin Teske# 	4	The IP address has either too few or too many octets.
192*7323adacSDevin Teske#
193*7323adacSDevin Teske# If a netmask is provided, the IP address is checked further:
194*7323adacSDevin Teske#
195*7323adacSDevin Teske# 	5	The IP address must not be the network or broadcast address.
196*7323adacSDevin Teske#
197*7323adacSDevin Teskef_validate_ipaddr()
198*7323adacSDevin Teske{
199*7323adacSDevin Teske	local ip="$1" mask="$2"
200*7323adacSDevin Teske
201*7323adacSDevin Teske	# Track number of octets for error checking
202*7323adacSDevin Teske	local noctets=0
203*7323adacSDevin Teske
204*7323adacSDevin Teske	local oldIFS="$IFS"
205*7323adacSDevin Teske	local IFS="." # Split on `dot'
206*7323adacSDevin Teske	for octet in $ip; do
207*7323adacSDevin Teske		# Return error if the octet is null
208*7323adacSDevin Teske		[ "$octet" ] || return 2
209*7323adacSDevin Teske
210*7323adacSDevin Teske		# Return error if not a whole integer
211*7323adacSDevin Teske		f_isinteger "$octet" || return 1
212*7323adacSDevin Teske
213*7323adacSDevin Teske		# Return error if not a positive integer
214*7323adacSDevin Teske		[ $octet -ge 0 ] || return 1
215*7323adacSDevin Teske
216*7323adacSDevin Teske		# Return error if the octet exceeds 255
217*7323adacSDevin Teske		[ $octet -gt 255 ] && return 3
218*7323adacSDevin Teske
219*7323adacSDevin Teske		noctets=$(( $noctets + 1 ))
220*7323adacSDevin Teske	done
221*7323adacSDevin Teske	IFS="$oldIFS"
222*7323adacSDevin Teske
223*7323adacSDevin Teske	[ $noctets -eq 4 ] || return 4
224*7323adacSDevin Teske
225*7323adacSDevin Teske	#
226*7323adacSDevin Teske	# The IP address must not be network or broadcast address.
227*7323adacSDevin Teske	#
228*7323adacSDevin Teske	if [ "$mask" ]; then
229*7323adacSDevin Teske		local ipnum masknum netnum bcastnum
230*7323adacSDevin Teske		local max_addr=4294967295 # 255.255.255.255
231*7323adacSDevin Teske
232*7323adacSDevin Teske		f_inet_atoi $ip ipnum
233*7323adacSDevin Teske		f_inet_atoi $mask masknum
234*7323adacSDevin Teske
235*7323adacSDevin Teske		netnum=$(( $ipnum & $masknum ))
236*7323adacSDevin Teske		bcastnum=$(( ($ipnum & $masknum)+$max_addr-$masknum ))
237*7323adacSDevin Teske
238*7323adacSDevin Teske		if [ "$masknum" ] &&
239*7323adacSDevin Teske		   [ $ipnum -eq $netnum -o $ipnum -eq $bcastnum ]
240*7323adacSDevin Teske		then
241*7323adacSDevin Teske			return 5
242*7323adacSDevin Teske		fi
243*7323adacSDevin Teske	fi
244*7323adacSDevin Teske
245*7323adacSDevin Teske	return $SUCCESS
246*7323adacSDevin Teske}
247*7323adacSDevin Teske
248*7323adacSDevin Teske# f_validate_ipaddr6 $ipv6_addr
249*7323adacSDevin Teske#
250*7323adacSDevin Teske# Returns zero if the given argument (an IPv6 address) is of the proper format.
251*7323adacSDevin Teske#
252*7323adacSDevin Teske# The return status for invalid IP address is one of:
253*7323adacSDevin Teske# 	1	One or more individual segments within the IP address
254*7323adacSDevin Teske# 	 	(separated by colons) contains one or more invalid characters.
255*7323adacSDevin Teske# 	 	Segments must contain only combinations of the characters 0-9,
256*7323adacSDevin Teske# 	 	A-F, or a-f.
257*7323adacSDevin Teske# 	2	Too many/incorrect null segments. A single null segment is
258*7323adacSDevin Teske# 	 	allowed within the IP address (separated by colons) but not
259*7323adacSDevin Teske# 	 	allowed at the beginning or end (unless a double-null segment;
260*7323adacSDevin Teske# 	 	i.e., "::*" or "*::").
261*7323adacSDevin Teske# 	3	One or more individual segments within the IP address
262*7323adacSDevin Teske# 	 	(separated by colons) exceeds the length of 4 hex-digits.
263*7323adacSDevin Teske# 	4	The IP address entered has either too few (less than 3), too
264*7323adacSDevin Teske# 	 	many (more than 8), or not enough segments, separated by
265*7323adacSDevin Teske# 	 	colons.
266*7323adacSDevin Teske# 	5*	The IPv4 address at the end of the IPv6 address is invalid.
267*7323adacSDevin Teske# 	*	When there is an error with the dotted-quad IPv4 address at the
268*7323adacSDevin Teske# 	 	end of the IPv6 address, the return value of 5 is OR'd with a
269*7323adacSDevin Teske# 	 	bit-shifted (<< 4) return of f_validate_ipaddr.
270*7323adacSDevin Teske#
271*7323adacSDevin Teskef_validate_ipaddr6()
272*7323adacSDevin Teske{
273*7323adacSDevin Teske	local ip="${1%\%*}" # removing the interface specification if-present
274*7323adacSDevin Teske
275*7323adacSDevin Teske	local IFS=":" # Split on `colon'
276*7323adacSDevin Teske	set -- $ip:
277*7323adacSDevin Teske
278*7323adacSDevin Teske	# Return error if too many or too few segments
279*7323adacSDevin Teske	# Using 9 as max in case of leading or trailing null spanner
280*7323adacSDevin Teske	[ $# -gt 9 -o $# -lt 3 ] && return 4
281*7323adacSDevin Teske
282*7323adacSDevin Teske	local h="[0-9A-Fa-f]"
283*7323adacSDevin Teske	local nulls=0 nsegments=$# contains_ipv4_segment=
284*7323adacSDevin Teske
285*7323adacSDevin Teske	while [ $# -gt 0 ]; do
286*7323adacSDevin Teske
287*7323adacSDevin Teske		segment="${1%:}"
288*7323adacSDevin Teske		shift
289*7323adacSDevin Teske
290*7323adacSDevin Teske		#
291*7323adacSDevin Teske		# Return error if this segment makes one null too-many. A
292*7323adacSDevin Teske		# single null segment is allowed anywhere in the middle as well
293*7323adacSDevin Teske		# as double null segments are allowed at the beginning or end
294*7323adacSDevin Teske		# (but not both).
295*7323adacSDevin Teske		#
296*7323adacSDevin Teske		if [ ! "$segment" ]; then
297*7323adacSDevin Teske			nulls=$(( $nulls + 1 ))
298*7323adacSDevin Teske			if [ $nulls -eq 3 ]; then
299*7323adacSDevin Teske				# Only valid syntax for 3 nulls is `::'
300*7323adacSDevin Teske				[ "$ip" = "::" ] || return 2
301*7323adacSDevin Teske			elif [ $nulls -eq 2 ]; then
302*7323adacSDevin Teske				# Only valid if begins/ends with `::'
303*7323adacSDevin Teske				case "$ip" in
304*7323adacSDevin Teske				::*|*::) : fall thru ;;
305*7323adacSDevin Teske				*) return 2
306*7323adacSDevin Teske				esac
307*7323adacSDevin Teske			fi
308*7323adacSDevin Teske			continue
309*7323adacSDevin Teske		fi
310*7323adacSDevin Teske
311*7323adacSDevin Teske		#
312*7323adacSDevin Teske		# Return error if not a valid hexadecimal short
313*7323adacSDevin Teske		#
314*7323adacSDevin Teske		case "$segment" in
315*7323adacSDevin Teske		$h|$h$h|$h$h$h|$h$h$h$h)
316*7323adacSDevin Teske			: valid segment of 1-4 hexadecimal digits
317*7323adacSDevin Teske			;;
318*7323adacSDevin Teske		*[!0-9A-Fa-f]*)
319*7323adacSDevin Teske			# Segment contains at least one invalid char
320*7323adacSDevin Teske
321*7323adacSDevin Teske			# Return error immediately if not last segment
322*7323adacSDevin Teske			[ $# -eq 0 ] || return 1
323*7323adacSDevin Teske
324*7323adacSDevin Teske			# Otherwise, check for legacy IPv4 notation
325*7323adacSDevin Teske			case "$segment" in
326*7323adacSDevin Teske			*[!0-9.]*)
327*7323adacSDevin Teske				# Segment contains at least one invalid
328*7323adacSDevin Teske				# character even for an IPv4 address
329*7323adacSDevin Teske				return 1
330*7323adacSDevin Teske			esac
331*7323adacSDevin Teske
332*7323adacSDevin Teske			# Return error if not enough segments
333*7323adacSDevin Teske			if [ $nulls -eq 0 ]; then
334*7323adacSDevin Teske				[ $nsegments -eq 7 ] || return 4
335*7323adacSDevin Teske			fi
336*7323adacSDevin Teske
337*7323adacSDevin Teske			contains_ipv4_segment=1
338*7323adacSDevin Teske
339*7323adacSDevin Teske			# Validate the IPv4 address
340*7323adacSDevin Teske			f_validate_ipaddr "$segment" ||
341*7323adacSDevin Teske				return $(( 5 | $? << 4 ))
342*7323adacSDevin Teske			;;
343*7323adacSDevin Teske		*)
344*7323adacSDevin Teske			# Segment characters are all valid but too many
345*7323adacSDevin Teske			return 3
346*7323adacSDevin Teske		esac
347*7323adacSDevin Teske
348*7323adacSDevin Teske	done
349*7323adacSDevin Teske
350*7323adacSDevin Teske	if [ $nulls -eq 1 ]; then
351*7323adacSDevin Teske		# Single null segment cannot be at beginning/end
352*7323adacSDevin Teske		case "$ip" in
353*7323adacSDevin Teske		:*|*:) return 2
354*7323adacSDevin Teske		esac
355*7323adacSDevin Teske	fi
356*7323adacSDevin Teske
357*7323adacSDevin Teske	#
358*7323adacSDevin Teske	# A legacy IPv4 address can span the last two 16-bit segments,
359*7323adacSDevin Teske	# reducing the amount of maximum allowable segments by-one.
360*7323adacSDevin Teske	#
361*7323adacSDevin Teske	maxsegments=8
362*7323adacSDevin Teske	if [ "$contains_ipv4_segment" ]; then
363*7323adacSDevin Teske		maxsegments=7
364*7323adacSDevin Teske	fi
365*7323adacSDevin Teske
366*7323adacSDevin Teske	case $nulls in
367*7323adacSDevin Teske	# Return error if missing segments with no null spanner
368*7323adacSDevin Teske	0) [ $nsegments -eq $maxsegments ] || return 4 ;;
369*7323adacSDevin Teske	# Return error if null spanner with too many segments
370*7323adacSDevin Teske	1) [ $nsegments -le $maxsegments ] || return 4 ;;
371*7323adacSDevin Teske	# Return error if leading/trailing `::' with too many segments
372*7323adacSDevin Teske	2) [ $nsegments -le $(( $maxsegments + 1 )) ] || return 4 ;;
373*7323adacSDevin Teske	esac
374*7323adacSDevin Teske
375*7323adacSDevin Teske	return $SUCCESS
376*7323adacSDevin Teske}
377*7323adacSDevin Teske
378*7323adacSDevin Teske# f_validate_netmask $netmask
379*7323adacSDevin Teske#
380*7323adacSDevin Teske# Returns zero if the given argument (a subnet mask) is of the proper format.
381*7323adacSDevin Teske#
382*7323adacSDevin Teske# The return status for invalid netmask is one of:
383*7323adacSDevin Teske# 	1	One or more individual fields within the subnet mask (separated
384*7323adacSDevin Teske# 	 	by dots) contains one or more invalid characters.
385*7323adacSDevin Teske# 	2	One or more individual fields within the subnet mask are null
386*7323adacSDevin Teske# 	 	and/or missing.
387*7323adacSDevin Teske# 	3	One or more individual fields within the subnet mask exceeds
388*7323adacSDevin Teske# 	 	the maximum of 255 (a full 8-bit register).
389*7323adacSDevin Teske# 	4	The subnet mask has either too few or too many fields.
390*7323adacSDevin Teske# 	5	One or more individual fields within the subnet mask is an
391*7323adacSDevin Teske# 	 	invalid integer (only 0,128,192,224,240,248,252,254,255 are
392*7323adacSDevin Teske# 	 	valid integers).
393*7323adacSDevin Teske#
394*7323adacSDevin Teskef_validate_netmask()
395*7323adacSDevin Teske{
396*7323adacSDevin Teske	local mask="$1"
397*7323adacSDevin Teske
398*7323adacSDevin Teske	# Track number of fields for error checking
399*7323adacSDevin Teske	local nfields=0
400*7323adacSDevin Teske
401*7323adacSDevin Teske	local IFS="." # Split on `dot'
402*7323adacSDevin Teske	for field in $mask; do
403*7323adacSDevin Teske		# Return error if the field is null
404*7323adacSDevin Teske		[ "$field" ] || return 2
405*7323adacSDevin Teske
406*7323adacSDevin Teske		# Return error if not a whole positive integer
407*7323adacSDevin Teske		f_isinteger "$field" || return 1
408*7323adacSDevin Teske
409*7323adacSDevin Teske		# Return error if the field exceeds 255
410*7323adacSDevin Teske		[ $field -gt 255 ] && return 3
411*7323adacSDevin Teske
412*7323adacSDevin Teske		# Return error if the field is an invalid integer
413*7323adacSDevin Teske		case "$field" in
414*7323adacSDevin Teske		0|128|192|224|240|248|252|254|255) :;;
415*7323adacSDevin Teske		*) return 5;;
416*7323adacSDevin Teske		esac
417*7323adacSDevin Teske
418*7323adacSDevin Teske		nfields=$(( $nfields + 1 ))
419*7323adacSDevin Teske	done
420*7323adacSDevin Teske
421*7323adacSDevin Teske	[ $nfields -eq 4 ] || return 4
422*7323adacSDevin Teske}
423*7323adacSDevin Teske
424*7323adacSDevin Teske# f_validate_gateway $gateway $ipaddr $netmask
425*7323adacSDevin Teske#
426*7323adacSDevin Teske# Validate an IPv4 default gateway (aka router) address for a given IP address
427*7323adacSDevin Teske# making sure the two are in the same network (able to ``talk'' to each other).
428*7323adacSDevin Teske# Returns success if $ipaddr and $gateway are in the same network given subnet
429*7323adacSDevin Teske# mask $netmask.
430*7323adacSDevin Teske#
431*7323adacSDevin Teskef_validate_gateway()
432*7323adacSDevin Teske{
433*7323adacSDevin Teske	local gateway="$1" ipaddr="$2" netmask="$3"
434*7323adacSDevin Teske	local gwnum ipnum masknum
435*7323adacSDevin Teske
436*7323adacSDevin Teske	f_validate_ipaddr "$gateway" "$netmask" || return $FAILURE
437*7323adacSDevin Teske
438*7323adacSDevin Teske	f_inet_atoi "$netmask" masknum
439*7323adacSDevin Teske	f_inet_atoi "$ipaddr"  ipnum
440*7323adacSDevin Teske	f_inet_atoi "$gateway" gwnum
441*7323adacSDevin Teske
442*7323adacSDevin Teske	# Gateway must be within set of IPs reachable through interface
443*7323adacSDevin Teske	[ $(( $ipnum & $masknum )) -eq \
444*7323adacSDevin Teske	  $(( $gwnum & $masknum )) ] # Return status
445*7323adacSDevin Teske}
446*7323adacSDevin Teske
447*7323adacSDevin Teske# f_dialog_validate_tcpip $hostname $gateway $nameserver $ipaddr $netmask
448*7323adacSDevin Teske#
449*7323adacSDevin Teske# Returns success if the arguments provided are valid for accessing a TCP/IP
450*7323adacSDevin Teske# network, otherwise returns failure.
451*7323adacSDevin Teske#
452*7323adacSDevin Teskef_dialog_validate_tcpip()
453*7323adacSDevin Teske{
454*7323adacSDevin Teske	local hostname="$1" gateway="$2" nameserver="$3"
455*7323adacSDevin Teske	local ipaddr="$4" netmask="$5"
456*7323adacSDevin Teske	local ipnum masknum
457*7323adacSDevin Teske
458*7323adacSDevin Teske	if [ ! "$hostname" ]; then
459*7323adacSDevin Teske		f_dialog_msgbox "$msg_must_specify_a_host_name_of_some_sort"
460*7323adacSDevin Teske	elif ! f_validate_hostname "$hostname"; then
461*7323adacSDevin Teske		f_dialog_msgbox "$msg_invalid_hostname_value"
462*7323adacSDevin Teske	elif [ "$netmask" ] && ! f_validate_netmask "$netmask"; then
463*7323adacSDevin Teske		f_dialog_msgbox "$msg_invalid_netmask_value"
464*7323adacSDevin Teske	elif [ "$nameserver" ] &&
465*7323adacSDevin Teske	      ! f_validate_ipaddr "$nameserver" &&
466*7323adacSDevin Teske	      ! f_validate_ipaddr6 "$nameserver"; then
467*7323adacSDevin Teske		f_dialog_msgbox "$msg_invalid_name_server_ip_address_specified"
468*7323adacSDevin Teske	elif [ "$ipaddr" ] && ! f_validate_ipaddr "$ipaddr" "$netmask"; then
469*7323adacSDevin Teske		f_dialog_msgbox "$msg_invalid_ipv4_address"
470*7323adacSDevin Teske	elif [ "$gateway" -a "$gateway" != "NO" ] &&
471*7323adacSDevin Teske	      ! f_validate_gateway "$gateway" "$ipaddr" "$netmask"; then
472*7323adacSDevin Teske		f_dialog_msgbox "$msg_invalid_gateway_ipv4_address_specified"
473*7323adacSDevin Teske	else
474*7323adacSDevin Teske		return $SUCCESS
475*7323adacSDevin Teske	fi
476*7323adacSDevin Teske
477*7323adacSDevin Teske	return $FAILURE
478*7323adacSDevin Teske}
479*7323adacSDevin Teske
480*7323adacSDevin Teske# f_ifconfig_inet $interface [$var_to_set]
481*7323adacSDevin Teske#
482*7323adacSDevin Teske# Returns the IPv4 address associated with $interface. If $var_to_set is
483*7323adacSDevin Teske# missing or NULL, the IP address is printed to standard output for capturing
484*7323adacSDevin Teske# in a sub-shell (which is less-recommended because of performance degredation;
485*7323adacSDevin Teske# for example, when called in a loop).
486*7323adacSDevin Teske#
487*7323adacSDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
488*7323adacSDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
489*7323adacSDevin Teske#
490*7323adacSDevin Teskef_ifconfig_inet_awk='
491*7323adacSDevin TeskeBEGIN { found = 0 }
492*7323adacSDevin Teske( $1 == "inet" ) \
493*7323adacSDevin Teske{
494*7323adacSDevin Teske	print $2
495*7323adacSDevin Teske	found = 1
496*7323adacSDevin Teske	exit
497*7323adacSDevin Teske}
498*7323adacSDevin TeskeEND { exit ! found }
499*7323adacSDevin Teske'
500*7323adacSDevin Teskef_ifconfig_inet()
501*7323adacSDevin Teske{
502*7323adacSDevin Teske	local __interface="$1" __var_to_set="$2"
503*7323adacSDevin Teske	if [ "$__var_to_set" ]; then
504*7323adacSDevin Teske		local __ip
505*7323adacSDevin Teske		__ip=$( ifconfig "$__interface" 2> /dev/null |
506*7323adacSDevin Teske			awk "$f_ifconfig_inet_awk" )
507*7323adacSDevin Teske		setvar "$__var_to_set" "$__ip"
508*7323adacSDevin Teske	else
509*7323adacSDevin Teske		ifconfig "$__interface" 2> /dev/null |
510*7323adacSDevin Teske			awk "$f_ifconfig_inet_awk"
511*7323adacSDevin Teske	fi
512*7323adacSDevin Teske}
513*7323adacSDevin Teske
514*7323adacSDevin Teske# f_ifconfig_inet6 $interface [$var_to_set]
515*7323adacSDevin Teske#
516*7323adacSDevin Teske# Returns the IPv6 address associated with $interface. If $var_to_set is
517*7323adacSDevin Teske# missing or NULL, the IP address is printed to standard output for capturing
518*7323adacSDevin Teske# in a sub-shell (which is less-recommended because of performance degredation;
519*7323adacSDevin Teske# for example, when called in a loop).
520*7323adacSDevin Teske#
521*7323adacSDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
522*7323adacSDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
523*7323adacSDevin Teske#
524*7323adacSDevin Teskef_ifconfig_inet6_awk='
525*7323adacSDevin TeskeBEGIN { found = 0 }
526*7323adacSDevin Teske( $1 == "inet6" ) \
527*7323adacSDevin Teske{
528*7323adacSDevin Teske	print $2
529*7323adacSDevin Teske	found = 1
530*7323adacSDevin Teske	exit
531*7323adacSDevin Teske}
532*7323adacSDevin TeskeEND { exit ! found }
533*7323adacSDevin Teske'
534*7323adacSDevin Teskef_ifconfig_inet6()
535*7323adacSDevin Teske{
536*7323adacSDevin Teske	local __interface="$1" __var_to_set="$2"
537*7323adacSDevin Teske	if [ "$__var_to_set" ]; then
538*7323adacSDevin Teske		local __ip6
539*7323adacSDevin Teske		__ip6=$( ifconfig "$__interface" 2> /dev/null |
540*7323adacSDevin Teske			awk "$f_ifconfig_inet6_awk" )
541*7323adacSDevin Teske		setvar "$__var_to_set" "$__ip6"
542*7323adacSDevin Teske	else
543*7323adacSDevin Teske		ifconfig "$__interface" 2> /dev/null |
544*7323adacSDevin Teske			awk "$f_ifconfig_inet6_awk"
545*7323adacSDevin Teske	fi
546*7323adacSDevin Teske}
547*7323adacSDevin Teske
548*7323adacSDevin Teske# f_ifconfig_netmask $interface [$var_to_set]
549*7323adacSDevin Teske#
550*7323adacSDevin Teske# Returns the IPv4 subnet mask associated with $interface. If $var_to_set is
551*7323adacSDevin Teske# missing or NULL, the netmask is printed to standard output for capturing in a
552*7323adacSDevin Teske# sub-shell (which is less-recommended because of performance degredation; for
553*7323adacSDevin Teske# example, when called in a loop).
554*7323adacSDevin Teske#
555*7323adacSDevin Teskef_ifconfig_netmask()
556*7323adacSDevin Teske{
557*7323adacSDevin Teske	local __interface="$1" __var_to_set="$2" __octets
558*7323adacSDevin Teske	__octets=$( ifconfig "$__interface" 2> /dev/null | awk \
559*7323adacSDevin Teske	'
560*7323adacSDevin Teske		BEGIN { found = 0 }
561*7323adacSDevin Teske		( $1 == "inet" ) \
562*7323adacSDevin Teske		{
563*7323adacSDevin Teske			printf "%s %s %s %s\n",
564*7323adacSDevin Teske				substr($4,3,2),
565*7323adacSDevin Teske				substr($4,5,2),
566*7323adacSDevin Teske				substr($4,7,2),
567*7323adacSDevin Teske				substr($4,9,2)
568*7323adacSDevin Teske			found = 1
569*7323adacSDevin Teske			exit
570*7323adacSDevin Teske		}
571*7323adacSDevin Teske		END { exit ! found }
572*7323adacSDevin Teske	' ) || return $FAILURE
573*7323adacSDevin Teske
574*7323adacSDevin Teske	local __octet __netmask=
575*7323adacSDevin Teske	for __octet in $__octets; do
576*7323adacSDevin Teske		__netmask="$__netmask.$( printf "%u" "0x$__octet" )"
577*7323adacSDevin Teske	done
578*7323adacSDevin Teske	__netmask="${__netmask#.}"
579*7323adacSDevin Teske	if [ "$__var_to_set" ]; then
580*7323adacSDevin Teske		setvar "$__var_to_set" "$__netmask"
581*7323adacSDevin Teske	else
582*7323adacSDevin Teske		echo $__netmask
583*7323adacSDevin Teske	fi
584*7323adacSDevin Teske}
585*7323adacSDevin Teske
586*7323adacSDevin Teske# f_route_get_default [$var_to_set]
587*7323adacSDevin Teske#
588*7323adacSDevin Teske# Returns the IP address of the currently active default router. If $var_to_set
589*7323adacSDevin Teske# is missing or NULL, the IP address is printed to standard output for
590*7323adacSDevin Teske# capturing in a sub-shell (which is less-recommended because of performance
591*7323adacSDevin Teske# degredation; for example, when called in a loop).
592*7323adacSDevin Teske#
593*7323adacSDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
594*7323adacSDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
595*7323adacSDevin Teske#
596*7323adacSDevin Teskef_route_get_default='
597*7323adacSDevin TeskeBEGIN { found = 0 }
598*7323adacSDevin Teske( $1 == "gateway:" ) \
599*7323adacSDevin Teske{
600*7323adacSDevin Teske	print $2
601*7323adacSDevin Teske	found = 1
602*7323adacSDevin Teske	exit
603*7323adacSDevin Teske}
604*7323adacSDevin TeskeEND { exit ! found }
605*7323adacSDevin Teske'
606*7323adacSDevin Teskef_route_get_default()
607*7323adacSDevin Teske{
608*7323adacSDevin Teske	local __var_to_set="$1"
609*7323adacSDevin Teske	if [ "$__var_to_set" ]; then
610*7323adacSDevin Teske		local __ip
611*7323adacSDevin Teske		__ip=$( route -n get default 2> /dev/null |
612*7323adacSDevin Teske			awk "$f_route_get_default_awk" )
613*7323adacSDevin Teske		setvar "$__var_to_set" "$__ip"
614*7323adacSDevin Teske	else
615*7323adacSDevin Teske		route -n get default 2> /dev/null |
616*7323adacSDevin Teske			awk "$f_route_get_default_awk"
617*7323adacSDevin Teske	fi
618*7323adacSDevin Teske}
619*7323adacSDevin Teske
620*7323adacSDevin Teske# f_resolv_conf_nameservers [$var_to_set]
621*7323adacSDevin Teske#
622*7323adacSDevin Teske# Returns nameserver(s) configured in resolv.conf(5). If $var_to_set is missing
623*7323adacSDevin Teske# or NULL, the list of nameservers is printed to standard output for capturing
624*7323adacSDevin Teske# in a sub-shell (which is less-recommended because of performance degredation;
625*7323adacSDevin Teske# for example, when called in a loop).
626*7323adacSDevin Teske#
627*7323adacSDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
628*7323adacSDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
629*7323adacSDevin Teske#
630*7323adacSDevin Teskef_resolv_conf_nameservers_awk='
631*7323adacSDevin TeskeBEGIN { found = 0 }
632*7323adacSDevin Teske( $1 == "nameserver" ) \
633*7323adacSDevin Teske{
634*7323adacSDevin Teske	print $2
635*7323adacSDevin Teske	found = 1
636*7323adacSDevin Teske}
637*7323adacSDevin TeskeEND { exit ! found }
638*7323adacSDevin Teske'
639*7323adacSDevin Teskef_resolv_conf_nameservers()
640*7323adacSDevin Teske{
641*7323adacSDevin Teske	local __var_to_set="$1"
642*7323adacSDevin Teske	if [ "$__var_to_set" ]; then
643*7323adacSDevin Teske		local __ns
644*7323adacSDevin Teske		__ns=$( awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \
645*7323adacSDevin Teske			2> /dev/null )
646*7323adacSDevin Teske		setvar "$__var_to_set" "$__ns"
647*7323adacSDevin Teske	else
648*7323adacSDevin Teske		awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \
649*7323adacSDevin Teske			2> /dev/null
650*7323adacSDevin Teske	fi
651*7323adacSDevin Teske}
652*7323adacSDevin Teske
653*7323adacSDevin Teske# f_config_resolv
654*7323adacSDevin Teske#
655*7323adacSDevin Teske# Attempts to configure resolv.conf(5) and ilk. Returns success if able to
656*7323adacSDevin Teske# write the file(s), otherwise returns error status.
657*7323adacSDevin Teske#
658*7323adacSDevin Teske# Variables from variable.subr that are used in configuring resolv.conf(5) are
659*7323adacSDevin Teske# as follows (all of which can be configured automatically through functions
660*7323adacSDevin Teske# like f_dhcp_get_info() or manually):
661*7323adacSDevin Teske#
662*7323adacSDevin Teske# 	VAR_NAMESERVER
663*7323adacSDevin Teske#		The nameserver to add in resolv.conf(5).
664*7323adacSDevin Teske# 	VAR_DOMAINNAME
665*7323adacSDevin Teske# 		The domain to configure in resolv.conf(5). Also used in the
666*7323adacSDevin Teske# 		configuration of hosts(5).
667*7323adacSDevin Teske# 	VAR_IPADDR
668*7323adacSDevin Teske# 		The IPv4 address to configure in hosts(5).
669*7323adacSDevin Teske# 	VAR_IPV6ADDR
670*7323adacSDevin Teske# 		The IPv6 address to configure in hosts(5).
671*7323adacSDevin Teske# 	VAR_HOSTNAME
672*7323adacSDevin Teske# 		The hostname to associate with the IPv4 and/or IPv6 address in
673*7323adacSDevin Teske# 		hosts(5).
674*7323adacSDevin Teske#
675*7323adacSDevin Teskef_config_resolv()
676*7323adacSDevin Teske{
677*7323adacSDevin Teske	local cp c6p dp hp
678*7323adacSDevin Teske
679*7323adacSDevin Teske	f_getvar $VAR_NAMESERVER cp
680*7323adacSDevin Teske	if [ "$cp" ]; then
681*7323adacSDevin Teske		case "$RESOLV_CONF" in
682*7323adacSDevin Teske		*/*) f_quietly mkdir -p "${RESOLV_CONF%/*}" ;;
683*7323adacSDevin Teske		esac
684*7323adacSDevin Teske
685*7323adacSDevin Teske		# Attempt to create/truncate the file
686*7323adacSDevin Teske		( :> "$RESOLV_CONF" ) 2> /dev/null || return $FAILURE
687*7323adacSDevin Teske
688*7323adacSDevin Teske		f_getvar $VAR_DOMAINNAME dp &&
689*7323adacSDevin Teske			printf "domain\t%s\n" "$dp" >> "$RESOLV_CONF"
690*7323adacSDevin Teske		printf "nameserver\t%s\n" "$cp" >> "$RESOLV_CONF"
691*7323adacSDevin Teske
692*7323adacSDevin Teske		f_dprintf "Wrote out %s" "$RESOLV_CONF"
693*7323adacSDevin Teske	fi
694*7323adacSDevin Teske
695*7323adacSDevin Teske	f_getvar $VAR_DOMAINNAME dp
696*7323adacSDevin Teske	f_getvar $VAR_IPADDR cp
697*7323adacSDevin Teske	f_getvar $VAR_IPV6ADDR c6p
698*7323adacSDevin Teske	f_getvar $VAR_HOSTNAME hp
699*7323adacSDevin Teske
700*7323adacSDevin Teske	# Attempt to create the file if it doesn't already exist
701*7323adacSDevin Teske	if [ ! -e "$ETC_HOSTS" ]; then
702*7323adacSDevin Teske		case "$ETC_HOSTS" in
703*7323adacSDevin Teske		*/*) f_quietly mkdir -p "${ETC_HOSTS%/*}" ;;
704*7323adacSDevin Teske		esac
705*7323adacSDevin Teske
706*7323adacSDevin Teske		( :> "$ETC_HOSTS" ) 2> /dev/null || return $FAILURE
707*7323adacSDevin Teske	fi
708*7323adacSDevin Teske
709*7323adacSDevin Teske	# Scan the file and add ourselves if not already configured
710*7323adacSDevin Teske	awk -v dn="$dp" -v ip4="$cp" -v ip6="$c6p" -v hn="$hp" '
711*7323adacSDevin Teske		BEGIN {
712*7323adacSDevin Teske			local4found = local6found = 0
713*7323adacSDevin Teske			hn4found = hn6found = h4found = h6found = 0
714*7323adacSDevin Teske			h = ( match(hn, /\./) ? substr(hn, 0, RSTART-1) : "" )
715*7323adacSDevin Teske		}
716*7323adacSDevin Teske		($1 == "127.0.0.1") { local4found = 1 }
717*7323adacSDevin Teske		($1 == "::1") { local6found = 1 }
718*7323adacSDevin Teske		{
719*7323adacSDevin Teske			for (n = 2; n <= NF; n++)
720*7323adacSDevin Teske			{
721*7323adacSDevin Teske				if ( $1 == ip4 ) {
722*7323adacSDevin Teske					if ( $n == h ) h4found = 1
723*7323adacSDevin Teske					if ( $n == hn ) hn4found = 1
724*7323adacSDevin Teske					if ( $n == hn "." ) hn4found = 1
725*7323adacSDevin Teske				}
726*7323adacSDevin Teske				if ( $1 == ip6 ) {
727*7323adacSDevin Teske					if ( $n == h ) h6found = 1
728*7323adacSDevin Teske					if ( $n == hn ) hn6found = 1
729*7323adacSDevin Teske					if ( $n == hn "." ) hn6found = 1
730*7323adacSDevin Teske				}
731*7323adacSDevin Teske			}
732*7323adacSDevin Teske		}
733*7323adacSDevin Teske		END {
734*7323adacSDevin Teske			hosts = FILENAME
735*7323adacSDevin Teske
736*7323adacSDevin Teske			if ( ! local6found )
737*7323adacSDevin Teske				printf "::1\t\t\tlocalhost%s\n",
738*7323adacSDevin Teske				       ( dn ? " localhost." dn : "" ) >> hosts
739*7323adacSDevin Teske			if ( ! local4found )
740*7323adacSDevin Teske				printf "127.0.0.1\t\tlocalhost%s\n",
741*7323adacSDevin Teske				       ( dn ? " localhost." dn : "" ) >> hosts
742*7323adacSDevin Teske
743*7323adacSDevin Teske			if ( ip6 && ! (h6found && hn6found))
744*7323adacSDevin Teske			{
745*7323adacSDevin Teske				printf "%s\t%s %s\n", ip6, hn, h >> hosts
746*7323adacSDevin Teske				printf "%s\t%s.\n", ip6, hn >> hosts
747*7323adacSDevin Teske			}
748*7323adacSDevin Teske			else if ( ip6 )
749*7323adacSDevin Teske			{
750*7323adacSDevin Teske				if ( ! h6found )
751*7323adacSDevin Teske					printf "%s\t%s.\n", ip6, h >> hosts
752*7323adacSDevin Teske				if ( ! hn6found )
753*7323adacSDevin Teske					printf "%s\t%s\n", ip6, hn >> hosts
754*7323adacSDevin Teske			}
755*7323adacSDevin Teske
756*7323adacSDevin Teske			if ( ip4 && ! (h4found && hn4found))
757*7323adacSDevin Teske			{
758*7323adacSDevin Teske				printf "%s\t\t%s %s\n", ip4, hn, h >> hosts
759*7323adacSDevin Teske				printf "%s\t\t%s.\n", ip4, hn >> hosts
760*7323adacSDevin Teske			}
761*7323adacSDevin Teske			else if ( ip4 )
762*7323adacSDevin Teske			{
763*7323adacSDevin Teske				if ( ! h4found )
764*7323adacSDevin Teske					printf "%s\t\t%s.\n", ip4, h >> hosts
765*7323adacSDevin Teske				if ( ! hn4found )
766*7323adacSDevin Teske					printf "%s\t\t%s\n", ip4, hn >> hosts
767*7323adacSDevin Teske			}
768*7323adacSDevin Teske		}
769*7323adacSDevin Teske	' "$ETC_HOSTS" 2> /dev/null || return $FAILURE
770*7323adacSDevin Teske
771*7323adacSDevin Teske	f_dprintf "Wrote out %s" "$ETC_HOSTS"
772*7323adacSDevin Teske	return $SUCCESS
773*7323adacSDevin Teske}
774*7323adacSDevin Teske
775*7323adacSDevin Teske# f_dhcp_parse_leases $leasefile struct_name
776*7323adacSDevin Teske#
777*7323adacSDevin Teske# Parse $leasefile and store the information for the most recent lease in a
778*7323adacSDevin Teske# struct (see struct.subr for additional details) named `struct_name'. See
779*7323adacSDevin Teske# DHCP_LEASE struct definition in the GLOBALS section above.
780*7323adacSDevin Teske#
781*7323adacSDevin Teskef_dhcp_parse_leases()
782*7323adacSDevin Teske{
783*7323adacSDevin Teske	local leasefile="$1" struct_name="$2"
784*7323adacSDevin Teske
785*7323adacSDevin Teske	[ "$struct_name" ] || return $FAILURE
786*7323adacSDevin Teske
787*7323adacSDevin Teske	if [ ! -e "$leasefile" ]; then
788*7323adacSDevin Teske		f_dprintf "%s: No such file or directory" "$leasefile"
789*7323adacSDevin Teske		return $FAILURE
790*7323adacSDevin Teske	fi
791*7323adacSDevin Teske
792*7323adacSDevin Teske	f_struct "$struct_name" && f_struct_free "$struct_name"
793*7323adacSDevin Teske	f_struct_new DHCP_LEASE "$struct_name"
794*7323adacSDevin Teske
795*7323adacSDevin Teske	eval "$( awk -v struct="$struct_name" '
796*7323adacSDevin Teske		BEGIN {
797*7323adacSDevin Teske			lease_found = 0
798*7323adacSDevin Teske			keyword_list = " \
799*7323adacSDevin Teske				interface	\
800*7323adacSDevin Teske				fixed-address	\
801*7323adacSDevin Teske				filename	\
802*7323adacSDevin Teske				server-name	\
803*7323adacSDevin Teske				script		\
804*7323adacSDevin Teske				medium		\
805*7323adacSDevin Teske			"
806*7323adacSDevin Teske			split(keyword_list, keywords, FS)
807*7323adacSDevin Teske
808*7323adacSDevin Teske			time_list = "renew rebind expire"
809*7323adacSDevin Teske			split(time_list, times, FS)
810*7323adacSDevin Teske
811*7323adacSDevin Teske			option_list = " \
812*7323adacSDevin Teske				host-name		\
813*7323adacSDevin Teske				subnet-mask		\
814*7323adacSDevin Teske				routers			\
815*7323adacSDevin Teske				domain-name-servers	\
816*7323adacSDevin Teske				domain-name		\
817*7323adacSDevin Teske				broadcast-address	\
818*7323adacSDevin Teske				dhcp-lease-time		\
819*7323adacSDevin Teske				dhcp-message-type	\
820*7323adacSDevin Teske				dhcp-server-identifier	\
821*7323adacSDevin Teske				dhcp-renewal-time	\
822*7323adacSDevin Teske				dhcp-rebinding-time	\
823*7323adacSDevin Teske			"
824*7323adacSDevin Teske			split(option_list, options, FS)
825*7323adacSDevin Teske		}
826*7323adacSDevin Teske		function set_value(prop,value)
827*7323adacSDevin Teske		{
828*7323adacSDevin Teske			lease_found = 1
829*7323adacSDevin Teske			gsub(/[^[:alnum:]_]/, "_", prop)
830*7323adacSDevin Teske			sub(/;$/, "", value)
831*7323adacSDevin Teske			sub(/^"/, "", value)
832*7323adacSDevin Teske			sub(/"$/, "", value)
833*7323adacSDevin Teske			sub(/,.*/, "", value)
834*7323adacSDevin Teske			printf "%s set %s \"%s\"\n", struct, prop, value
835*7323adacSDevin Teske		}
836*7323adacSDevin Teske		/^lease {$/, /^}$/ \
837*7323adacSDevin Teske		{
838*7323adacSDevin Teske			if ( $0 ~ /^lease {$/ ) next
839*7323adacSDevin Teske			if ( $0 ~ /^}$/ ) exit
840*7323adacSDevin Teske
841*7323adacSDevin Teske			for (k in keywords)
842*7323adacSDevin Teske			{
843*7323adacSDevin Teske				keyword = keywords[k]
844*7323adacSDevin Teske				if ( $1 == keyword )
845*7323adacSDevin Teske				{
846*7323adacSDevin Teske					set_value(keyword, $2)
847*7323adacSDevin Teske					next
848*7323adacSDevin Teske				}
849*7323adacSDevin Teske			}
850*7323adacSDevin Teske
851*7323adacSDevin Teske			for (t in times)
852*7323adacSDevin Teske			{
853*7323adacSDevin Teske				time = times[t]
854*7323adacSDevin Teske				if ( $1 == time )
855*7323adacSDevin Teske				{
856*7323adacSDevin Teske					set_value(time, $2 " " $3 " " $4)
857*7323adacSDevin Teske					next
858*7323adacSDevin Teske				}
859*7323adacSDevin Teske			}
860*7323adacSDevin Teske
861*7323adacSDevin Teske			if ( $1 != "option" ) next
862*7323adacSDevin Teske			for (o in options)
863*7323adacSDevin Teske			{
864*7323adacSDevin Teske				option = options[o]
865*7323adacSDevin Teske				if ( $2 == option )
866*7323adacSDevin Teske				{
867*7323adacSDevin Teske					set_value(option, $3)
868*7323adacSDevin Teske					next
869*7323adacSDevin Teske				}
870*7323adacSDevin Teske			}
871*7323adacSDevin Teske		}
872*7323adacSDevin Teske		EXIT {
873*7323adacSDevin Teske			if ( ! lease_found )
874*7323adacSDevin Teske			{
875*7323adacSDevin Teske				printf "f_struct_free \"%s\"\n", struct
876*7323adacSDevin Teske				print "return $FAILURE"
877*7323adacSDevin Teske			}
878*7323adacSDevin Teske		}
879*7323adacSDevin Teske	' "$leasefile" )"
880*7323adacSDevin Teske}
881*7323adacSDevin Teske
882*7323adacSDevin Teske# f_dhcp_get_info $interface
883*7323adacSDevin Teske#
884*7323adacSDevin Teske# Parse the dhclient(8) lease database for $interface to obtain all the
885*7323adacSDevin Teske# necessary IPv4 details necessary to communicate on the network. The retrieved
886*7323adacSDevin Teske# information is stored in VAR_IPADDR, VAR_NETMASK, VAR_GATEWAY, and
887*7323adacSDevin Teske# VAR_NAMESERVER.
888*7323adacSDevin Teske#
889*7323adacSDevin Teske# If reading the lease database fails, values are obtained from ifconfig(8) and
890*7323adacSDevin Teske# route(8). If the DHCP lease did not provide a nameserver (or likewise, we
891*7323adacSDevin Teske# were unable to parse the lease database), fall-back to resolv.conf(5) for
892*7323adacSDevin Teske# obtaining the nameserver. Always returns success.
893*7323adacSDevin Teske#
894*7323adacSDevin Teskef_dhcp_get_info()
895*7323adacSDevin Teske{
896*7323adacSDevin Teske	local interface="$1" cp
897*7323adacSDevin Teske	local leasefile="/var/db/dhclient.leases.$interface"
898*7323adacSDevin Teske
899*7323adacSDevin Teske	# If it fails, do it the old-fashioned way
900*7323adacSDevin Teske	if f_dhcp_parse_leases "$leasefile" lease; then
901*7323adacSDevin Teske		lease get fixed_address $VAR_IPADDR
902*7323adacSDevin Teske		lease get subnet_mask $VAR_NETMASK
903*7323adacSDevin Teske		lease get routers cp
904*7323adacSDevin Teske		setvar $VAR_GATEWAY "${cp%%,*}"
905*7323adacSDevin Teske		lease get domain_name_servers cp
906*7323adacSDevin Teske		setvar $VAR_NAMESERVER "${cp%%,*}"
907*7323adacSDevin Teske		lease get host_name cp &&
908*7323adacSDevin Teske			setvar $VAR_HOSTNAME "$cp"
909*7323adacSDevin Teske		f_struct_free lease
910*7323adacSDevin Teske	else
911*7323adacSDevin Teske		# Bah, now we have to get the information from ifconfig
912*7323adacSDevin Teske		if f_debugging; then
913*7323adacSDevin Teske			f_dprintf "DHCP configured interface returns %s" \
914*7323adacSDevin Teske			          "$( ifconfig "$interface" )"
915*7323adacSDevin Teske		fi
916*7323adacSDevin Teske		f_ifconfig_inet "$interface" $VAR_IPADDR
917*7323adacSDevin Teske		f_ifconfig_netmask "$interface" $VAR_NETMASK
918*7323adacSDevin Teske		f_route_get_default $VAR_GATEWAY
919*7323adacSDevin Teske	fi
920*7323adacSDevin Teske
921*7323adacSDevin Teske	# If we didn't get a name server value, hunt for it in resolv.conf
922*7323adacSDevin Teske	local ns
923*7323adacSDevin Teske	if [ -r "$RESOLV_CONF" ] && ! {
924*7323adacSDevin Teske		f_getvar $VAR_NAMESERVER ns || [ "$ns" ]
925*7323adacSDevin Teske	}; then
926*7323adacSDevin Teske		f_resolv_conf_nameservers cp &&
927*7323adacSDevin Teske			setvar $VAR_NAMESERVER ${cp%%[$IFS]*}
928*7323adacSDevin Teske	fi
929*7323adacSDevin Teske
930*7323adacSDevin Teske	return $SUCCESS
931*7323adacSDevin Teske}
932*7323adacSDevin Teske
933*7323adacSDevin Teske# f_rtsol_get_info $interface
934*7323adacSDevin Teske#
935*7323adacSDevin Teske# Returns the rtsol-provided IPv6 address associated with $interface. The
936*7323adacSDevin Teske# retrieved IP address is stored in VAR_IPV6ADDR. Always returns success.
937*7323adacSDevin Teske#
938*7323adacSDevin Teskef_rtsol_get_info()
939*7323adacSDevin Teske{
940*7323adacSDevin Teske	local interface="$1" cp
941*7323adacSDevin Teske	cp=$( ifconfig "$interface" 2> /dev/null | awk \
942*7323adacSDevin Teske	'
943*7323adacSDevin Teske		BEGIN { found = 0 }
944*7323adacSDevin Teske		( $1 == "inet6" ) && ( $2 ~ /^fe80:/ ) \
945*7323adacSDevin Teske		{
946*7323adacSDevin Teske			print $2
947*7323adacSDevin Teske			found = 1
948*7323adacSDevin Teske			exit
949*7323adacSDevin Teske		}
950*7323adacSDevin Teske		END { exit ! found }
951*7323adacSDevin Teske	' ) && setvar $VAR_IPV6ADDR "$cp"
952*7323adacSDevin Teske}
953*7323adacSDevin Teske
954*7323adacSDevin Teske# f_host_lookup $host [$var_to_set]
955*7323adacSDevin Teske#
956*7323adacSDevin Teske# Use host(1) to lookup (or reverse) an Internet number from (or to) a name.
957*7323adacSDevin Teske# Multiple answers are returned separated by a single space. If host(1) does
958*7323adacSDevin Teske# not exit cleanly, its full output is provided and the return status is 1.
959*7323adacSDevin Teske#
960*7323adacSDevin Teske# If nsswitch.conf(5) has been configured to query local access first for the
961*7323adacSDevin Teske# `hosts' database, we'll manually check hosts(5) first (preventing host(1)
962*7323adacSDevin Teske# from hanging in the event that DNS goes awry).
963*7323adacSDevin Teske#
964*7323adacSDevin Teske# If $var_to_set is missing or NULL, the list of IP addresses is printed to
965*7323adacSDevin Teske# standard output for capturing in a sub-shell (which is less-recommended
966*7323adacSDevin Teske# because of performance degredation; for example, when called in a loop).
967*7323adacSDevin Teske#
968*7323adacSDevin Teske# The variables from variable.subr used in looking up the host are as follows
969*7323adacSDevin Teske# (which are set manually):
970*7323adacSDevin Teske#
971*7323adacSDevin Teske# 	VAR_IPV6_ENABLE [Optional]
972*7323adacSDevin Teske# 		If set to "YES", enables the lookup of IPv6 addresses and IPv4
973*7323adacSDevin Teske# 		address. IPv6 addresses, if any, will come before IPv4. Note
974*7323adacSDevin Teske# 		that if nsswitch.conf(5) shows an affinity for "files" for the
975*7323adacSDevin Teske# 		"host" database and there is a valid entry in hosts(5) for
976*7323adacSDevin Teske# 		$host, this setting currently has no effect (an IPv4 address
977*7323adacSDevin Teske# 		can supersede an IPv6 address). By design, hosts(5) overrides
978*7323adacSDevin Teske# 		any preferential treatment. Otherwise, if this variable is not
979*7323adacSDevin Teske# 		set, IPv6 addresses will not be used (IPv4 addresses will
980*7323adacSDevin Teske# 		specifically be requested from DNS).
981*7323adacSDevin Teske#
982*7323adacSDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
983*7323adacSDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
984*7323adacSDevin Teske#
985*7323adacSDevin Teskef_host_lookup_awk='
986*7323adacSDevin TeskeBEGIN{ addrs = "" }
987*7323adacSDevin Teske!/^[[:space:]]*(#|$)/ \
988*7323adacSDevin Teske{
989*7323adacSDevin Teske	for (n=1; n++ < NF;) if ($n == name)
990*7323adacSDevin Teske		addrs = addrs (addrs ? " " : "") $1
991*7323adacSDevin Teske}
992*7323adacSDevin TeskeEND {
993*7323adacSDevin Teske	if (addrs) print addrs
994*7323adacSDevin Teske	exit !addrs
995*7323adacSDevin Teske}
996*7323adacSDevin Teske'
997*7323adacSDevin Teskef_host_lookup()
998*7323adacSDevin Teske{
999*7323adacSDevin Teske	local __host="$1" __var_to_set="$2"
1000*7323adacSDevin Teske	f_dprintf "f_host_lookup: host=[%s]" "$__host"
1001*7323adacSDevin Teske
1002*7323adacSDevin Teske	# If we're configured to look at local files first, do that
1003*7323adacSDevin Teske	if awk '/^hosts:/{exit !($2=="files")}' "$NSSWITCH_CONF"; then
1004*7323adacSDevin Teske		if [ "$__var_to_set" ]; then
1005*7323adacSDevin Teske			local __cp
1006*7323adacSDevin Teske			if __cp=$( awk -v name="$__host" \
1007*7323adacSDevin Teske				"$f_host_lookup_awk" "$ETC_HOSTS" )
1008*7323adacSDevin Teske			then
1009*7323adacSDevin Teske				setvar "$__var_to_set" "$__cp"
1010*7323adacSDevin Teske				return $SUCCESS
1011*7323adacSDevin Teske			fi
1012*7323adacSDevin Teske		else
1013*7323adacSDevin Teske			awk -v name="$__host" \
1014*7323adacSDevin Teske				"$f_host_lookup_awk" "$ETC_HOSTS" &&
1015*7323adacSDevin Teske				return $SUCCESS
1016*7323adacSDevin Teske		fi
1017*7323adacSDevin Teske	fi
1018*7323adacSDevin Teske
1019*7323adacSDevin Teske	#
1020*7323adacSDevin Teske	# Fall back to host(1) -- which is further governed by nsswitch.conf(5)
1021*7323adacSDevin Teske	#
1022*7323adacSDevin Teske
1023*7323adacSDevin Teske	local __output __ip6 __addrs="" __wait=""
1024*7323adacSDevin Teske	f_getvar $VAR_MEDIA_TIMEOUT __wait
1025*7323adacSDevin Teske	[ "$__wait" ] && __wait="-W $(( $__wait / 2 ))"
1026*7323adacSDevin Teske	f_getvar $VAR_IPV6_ENABLE __ip6
1027*7323adacSDevin Teske	if [ "$__ip6" = "YES" ]; then
1028*7323adacSDevin Teske		if ! __output=$( host -t AAAA $__wait -- "$__host" 2>&1 ); then
1029*7323adacSDevin Teske			# An error occurred, display in-full and return error
1030*7323adacSDevin Teske			[ "$__var_to_set" ] &&
1031*7323adacSDevin Teske				setvar "$__var_to_set" "$__output"
1032*7323adacSDevin Teske			return $FAILURE
1033*7323adacSDevin Teske		fi
1034*7323adacSDevin Teske		__addrs=$( echo "$__output" | awk '/ address /{print $NF}' )
1035*7323adacSDevin Teske	fi
1036*7323adacSDevin Teske	if ! __output=$( host -t A $__wait -- "$__host" 2>&1 ); then
1037*7323adacSDevin Teske		# An error occurred, display it in-full and return error
1038*7323adacSDevin Teske		[ "$__var_to_set" ] && setvar "$__var_to_set" "$__output"
1039*7323adacSDevin Teske		return $FAILURE
1040*7323adacSDevin Teske	fi
1041*7323adacSDevin Teske	__addrs="$__addrs${__addrs:+ }$(
1042*7323adacSDevin Teske		echo "$__output" | awk '/ address /{print $NF}' )"
1043*7323adacSDevin Teske	if [ "$__var_to_set" ]; then
1044*7323adacSDevin Teske		setvar "$__var_to_set" "$__addrs"
1045*7323adacSDevin Teske	else
1046*7323adacSDevin Teske		echo $__addrs
1047*7323adacSDevin Teske	fi
1048*7323adacSDevin Teske}
1049*7323adacSDevin Teske
1050*7323adacSDevin Teske# f_device_dialog_tcp $device
1051*7323adacSDevin Teske#
1052*7323adacSDevin Teske# This is it - how to get TCP setup values. Prompt the user to edit/confirm the
1053*7323adacSDevin Teske# interface, gateway, nameserver, and hostname settings -- all required for
1054*7323adacSDevin Teske# general TCP/IP access.
1055*7323adacSDevin Teske#
1056*7323adacSDevin Teske# Variables from variable.subr that can be used to sript user input:
1057*7323adacSDevin Teske#
1058*7323adacSDevin Teske# 	VAR_NO_INET6
1059*7323adacSDevin Teske# 		If set, prevents asking the user if they would like to use
1060*7323adacSDevin Teske# 		rtsol(8) to check for an IPv6 router.
1061*7323adacSDevin Teske# 	VAR_TRY_RTSOL
1062*7323adacSDevin Teske# 		If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the
1063*7323adacSDevin Teske# 		user if they would like to try the IPv6 RouTer SOLicitation
1064*7323adacSDevin Teske# 		utility (rtsol(8)) to get IPv6 information. Ignored if
1065*7323adacSDevin Teske# 		VAR_NO_INET6 is set.
1066*7323adacSDevin Teske# 	VAR_TRY_DHCP
1067*7323adacSDevin Teske# 		If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the
1068*7323adacSDevin Teske# 		user if they would like to try to acquire IPv4 connection
1069*7323adacSDevin Teske# 		settings from a DHCP server using dhclient(8).
1070*7323adacSDevin Teske#
1071*7323adacSDevin Teske# 	VAR_GATEWAY	Default gateway to use.
1072*7323adacSDevin Teske# 	VAR_IPADDR	Interface address to assign.
1073*7323adacSDevin Teske# 	VAR_NETMASK	Interface subnet mask.
1074*7323adacSDevin Teske# 	VAR_EXTRAS	Extra interface options to ifconfig(8).
1075*7323adacSDevin Teske# 	VAR_HOSTNAME	Hostname to set.
1076*7323adacSDevin Teske# 	VAR_DOMAINNAME	Domain name to use.
1077*7323adacSDevin Teske# 	VAR_NAMESERVER	DNS nameserver to use when making lookups.
1078*7323adacSDevin Teske# 	VAR_IPV6ADDR	IPv6 interface address.
1079*7323adacSDevin Teske#
1080*7323adacSDevin Teske# In addition, the following variables are used in acquiring network settings
1081*7323adacSDevin Teske# from the user:
1082*7323adacSDevin Teske#
1083*7323adacSDevin Teske# 	VAR_NONINTERACTIVE
1084*7323adacSDevin Teske# 		If set (such as when running in a script), prevents asking the
1085*7323adacSDevin Teske# 		user questions or displaying the usual prompts, etc.
1086*7323adacSDevin Teske# 	VAR_NETINTERACTIVE
1087*7323adacSDevin Teske# 		The one exception to VAR_NONINTERACTIVE is VAR_NETINTERACTIVE,
1088*7323adacSDevin Teske# 		which if set will prompt the user to try RTSOL (unless
1089*7323adacSDevin Teske# 		VAR_TRY_RTSOL has been set), try DHCP (unless VAR_TRY_DHCP has
1090*7323adacSDevin Teske# 		been set), and display the network verification dialog. This
1091*7323adacSDevin Teske# 		allows you to have a mostly non-interactive script that still
1092*7323adacSDevin Teske# 		prompts for network setup/confirmation.
1093*7323adacSDevin Teske#
1094*7323adacSDevin Teske# After successfull execution, the following variables are set:
1095*7323adacSDevin Teske#
1096*7323adacSDevin Teske# 	VAR_IFCONFIG + $device (e.g., `ifconfig_em0')
1097*7323adacSDevin Teske#               Defines the ifconfig(8) properties specific to $device.
1098*7323adacSDevin Teske#
1099*7323adacSDevin Teskef_device_dialog_tcp()
1100*7323adacSDevin Teske{
1101*7323adacSDevin Teske	local dev="$1" cp n
1102*7323adacSDevin Teske	local use_dhcp="" use_rtsol=""
1103*7323adacSDevin Teske	local _ipaddr _netmask _extras
1104*7323adacSDevin Teske
1105*7323adacSDevin Teske	[ "$dev" ] || return $FAILURE
1106*7323adacSDevin Teske
1107*7323adacSDevin Teske	# Initialize vars from previous device values
1108*7323adacSDevin Teske	local private
1109*7323adacSDevin Teske	device_$dev get private private
1110*7323adacSDevin Teske	if [ "$private" ] && f_struct "$private"; then
1111*7323adacSDevin Teske		$private get ipaddr    _ipaddr
1112*7323adacSDevin Teske		$private get netmask   _netmask
1113*7323adacSDevin Teske		$private get extras    _extras
1114*7323adacSDevin Teske		$private get use_dhcp  use_dhcp
1115*7323adacSDevin Teske		$private get use_rtsol use_rtsol
1116*7323adacSDevin Teske	else # See if there are any defaults
1117*7323adacSDevin Teske
1118*7323adacSDevin Teske		#
1119*7323adacSDevin Teske		# This is a hack so that the dialogs below are interactive in a
1120*7323adacSDevin Teske		# script if we have requested interactive behavior.
1121*7323adacSDevin Teske		#
1122*7323adacSDevin Teske		local old_interactive=
1123*7323adacSDevin Teske		if ! f_interactive && f_netinteractive; then
1124*7323adacSDevin Teske			f_getvar $VAR_NONINTERACTIVE old_interactive
1125*7323adacSDevin Teske			unset $VAR_NONINTERACTIVE
1126*7323adacSDevin Teske		fi
1127*7323adacSDevin Teske
1128*7323adacSDevin Teske
1129*7323adacSDevin Teske		#
1130*7323adacSDevin Teske		# Try a RTSOL scan if such behavior is desired.
1131*7323adacSDevin Teske		# If the variable was configured and is YES, do it.
1132*7323adacSDevin Teske		# If it was configured to anything else, treat it as NO.
1133*7323adacSDevin Teske		# Otherwise, ask the question interactively.
1134*7323adacSDevin Teske		#
1135*7323adacSDevin Teske		local try6
1136*7323adacSDevin Teske		if ! f_quietly f_getvar $VAR_NO_INET6 && {
1137*7323adacSDevin Teske		   { f_getvar $VAR_TRY_RTSOL try6 && [ "$try6" = "YES" ]; } ||
1138*7323adacSDevin Teske		   {
1139*7323adacSDevin Teske			! f_quietly f_getvar $VAR_TRY_RTSOL &&
1140*7323adacSDevin Teske			f_dialog_noyes "$msg_try_ipv6_configuration"
1141*7323adacSDevin Teske		   }
1142*7323adacSDevin Teske		}; then
1143*7323adacSDevin Teske			local i
1144*7323adacSDevin Teske
1145*7323adacSDevin Teske			f_quietly sysctl net.inet6.ip6.forwarding=0
1146*7323adacSDevin Teske			f_quietly sysctl net.inet6.ip6.accept_rtadv=1
1147*7323adacSDevin Teske			f_quietly ifconfig $dev up
1148*7323adacSDevin Teske
1149*7323adacSDevin Teske			i=$( sysctl -n net.inet6.ip6.dad_count )
1150*7323adacSDevin Teske			sleep $(( $i + 1 ))
1151*7323adacSDevin Teske
1152*7323adacSDevin Teske			f_quietly mkdir -p /var/run
1153*7323adacSDevin Teske			f_dialog_info "$msg_scanning_for_ra_servers"
1154*7323adacSDevin Teske			if f_quietly rtsol $dev; then
1155*7323adacSDevin Teske				i=$( sysctl -n net.inet6.ip6.dad_count )
1156*7323adacSDevin Teske				sleep $(( $i + 1 ))
1157*7323adacSDevin Teske				f_rtsol_get_info $dev
1158*7323adacSDevin Teske				use_rtsol=1
1159*7323adacSDevin Teske			else
1160*7323adacSDevin Teske				use_rtsol=
1161*7323adacSDevin Teske			fi
1162*7323adacSDevin Teske		fi
1163*7323adacSDevin Teske
1164*7323adacSDevin Teske		#
1165*7323adacSDevin Teske		# Try a DHCP scan if such behavior is desired.
1166*7323adacSDevin Teske		# If the variable was configured and is YES, do it.
1167*7323adacSDevin Teske		# If it was configured to anything else, treat it as NO.
1168*7323adacSDevin Teske		# Otherwise, ask the question interactively.
1169*7323adacSDevin Teske		#
1170*7323adacSDevin Teske		local try4
1171*7323adacSDevin Teske		if { f_getvar $VAR_TRY_DHCP try4 && [ "$try4" = "YES" ]; } || {
1172*7323adacSDevin Teske			! f_quietly f_getvar $VAR_TRY_DHCP &&
1173*7323adacSDevin Teske			f_dialog_noyes "$msg_try_dhcp_configuration"
1174*7323adacSDevin Teske		}; then
1175*7323adacSDevin Teske			f_quietly ifconfig $dev delete
1176*7323adacSDevin Teske			f_quietly mkdir -p /var/db
1177*7323adacSDevin Teske			f_quietly mkdir -p /var/run
1178*7323adacSDevin Teske			f_quietly mkdir -p /tmp
1179*7323adacSDevin Teske
1180*7323adacSDevin Teske			local msg="$msg_scanning_for_dhcp_servers"
1181*7323adacSDevin Teske			trap - SIGINT
1182*7323adacSDevin Teske			( # Execute in sub-shell to allow/catch Ctrl-C
1183*7323adacSDevin Teske			  trap 'exit $FAILURE' SIGINT
1184*7323adacSDevin Teske			  if [ "$USE_XDIALOG" ]; then
1185*7323adacSDevin Teske			  	f_quietly dhclient $dev |
1186*7323adacSDevin Teske			  			f_xdialog_info "$msg"
1187*7323adacSDevin Teske			  else
1188*7323adacSDevin Teske			  	f_dialog_info "$msg"
1189*7323adacSDevin Teske			  	f_quietly dhclient $dev
1190*7323adacSDevin Teske			  fi
1191*7323adacSDevin Teske			)
1192*7323adacSDevin Teske			local retval=$?
1193*7323adacSDevin Teske			trap 'f_interrupt' SIGINT
1194*7323adacSDevin Teske			if [ $retval -eq $SUCCESS ]; then
1195*7323adacSDevin Teske				f_dhcp_get_info $dev
1196*7323adacSDevin Teske				use_dhcp=1
1197*7323adacSDevin Teske			else
1198*7323adacSDevin Teske				use_dhcp=
1199*7323adacSDevin Teske			fi
1200*7323adacSDevin Teske		fi
1201*7323adacSDevin Teske
1202*7323adacSDevin Teske		# Restore old VAR_NONINTERACTIVE if needed.
1203*7323adacSDevin Teske		[ "$old_interactive" ] &&
1204*7323adacSDevin Teske			setvar $VAR_NONINTERACTIVE "$old_interactive"
1205*7323adacSDevin Teske
1206*7323adacSDevin Teske		# Special hack so it doesn't show up oddly in the menu
1207*7323adacSDevin Teske		local gw
1208*7323adacSDevin Teske		if f_getvar $VAR_GATEWAY gw && [ "$gw" = "NO" ]; then
1209*7323adacSDevin Teske			setvar $VAR_GATEWAY ""
1210*7323adacSDevin Teske		fi
1211*7323adacSDevin Teske
1212*7323adacSDevin Teske		# Get old IP address from variable space, if available
1213*7323adacSDevin Teske		if [ ! "$_ipaddr" ]; then
1214*7323adacSDevin Teske			if f_getvar $VAR_IPADDR cp; then
1215*7323adacSDevin Teske				_ipaddr="$cp"
1216*7323adacSDevin Teske			elif f_getvar ${dev}_$VAR_IPADDR cp; then
1217*7323adacSDevin Teske				_ipaddr="$cp"
1218*7323adacSDevin Teske			fi
1219*7323adacSDevin Teske		fi
1220*7323adacSDevin Teske
1221*7323adacSDevin Teske		# Get old netmask from variable space, if available
1222*7323adacSDevin Teske		if [ ! "$_netmask" ]; then
1223*7323adacSDevin Teske			if f_getvar $VAR_NETMASK cp; then
1224*7323adacSDevin Teske				_netmask="$cp"
1225*7323adacSDevin Teske			elif f_getvar ${dev}_$VAR_NETMASK cp; then
1226*7323adacSDevin Teske				_netmask="$cp"
1227*7323adacSDevin Teske			fi
1228*7323adacSDevin Teske		fi
1229*7323adacSDevin Teske
1230*7323adacSDevin Teske		# Get old extras string from variable space, if available
1231*7323adacSDevin Teske		if [ ! "$_extras" ]; then
1232*7323adacSDevin Teske			if f_getvar $VAR_EXTRAS cp; then
1233*7323adacSDevin Teske				_extras="$cp"
1234*7323adacSDevin Teske			elif f_getvar ${dev}_$VAR_EXTRAS cp; then
1235*7323adacSDevin Teske				_extras="$cp"
1236*7323adacSDevin Teske			fi
1237*7323adacSDevin Teske		fi
1238*7323adacSDevin Teske	fi
1239*7323adacSDevin Teske
1240*7323adacSDevin Teske	# Look up values already recorded with the system, or blank the string
1241*7323adacSDevin Teske	# variables ready to accept some new data
1242*7323adacSDevin Teske	local _hostname _gateway _nameserver
1243*7323adacSDevin Teske	f_getvar $VAR_HOSTNAME _hostname
1244*7323adacSDevin Teske	case "$_hostname" in
1245*7323adacSDevin Teske	*.*) : do nothing ;; # Already fully-qualified
1246*7323adacSDevin Teske	*)
1247*7323adacSDevin Teske		f_getvar $VAR_DOMAINNAME cp
1248*7323adacSDevin Teske		[ "$cp" ] && _hostname="$_hostname.$cp"
1249*7323adacSDevin Teske	esac
1250*7323adacSDevin Teske	f_getvar $VAR_GATEWAY _gateway
1251*7323adacSDevin Teske	f_getvar $VAR_NAMESERVER _nameserver
1252*7323adacSDevin Teske
1253*7323adacSDevin Teske	# Re-check variables for initial inheritance before heading into dialog
1254*7323adacSDevin Teske	[ "$_hostname" ] || _hostname="${HOSTNAME:-$( hostname )}"
1255*7323adacSDevin Teske	[ "$_gateway" ] || f_route_get_default _gateway
1256*7323adacSDevin Teske	[ ! "$_nameserver" ] &&
1257*7323adacSDevin Teske		f_resolv_conf_nameservers cp && _nameserver=${cp%%[$IFS]*}
1258*7323adacSDevin Teske	[ "$_ipaddr" ] || f_ifconfig_inet $dev _ipaddr
1259*7323adacSDevin Teske	[ "$_netmask" ] || f_ifconfig_netmask $dev _netmask
1260*7323adacSDevin Teske
1261*7323adacSDevin Teske	# If non-interactive, jump over dialog section and into config section
1262*7323adacSDevin Teske	if f_netinteractive || f_interactive || [ ! "$_hostname" ]
1263*7323adacSDevin Teske	then
1264*7323adacSDevin Teske		[ ! "$_hostname" ] && f_interactive &&
1265*7323adacSDevin Teske			f_dialog_msgbox "$msg_hostname_variable_not_set"
1266*7323adacSDevin Teske
1267*7323adacSDevin Teske		local title=" $msg_network_configuration "
1268*7323adacSDevin Teske		local hline="$hline_alnum_arrows_punc_tab_enter"
1269*7323adacSDevin Teske		local extras_help="$tcplayout_extras_help"
1270*7323adacSDevin Teske
1271*7323adacSDevin Teske		# Modify the help line for PLIP config
1272*7323adacSDevin Teske		[ "${dev#plip}" != "$dev" ] &&
1273*7323adacSDevin Teske			extras_help="$tcplayout_extras_help_for_plip"
1274*7323adacSDevin Teske
1275*7323adacSDevin Teske		f_getvar $VAR_IPV6ADDR cp && [ "$cp" ] &&
1276*7323adacSDevin Teske			title="$title($msg_ipv6_ready) "
1277*7323adacSDevin Teske
1278*7323adacSDevin Teske		if [ ! "$USE_XDIALOG" ]; then
1279*7323adacSDevin Teske			local prompt="$msg_dialog_mixedform_navigation_help"
1280*7323adacSDevin Teske			# Calculate center position for displaying device label
1281*7323adacSDevin Teske			local devlabel="$msg_configuration_for_interface $dev"
1282*7323adacSDevin Teske			local width=54
1283*7323adacSDevin Teske			local n=$(( $width/2 - (${#devlabel} + 4)/2 - 2 ))
1284*7323adacSDevin Teske
1285*7323adacSDevin Teske			while :; do
1286*7323adacSDevin Teske				cp=$( $DIALOG \
1287*7323adacSDevin Teske					--title "$title"                     \
1288*7323adacSDevin Teske					--backtitle "$DIALOG_BACKTITLE"      \
1289*7323adacSDevin Teske					--hline "$hline"                     \
1290*7323adacSDevin Teske					--item-help                          \
1291*7323adacSDevin Teske					--ok-label "$msg_ok"                 \
1292*7323adacSDevin Teske					--cancel-label "$msg_cancel"         \
1293*7323adacSDevin Teske					--help-button                        \
1294*7323adacSDevin Teske					--help-label "$msg_help"             \
1295*7323adacSDevin Teske					--mixedform "$prompt" 16 $width 9    \
1296*7323adacSDevin Teske					"$msg_host_name_including_domain:" 1 2 \
1297*7323adacSDevin Teske						"$_hostname" 2 3 45 255 0    \
1298*7323adacSDevin Teske						"$tcplayout_hostname_help"   \
1299*7323adacSDevin Teske					"$msg_ipv4_gateway:" 3 2             \
1300*7323adacSDevin Teske						"$_gateway" 4 3 16 15 0      \
1301*7323adacSDevin Teske						"$tcplayout_gateway_help"    \
1302*7323adacSDevin Teske					"$msg_name_server:" 3 31             \
1303*7323adacSDevin Teske						"$_nameserver" 4 32 16 15 0  \
1304*7323adacSDevin Teske						"$tcplayout_nameserver_help" \
1305*7323adacSDevin Teske					"- $devlabel -" 5 $n "" 0 0 0 0 3 "" \
1306*7323adacSDevin Teske					"$msg_ipv4_address:" 6 6             \
1307*7323adacSDevin Teske						"$_ipaddr" 7 7 16 15 0       \
1308*7323adacSDevin Teske						"$tcplayout_ipaddr_help"     \
1309*7323adacSDevin Teske					"$msg_netmask:" 6 31                 \
1310*7323adacSDevin Teske						"$_netmask" 7 32 16 15 0     \
1311*7323adacSDevin Teske						"$tcplayout_netmask_help"    \
1312*7323adacSDevin Teske					"$msg_extra_options_to_ifconfig" 8 6 \
1313*7323adacSDevin Teske						"$_extras" 9 7 41 2048 0     \
1314*7323adacSDevin Teske						"$extras_help"               \
1315*7323adacSDevin Teske					2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
1316*7323adacSDevin Teske
1317*7323adacSDevin Teske				# --mixed-form always returns 0, we have to
1318*7323adacSDevin Teske				# use the returned data to determine button
1319*7323adacSDevin Teske				if [ ! "$cp" ]; then
1320*7323adacSDevin Teske					# User either chose "Cancel", pressed
1321*7323adacSDevin Teske					# ESC, or blanked every form field
1322*7323adacSDevin Teske					return $FAILURE
1323*7323adacSDevin Teske				else
1324*7323adacSDevin Teske					n=$( echo "$cp" | f_number_of_lines )
1325*7323adacSDevin Teske					[ $n -eq 1 ] && case "$cp" in HELP*)
1326*7323adacSDevin Teske						# User chose "Help"
1327*7323adacSDevin Teske						f_show_help "$TCP_HELPFILE"
1328*7323adacSDevin Teske						continue
1329*7323adacSDevin Teske					esac
1330*7323adacSDevin Teske				fi
1331*7323adacSDevin Teske
1332*7323adacSDevin Teske				# Turn mixed-form results into env variables
1333*7323adacSDevin Teske				eval "$( echo "$cp" | awk '
1334*7323adacSDevin Teske				BEGIN {
1335*7323adacSDevin Teske					n = 0
1336*7323adacSDevin Teske					field[++n] = "_hostname"
1337*7323adacSDevin Teske					field[++n] = "_gateway"
1338*7323adacSDevin Teske					field[++n] = "_nameserver"
1339*7323adacSDevin Teske					field[++n] = "_ipaddr"
1340*7323adacSDevin Teske					field[++n] = "_netmask"
1341*7323adacSDevin Teske					field[++n] = "_extras"
1342*7323adacSDevin Teske					nfields = n
1343*7323adacSDevin Teske					n = 0
1344*7323adacSDevin Teske				}
1345*7323adacSDevin Teske				{
1346*7323adacSDevin Teske					gsub(/'\''/, "'\'\\\\\'\''")
1347*7323adacSDevin Teske					sub(/[[:space:]]*$/, "")
1348*7323adacSDevin Teske					value[field[++n]] = $0
1349*7323adacSDevin Teske				}
1350*7323adacSDevin Teske				END {
1351*7323adacSDevin Teske					for ( n = 1; n <= nfields; n++ )
1352*7323adacSDevin Teske					{
1353*7323adacSDevin Teske						printf "%s='\''%s'\'';\n",
1354*7323adacSDevin Teske						       field[n],
1355*7323adacSDevin Teske						       value[field[n]]
1356*7323adacSDevin Teske					}
1357*7323adacSDevin Teske				}' )"
1358*7323adacSDevin Teske
1359*7323adacSDevin Teske				f_dialog_validate_tcpip \
1360*7323adacSDevin Teske					"$_hostname" \
1361*7323adacSDevin Teske					"$_gateway" \
1362*7323adacSDevin Teske					"$_nameserver" \
1363*7323adacSDevin Teske					"$_ipaddr" \
1364*7323adacSDevin Teske					"$_netmask" \
1365*7323adacSDevin Teske					&& break
1366*7323adacSDevin Teske			done
1367*7323adacSDevin Teske		else
1368*7323adacSDevin Teske			# Xdialog(1) does not support --mixed-form
1369*7323adacSDevin Teske			# Create a persistent menu instead
1370*7323adacSDevin Teske
1371*7323adacSDevin Teske			f_dialog_title "$msg_network_configuration"
1372*7323adacSDevin Teske			local prompt=""
1373*7323adacSDevin Teske
1374*7323adacSDevin Teske			while :; do
1375*7323adacSDevin Teske				cp=$( $DIALOG \
1376*7323adacSDevin Teske					--title "$DIALOG_TITLE"               \
1377*7323adacSDevin Teske					--backtitle "$DIALOG_BACKTITLE"       \
1378*7323adacSDevin Teske					--hline "$hline"                      \
1379*7323adacSDevin Teske					--item-help                           \
1380*7323adacSDevin Teske					--ok-label "$msg_ok"                  \
1381*7323adacSDevin Teske					--cancel-label "$msg_cancel"          \
1382*7323adacSDevin Teske					--help ""                             \
1383*7323adacSDevin Teske					--menu "$prompt" 21 60 8              \
1384*7323adacSDevin Teske					"$msg_accept_continue" ""             \
1385*7323adacSDevin Teske						"$tcplayout_accept_cont_help" \
1386*7323adacSDevin Teske					"$msg_host_name_including_domain:"    \
1387*7323adacSDevin Teske						"$_hostname"                  \
1388*7323adacSDevin Teske						"$tcplayout_hostname_help"    \
1389*7323adacSDevin Teske					"$msg_ipv4_gateway:" "$_gateway"      \
1390*7323adacSDevin Teske						"$tcplayout_gateway_help"     \
1391*7323adacSDevin Teske					"$msg_name_server:" "$_nameserver"    \
1392*7323adacSDevin Teske						"$tcplayout_nameserver_help"  \
1393*7323adacSDevin Teske					"$msg_ipv4_address:" "$_ipaddr"       \
1394*7323adacSDevin Teske						"$tcplayout_ipaddr_help"      \
1395*7323adacSDevin Teske					"$msg_netmask:" "$_netmask"           \
1396*7323adacSDevin Teske						"$tcplayout_netmask_help"     \
1397*7323adacSDevin Teske					"$msg_extra_options_to_ifconfig"      \
1398*7323adacSDevin Teske						"$_extras" "$extras_help"     \
1399*7323adacSDevin Teske					2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1400*7323adacSDevin Teske				)
1401*7323adacSDevin Teske				local retval=$?
1402*7323adacSDevin Teske				f_dprintf "retval=%u mtag=[%s]" $retval "$cp"
1403*7323adacSDevin Teske
1404*7323adacSDevin Teske				if [ $retval -eq 2 ]; then
1405*7323adacSDevin Teske					# The Help button was pressed
1406*7323adacSDevin Teske					f_show_help "$TCP_HELPFILE"
1407*7323adacSDevin Teske					continue
1408*7323adacSDevin Teske				elif [ $retval -ne 0 ]; then
1409*7323adacSDevin Teske					# User chose "Cancel" or pressed ESC
1410*7323adacSDevin Teske					f_dialog_title_restore
1411*7323adacSDevin Teske					return $FAILURE
1412*7323adacSDevin Teske				fi
1413*7323adacSDevin Teske
1414*7323adacSDevin Teske				case "$cp" in
1415*7323adacSDevin Teske				"$msg_accept_continue")
1416*7323adacSDevin Teske					f_dialog_validate_tcpip \
1417*7323adacSDevin Teske						"$_hostname" \
1418*7323adacSDevin Teske						"$_gateway" \
1419*7323adacSDevin Teske						"$_nameserver" \
1420*7323adacSDevin Teske						"$_ipaddr" \
1421*7323adacSDevin Teske						"$_netmask" \
1422*7323adacSDevin Teske						&& break ;;
1423*7323adacSDevin Teske				"$msg_host_name_including_domain:")
1424*7323adacSDevin Teske					cp=$( f_dialog_input "$cp" \
1425*7323adacSDevin Teske					                     "$_hostname"
1426*7323adacSDevin Teske					    ) && _hostname="$cp" ;;
1427*7323adacSDevin Teske				"$msg_ipv4_gateway:")
1428*7323adacSDevin Teske					cp=$( f_dialog_input "$cp" \
1429*7323adacSDevin Teske					                     "$_gateway"
1430*7323adacSDevin Teske					    ) && _gateway="$cp" ;;
1431*7323adacSDevin Teske				"$msg_name_server:")
1432*7323adacSDevin Teske					cp=$( f_dialog_input "$cp" \
1433*7323adacSDevin Teske					                     "$_nameserver"
1434*7323adacSDevin Teske					    ) && _nameserver="$cp" ;;
1435*7323adacSDevin Teske				"$msg_ipv4_address:")
1436*7323adacSDevin Teske					cp=$( f_dialog_input "$cp" \
1437*7323adacSDevin Teske					                     "$_ipaddr"
1438*7323adacSDevin Teske					    ) && _ipaddr="$cp" ;;
1439*7323adacSDevin Teske				"$msg_netmask:")
1440*7323adacSDevin Teske					cp=$( f_dialog_input "$cp" \
1441*7323adacSDevin Teske					                     "$_netmask"
1442*7323adacSDevin Teske					    ) && _netmask="$cp" ;;
1443*7323adacSDevin Teske				"$msg_extra_options_to_ifconfig")
1444*7323adacSDevin Teske					cp=$( f_dialog_input "$cp" \
1445*7323adacSDevin Teske					                     "$_extras"
1446*7323adacSDevin Teske					    ) && _extras="$cp" ;;
1447*7323adacSDevin Teske				esac
1448*7323adacSDevin Teske			done
1449*7323adacSDevin Teske
1450*7323adacSDevin Teske			f_dialog_title_restore
1451*7323adacSDevin Teske
1452*7323adacSDevin Teske		fi # XDIALOG
1453*7323adacSDevin Teske
1454*7323adacSDevin Teske	fi # interactive
1455*7323adacSDevin Teske
1456*7323adacSDevin Teske	# We actually need to inform the rest of bsdconfig about this
1457*7323adacSDevin Teske	# data now if the user hasn't selected cancel.
1458*7323adacSDevin Teske
1459*7323adacSDevin Teske	if [ "$_hostname" ]; then
1460*7323adacSDevin Teske		setvar $VAR_HOSTNAME "$_hostname"
1461*7323adacSDevin Teske		f_quietly hostname "$_hostname"
1462*7323adacSDevin Teske		case "$_hostname" in
1463*7323adacSDevin Teske		*.*) setvar $VAR_DOMAINNAME "${_hostname#*.}" ;;
1464*7323adacSDevin Teske		esac
1465*7323adacSDevin Teske	fi
1466*7323adacSDevin Teske	[ "$_gateway"    ] && setvar $VAR_GATEWAY    "$_gateway"
1467*7323adacSDevin Teske	[ "$_nameserver" ] && setvar $VAR_NAMESERVER "$_nameserver"
1468*7323adacSDevin Teske	[ "$_ipaddr"     ] && setvar $VAR_IPADDR     "$_ipaddr"
1469*7323adacSDevin Teske	[ "$_netmask"    ] && setvar $VAR_NETMASK    "$_netmask"
1470*7323adacSDevin Teske	[ "$_extras"     ] && setvar $VAR_EXTRAS     "$_extras"
1471*7323adacSDevin Teske
1472*7323adacSDevin Teske	f_dprintf "Creating struct DEVICE_INFO devinfo_%s" "$dev"
1473*7323adacSDevin Teske	f_struct_new DEVICE_INFO devinfo_$dev
1474*7323adacSDevin Teske	device_$dev set private devinfo_$dev
1475*7323adacSDevin Teske
1476*7323adacSDevin Teske	devinfo_$dev set ipaddr    $_ipaddr
1477*7323adacSDevin Teske	devinfo_$dev set netmask   $_netmask
1478*7323adacSDevin Teske	devinfo_$dev set extras    $_extras
1479*7323adacSDevin Teske	devinfo_$dev set use_rtsol $use_rtsol
1480*7323adacSDevin Teske	devinfo_$dev set use_dhcp  $use_dhcp
1481*7323adacSDevin Teske
1482*7323adacSDevin Teske	if [ "$use_dhcp" -o "$_ipaddr" ]; then
1483*7323adacSDevin Teske		if [ "$use_dhcp" ]; then
1484*7323adacSDevin Teske			cp="DHCP${extras:+ $extras}"
1485*7323adacSDevin Teske		else
1486*7323adacSDevin Teske			cp="inet $_ipaddr netmask $_netmask${extras:+ $extras}"
1487*7323adacSDevin Teske		fi
1488*7323adacSDevin Teske		setvar $VAR_IFCONFIG$dev "$cp"
1489*7323adacSDevin Teske	fi
1490*7323adacSDevin Teske	[ "$use_rtsol" ] &&
1491*7323adacSDevin Teske		setvar $VAR_IPV6_ENABLE "YES"
1492*7323adacSDevin Teske
1493*7323adacSDevin Teske	[ "$use_dhcp" ] ||
1494*7323adacSDevin Teske		f_config_resolv # XXX this will do it on the MFS copy
1495*7323adacSDevin Teske
1496*7323adacSDevin Teske	return $SUCCESS
1497*7323adacSDevin Teske}
1498*7323adacSDevin Teske
1499*7323adacSDevin Teske# f_device_scan_tcp [$var_to_set]
1500*7323adacSDevin Teske#
1501*7323adacSDevin Teske# Scan for the first active/configured TCP/IP device. The name of the interface
1502*7323adacSDevin Teske# is printed to stderr like other dialog(1)-based functions (stdout is reserved
1503*7323adacSDevin Teske# for dialog(1) interaction) if $var_to_set is missing or NULL. Returns failure
1504*7323adacSDevin Teske# if no active/configured interface
1505*7323adacSDevin Teske#
1506*7323adacSDevin Teskef_device_scan_tcp()
1507*7323adacSDevin Teske{
1508*7323adacSDevin Teske	local __var_to_set="$1" __iface
1509*7323adacSDevin Teske	for __iface in $( ifconfig -l ); do
1510*7323adacSDevin Teske		if ifconfig $__iface | awk '
1511*7323adacSDevin Teske		BEGIN {
1512*7323adacSDevin Teske			has_inet = has_inet6 = is_ethernet = 0
1513*7323adacSDevin Teske			is_usable = 1
1514*7323adacSDevin Teske		}
1515*7323adacSDevin Teske		( $1 == "status:" && $2 != "active" ) { is_usable = 0; exit }
1516*7323adacSDevin Teske		( $1 == "inet" ) {
1517*7323adacSDevin Teske			if ($2 == "0.0.0.0") { is_usable = 0; exit }
1518*7323adacSDevin Teske			has_inet++
1519*7323adacSDevin Teske		}
1520*7323adacSDevin Teske		( $1 == "inet6") { has_inet6++ }
1521*7323adacSDevin Teske		( $1 == "media:" ) {
1522*7323adacSDevin Teske			if ($2 != "Ethernet") { is_usable = 0; exit }
1523*7323adacSDevin Teske			is_ethernet = 1
1524*7323adacSDevin Teske		}
1525*7323adacSDevin Teske		END {
1526*7323adacSDevin Teske			if (!(is_ethernet && (has_inet || has_inet6)))
1527*7323adacSDevin Teske				is_usable = 0
1528*7323adacSDevin Teske			exit ! is_usable
1529*7323adacSDevin Teske		}'; then
1530*7323adacSDevin Teske			f_interactive &&
1531*7323adacSDevin Teske				f_show_msg "$msg_using_interface" "$__iface"
1532*7323adacSDevin Teske			f_dprintf "f_device_scan_tcp found %s" "$__iface"
1533*7323adacSDevin Teske			if [ "$__var_to_set" ]; then
1534*7323adacSDevin Teske				setvar "$__var_to_set" "$__iface"
1535*7323adacSDevin Teske			else
1536*7323adacSDevin Teske				echo "$__iface" >&2
1537*7323adacSDevin Teske			fi
1538*7323adacSDevin Teske			return $SUCCESS
1539*7323adacSDevin Teske		fi
1540*7323adacSDevin Teske	done
1541*7323adacSDevin Teske
1542*7323adacSDevin Teske	return $FAILURE
1543*7323adacSDevin Teske}
1544*7323adacSDevin Teske
1545*7323adacSDevin Teske# f_device_select_tcp
1546*7323adacSDevin Teske#
1547*7323adacSDevin Teske# Prompt the user to select network interface to use for TCP/IP access.
1548*7323adacSDevin Teske# Variables from variable.subr that can be used to script user input:
1549*7323adacSDevin Teske#
1550*7323adacSDevin Teske# 	VAR_NETWORK_DEVICE [Optional]
1551*7323adacSDevin Teske# 		Either a comma-separated list of network interfaces to try when
1552*7323adacSDevin Teske# 		setting up network access (e.g., "fxp0,em0") or "ANY" (case-
1553*7323adacSDevin Teske# 		sensitive) to indicate that the first active and configured
1554*7323adacSDevin Teske# 		interface is acceptable. If unset, the user is presented with a
1555*7323adacSDevin Teske# 		menu of all available network interfaces.
1556*7323adacSDevin Teske#
1557*7323adacSDevin Teske# Returns success if a valid network interface has been selected.
1558*7323adacSDevin Teske#
1559*7323adacSDevin Teskef_device_select_tcp()
1560*7323adacSDevin Teske{
1561*7323adacSDevin Teske	local devs dev cnt network_dev
1562*7323adacSDevin Teske	f_getvar $VAR_NETWORK_DEVICE network_dev
1563*7323adacSDevin Teske
1564*7323adacSDevin Teske	f_dprintf "f_device_select_tcp: %s=[%s]" \
1565*7323adacSDevin Teske	          VAR_NETWORK_DEVICE "$network_dev"
1566*7323adacSDevin Teske
1567*7323adacSDevin Teske	if [ "$network_dev" ]; then
1568*7323adacSDevin Teske		#
1569*7323adacSDevin Teske		# This can be set to several types of values. If set to ANY,
1570*7323adacSDevin Teske		# scan all network devices looking for a valid link, and go
1571*7323adacSDevin Teske		# with the first device found. Can also be specified as a
1572*7323adacSDevin Teske		# comma delimited list, with each network device tried in
1573*7323adacSDevin Teske		# order. Can also be set to a single network device.
1574*7323adacSDevin Teske		#
1575*7323adacSDevin Teske		[ "$network_dev" = "ANY" ] && f_device_scan_tcp network_dev
1576*7323adacSDevin Teske
1577*7323adacSDevin Teske		while [ "$network_dev" ]; do
1578*7323adacSDevin Teske			case "$network_dev" in
1579*7323adacSDevin Teske			*,*) dev="${network_dev%%,*}"
1580*7323adacSDevin Teske			     network_dev="${network_dev#*,}"
1581*7323adacSDevin Teske			     ;;
1582*7323adacSDevin Teske			  *) dev="$network_dev"
1583*7323adacSDevin Teske			     network_dev=
1584*7323adacSDevin Teske			esac
1585*7323adacSDevin Teske
1586*7323adacSDevin Teske			f_device_find "$dev" $DEVICE_TYPE_NETWORK devs
1587*7323adacSDevin Teske			cnt=$( set -- $devs; echo $# )
1588*7323adacSDevin Teske
1589*7323adacSDevin Teske			if [ ${cnt:=0} -gt 0 ]; then
1590*7323adacSDevin Teske				dev="${devs%%[$IFS]*}"
1591*7323adacSDevin Teske				f_device_dialog_tcp $dev
1592*7323adacSDevin Teske				if [ $? -eq $SUCCESS ]; then
1593*7323adacSDevin Teske					setvar $VAR_NETWORK_DEVICE $dev
1594*7323adacSDevin Teske					return $SUCCESS
1595*7323adacSDevin Teske				fi
1596*7323adacSDevin Teske			fi
1597*7323adacSDevin Teske		done
1598*7323adacSDevin Teske
1599*7323adacSDevin Teske		f_interactive && f_dialog_msgbox "$msg_no_network_devices"
1600*7323adacSDevin Teske		return $FAILURE
1601*7323adacSDevin Teske
1602*7323adacSDevin Teske	fi # $network_dev
1603*7323adacSDevin Teske
1604*7323adacSDevin Teske	f_device_find "" $DEVICE_TYPE_NETWORK devs
1605*7323adacSDevin Teske	cnt=$( set -- $devs; echo $# )
1606*7323adacSDevin Teske	dev="${devs%%[$IFS]*}"
1607*7323adacSDevin Teske
1608*7323adacSDevin Teske	f_quietly f_getvar NETWORK_CONFIGURED # for debugging info
1609*7323adacSDevin Teske	if ! f_running_as_init &&
1610*7323adacSDevin Teske	   ! [ "${NETWORK_CONFIGURED+set}" -a "$NETWORK_CONFIGURED" = "NO" ]
1611*7323adacSDevin Teske	then
1612*7323adacSDevin Teske		trap 'f_interrupt' SIGINT
1613*7323adacSDevin Teske		if f_dialog_yesno "$msg_assume_network_is_already_configured"
1614*7323adacSDevin Teske		then
1615*7323adacSDevin Teske			setvar $VAR_NETWORK_DEVICE $dev
1616*7323adacSDevin Teske			return $SUCCESS
1617*7323adacSDevin Teske		fi
1618*7323adacSDevin Teske	fi
1619*7323adacSDevin Teske
1620*7323adacSDevin Teske	local retval=$SUCCESS
1621*7323adacSDevin Teske	if [ ${cnt:=0} -eq 0 ]; then
1622*7323adacSDevin Teske		f_dialog_msgbox "$msg_no_network_devices"
1623*7323adacSDevin Teske		retval=$FAILURE
1624*7323adacSDevin Teske	elif [ $cnt -eq 1 ]; then
1625*7323adacSDevin Teske		f_device_dialog_tcp $dev
1626*7323adacSDevin Teske		retval=$?
1627*7323adacSDevin Teske		[ $retval -eq $SUCCESS ] && setvar $VAR_NETWORK_DEVICE $dev
1628*7323adacSDevin Teske	else
1629*7323adacSDevin Teske		local title="$msg_network_interface_information_required"
1630*7323adacSDevin Teske		local prompt="$msg_please_select_ethernet_device_to_configure"
1631*7323adacSDevin Teske		local hline="$hline_arrows_tab_enter"
1632*7323adacSDevin Teske
1633*7323adacSDevin Teske		dev=$( f_device_menu \
1634*7323adacSDevin Teske			"$title" "$prompt" "$hline" $DEVICE_TYPE_NETWORK \
1635*7323adacSDevin Teske			"$NETWORK_DEVICE_HELPFILE" \
1636*7323adacSDevin Teske			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
1637*7323adacSDevin Teske		retval=$?
1638*7323adacSDevin Teske		[ "$dev" ] || return $FAILURE
1639*7323adacSDevin Teske
1640*7323adacSDevin Teske		f_device_find "$dev" $DEVICE_TYPE_NETWORK devs
1641*7323adacSDevin Teske		[ "$devs" ] || return $FAILURE
1642*7323adacSDevin Teske		dev="${devs%%[$IFS]*}"
1643*7323adacSDevin Teske
1644*7323adacSDevin Teske		f_device_dialog_tcp $dev
1645*7323adacSDevin Teske		retval=$?
1646*7323adacSDevin Teske		if [ $retval -eq $SUCCESS ]; then
1647*7323adacSDevin Teske			f_struct_copy device_$dev device_network
1648*7323adacSDevin Teske			setvar $VAR_NETWORK_DEVICE network
1649*7323adacSDevin Teske		else
1650*7323adacSDevin Teske			f_struct_free device_network
1651*7323adacSDevin Teske		fi
1652*7323adacSDevin Teske	fi
1653*7323adacSDevin Teske
1654*7323adacSDevin Teske	return $retval
1655*7323adacSDevin Teske}
1656*7323adacSDevin Teske
1657*7323adacSDevin Teske# f_dialog_menu_select_tcp
1658*7323adacSDevin Teske#
1659*7323adacSDevin Teske# Like f_dialog_select_tcp() above, but do it from a menu that doesn't care
1660*7323adacSDevin Teske# about status. In other words, where f_dialog_select_tcp() will not display a
1661*7323adacSDevin Teske# menu if scripted, this function will always display the menu of available
1662*7323adacSDevin Teske# network interfaces.
1663*7323adacSDevin Teske#
1664*7323adacSDevin Teskef_dialog_menu_select_tcp()
1665*7323adacSDevin Teske{
1666*7323adacSDevin Teske	local private use_dhcp name
1667*7323adacSDevin Teske	NETWORK_CONFIGURED=NO f_device_select_tcp
1668*7323adacSDevin Teske	if f_struct device_network &&
1669*7323adacSDevin Teske	   device_network get private private &&
1670*7323adacSDevin Teske	   f_struct_copy "$private" di &&
1671*7323adacSDevin Teske	   di get use_dhcp use_dhcp &&
1672*7323adacSDevin Teske	   [ ! "$use_dhcp" ] &&
1673*7323adacSDevin Teske	   device_network get name name &&
1674*7323adacSDevin Teske	   f_yesno "$msg_would_you_like_to_bring_interface_up" "$name"
1675*7323adacSDevin Teske	then
1676*7323adacSDevin Teske		if ! f_device_init network; then
1677*7323adacSDevin Teske			f_show_msg "$msg_initialization_of_device_failed" \
1678*7323adacSDevin Teske			           "$name"
1679*7323adacSDevin Teske		fi
1680*7323adacSDevin Teske	fi
1681*7323adacSDevin Teske	return $SUCCESS
1682*7323adacSDevin Teske}
1683*7323adacSDevin Teske
1684*7323adacSDevin Teske############################################################ MAIN
1685*7323adacSDevin Teske
1686*7323adacSDevin Teskef_dprintf "%s: Successfully loaded." media/tcpip.subr
1687*7323adacSDevin Teske
1688*7323adacSDevin Teskefi # ! $_MEDIA_TCPIP_SUBR
1689