xref: /freebsd/libexec/rc/network.subr (revision 24e8ed535ff673b9ea751c3d3b2a68ef0a29b0e2)
1#
2# Copyright (c) 2003 The FreeBSD Project. All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions
6# are met:
7# 1. Redistributions of source code must retain the above copyright
8#    notice, this list of conditions and the following disclaimer.
9# 2. Redistributions in binary form must reproduce the above copyright
10#    notice, this list of conditions and the following disclaimer in the
11#    documentation and/or other materials provided with the distribution.
12#
13# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
14# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16# ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
17# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23# SUCH DAMAGE.
24#
25#
26IFCONFIG_CMD="/sbin/ifconfig"
27: ${netif_ipexpand_max:=2048}
28
29#
30# Subroutines commonly used from network startup scripts.
31# Requires that rc.conf be loaded first.
32#
33
34# ifn_start ifn
35#	Bring up and configure an interface.  If some configuration is
36#	applied, print the interface configuration.
37#
38ifn_start()
39{
40	local ifn cfg
41	ifn="$1"
42	cfg=1
43
44	[ -z "$ifn" ] && err 1 "ifn_start called without an interface"
45
46	ifscript_up ${ifn} && cfg=0
47	ifconfig_up ${ifn} && cfg=0
48	if ! noafif $ifn; then
49		afexists inet6 && ipv6_up ${ifn} && cfg=0
50		afexists inet && ipv4_up ${ifn} && cfg=0
51	fi
52	childif_create ${ifn} && cfg=0
53
54	return $cfg
55}
56
57# ifn_stop ifn
58#	Shutdown and de-configure an interface.  If action is taken,
59#	print the interface name.
60#
61ifn_stop()
62{
63	local ifn cfg
64	ifn="$1"
65	cfg=1
66
67	[ -z "$ifn" ] && err 1 "ifn_stop called without an interface"
68
69	if ! noafif $ifn; then
70		afexists inet && ipv4_down ${ifn} && cfg=0
71		afexists inet6 && ipv6_down ${ifn} && cfg=0
72	fi
73	ifconfig_down ${ifn} && cfg=0
74	ifscript_down ${ifn} && cfg=0
75	childif_destroy ${ifn} && cfg=0
76
77	return $cfg
78}
79
80# ifn_vnetup ifn
81#	Move ifn to the specified vnet jail.
82#
83ifn_vnetup()
84{
85
86	ifn_vnet0 $1 vnet
87}
88
89# ifn_vnetdown ifn
90#	Reclaim ifn from the specified vnet jail.
91#
92ifn_vnetdown()
93{
94
95	ifn_vnet0 $1 -vnet
96}
97
98# ifn_vnet0 ifn action
99#	Helper function for ifn_vnetup and ifn_vnetdown.
100#
101ifn_vnet0()
102{
103	local _ifn _cfg _action _vnet
104	_ifn="$1"
105	_action="$2"
106	_cfg=1
107
108	if _vnet=$(vnetif $_ifn); then
109		${IFCONFIG_CMD} $_ifn $_action $_vnet && _cfg=0
110	fi
111
112	return $_cfg
113}
114
115# ifconfig_up if
116#	Evaluate ifconfig(8) arguments for interface $if and
117#	run ifconfig(8) with those arguments. It returns 0 if
118#	arguments were found and executed or 1 if the interface
119#	had no arguments.  Pseudo arguments DHCP and WPA are handled
120#	here.
121#
122ifconfig_up()
123{
124	local _cfg _ifconfig_descr _ipv6_opts ifconfig_args
125	_cfg=1
126
127	# Make sure lo0 always comes up.
128	if [ "$1" = "lo0" ]; then
129		_cfg=0
130	fi
131
132	# inet6 specific
133	if ! noafif $1 && afexists inet6; then
134		if checkyesno ipv6_activate_all_interfaces; then
135			_ipv6_opts="-ifdisabled"
136		fi
137
138		# backward compatibility: $ipv6_enable
139		case $ipv6_enable in
140		[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
141			case $1 in
142			bridge[0-9]*)
143				# No accept_rtadv by default on if_bridge(4)
144				# to avoid a conflict with the member
145				# interfaces.
146			;;
147			*)
148				if ! checkyesno ipv6_gateway_enable; then
149					_ipv6_opts="${_ipv6_opts} accept_rtadv"
150				fi
151			;;
152			esac
153		;;
154		esac
155
156		case $ipv6_cpe_wanif in
157		$1)
158			_ipv6_opts="${_ipv6_opts} -no_radr accept_rtadv"
159		;;
160		esac
161
162		if [ -n "${_ipv6_opts}" ]; then
163			${IFCONFIG_CMD} $1 inet6 ${_ipv6_opts}
164		fi
165	fi
166
167	# ifconfig_IF
168	ifconfig_args=`ifconfig_getargs $1`
169	if [ -n "${ifconfig_args}" ]; then
170		eval ${IFCONFIG_CMD} $1 ${ifconfig_args}
171		_cfg=0
172	fi
173
174	# inet6 specific
175	if ! noafif $1 && afexists inet6; then
176		# ifconfig_IF_ipv6
177		ifconfig_args=`ifconfig_getargs $1 ipv6`
178		if [ -n "${ifconfig_args}" ]; then
179			# backward compatibility: inet6 keyword
180			case "${ifconfig_args}" in
181			:*|[0-9a-fA-F]*:*)
182				warn "\$ifconfig_$1_ipv6 needs leading" \
183				    "\"inet6\" keyword for an IPv6 address."
184				ifconfig_args="inet6 ${ifconfig_args}"
185			;;
186			esac
187			${IFCONFIG_CMD} $1 inet6 -ifdisabled
188			eval ${IFCONFIG_CMD} $1 ${ifconfig_args}
189			_cfg=0
190		fi
191
192		# $ipv6_prefix_IF will be handled in
193		# ipv6_prefix_hostid_addr_common().
194		ifconfig_args=`get_if_var $1 ipv6_prefix_IF`
195		if [ -n "${ifconfig_args}" ]; then
196			${IFCONFIG_CMD} $1 inet6 -ifdisabled
197			_cfg=0
198		fi
199
200		# backward compatibility: $ipv6_ifconfig_IF
201		ifconfig_args=`get_if_var $1 ipv6_ifconfig_IF`
202		if [ -n "${ifconfig_args}" ]; then
203			warn "\$ipv6_ifconfig_$1 is obsolete." \
204			    "  Use ifconfig_$1_ipv6 instead."
205			${IFCONFIG_CMD} $1 inet6 -ifdisabled
206			eval ${IFCONFIG_CMD} $1 inet6 ${ifconfig_args}
207			_cfg=0
208		fi
209	fi
210
211	ifalias $1 link alias
212	ifalias $1 ether alias
213
214	_ifconfig_descr=`get_if_var $1 ifconfig_IF_descr`
215	if [ -n "${_ifconfig_descr}" ]; then
216		${IFCONFIG_CMD} $1 description "${_ifconfig_descr}"
217	fi
218
219	if wpaif $1; then
220		/etc/rc.d/wpa_supplicant start $1
221		_cfg=0		# XXX: not sure this should count
222	elif hostapif $1; then
223		/etc/rc.d/hostapd start $1
224		_cfg=0
225	elif [ ${_cfg} -eq 0 ]; then
226		${IFCONFIG_CMD} $1 up
227	fi
228
229	if ! noafif $1 && afexists inet6; then
230		ipv6_accept_rtadv_up $1 && _cfg=0
231	fi
232
233	if dhcpif $1; then
234		if [ $_cfg -ne 0 ] ; then
235			${IFCONFIG_CMD} $1 up
236		fi
237		if syncdhcpif $1; then
238			/etc/rc.d/dhclient start $1
239		fi
240		_cfg=0
241	fi
242
243	return $_cfg
244}
245
246# ifconfig_down if
247#	returns 1 if wpa_supplicant or dhclient was stopped or
248#	the interface exists.
249#
250ifconfig_down()
251{
252	local _cfg
253	_cfg=1
254
255	if wpaif $1; then
256		/etc/rc.d/wpa_supplicant stop $1
257		_cfg=0
258	elif hostapif $1; then
259		/etc/rc.d/hostapd stop $1
260		_cfg=0
261	elif dhcpif $1; then
262		/etc/rc.d/dhclient stop $1
263		_cfg=0
264	fi
265
266	if ifexists $1; then
267		${IFCONFIG_CMD} $1 down
268		_cfg=0
269	fi
270
271	return $_cfg
272}
273
274# get_if_var if var [default]
275#	Return the value of the pseudo-hash corresponding to $if where
276#	$var is a string containg the sub-string "IF" which will be
277#	replaced with $if after the characters defined in _punct are
278#	replaced with '_'. If the variable is unset, replace it with
279#	$default if given.
280get_if_var()
281{
282	local _if _punct _punct_c _var _default prefix suffix
283
284	if [ $# -ne 2 -a $# -ne 3 ]; then
285		err 3 'USAGE: get_if_var name var [default]'
286	fi
287
288	_if=$1
289	_punct=".-/+"
290	ltr ${_if} "${_punct}" '_' _if
291	_var=$2
292	_default=$3
293
294	prefix=${_var%%IF*}
295	suffix=${_var##*IF}
296	eval echo \${${prefix}${_if}${suffix}-${_default}}
297}
298
299# _ifconfig_getargs if [af]
300#	Prints the arguments for the supplied interface to stdout.
301#	Returns 1 if empty.  In general, ifconfig_getargs should be used
302#	outside this file.
303_ifconfig_getargs()
304{
305	local _ifn _af
306	_ifn=$1
307	_af=${2+_$2}
308
309	if [ -z "$_ifn" ]; then
310		return 1
311	fi
312
313	get_if_var $_ifn ifconfig_IF$_af "$ifconfig_DEFAULT"
314}
315
316# ifconfig_getargs if [af]
317#	Takes the result from _ifconfig_getargs and removes pseudo
318#	args such as DHCP and WPA.
319ifconfig_getargs()
320{
321	local _tmpargs _arg _args _vnet
322	_tmpargs=`_ifconfig_getargs $1 $2`
323	if [ $? -eq 1 ]; then
324		return 1
325	fi
326	_args=
327	_vnet=0
328
329	for _arg in $_tmpargs; do
330		case $_arg:$_vnet in
331		[Dd][Hh][Cc][Pp]:0) ;;
332		[Nn][Oo][Aa][Uu][Tt][Oo]:0) ;;
333		[Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]:0) ;;
334		[Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]:0) ;;
335		[Ww][Pp][Aa]:0) ;;
336		[Hh][Oo][Ss][Tt][Aa][Pp]:0) ;;
337		vnet:0)	_vnet=1 ;;
338		*:1)	_vnet=0 ;;
339		*:0)
340			_args="$_args $_arg"
341		;;
342		esac
343	done
344
345	echo $_args
346}
347
348# autoif
349#	Returns 0 if the interface should be automatically configured at
350#	boot time and 1 otherwise.
351autoif()
352{
353	local _tmpargs _arg
354	_tmpargs=`_ifconfig_getargs $1`
355
356	for _arg in $_tmpargs; do
357		case $_arg in
358		[Nn][Oo][Aa][Uu][Tt][Oo])
359			return 1
360			;;
361		esac
362	done
363
364	return 0
365}
366
367# dhcpif if
368#	Returns 0 if the interface is a DHCP interface and 1 otherwise.
369dhcpif()
370{
371	local _tmpargs _arg
372	_tmpargs=`_ifconfig_getargs $1`
373
374	case $1 in
375	lo[0-9]*|\
376	stf[0-9]*|\
377	lp[0-9]*|\
378	sl[0-9]*)
379		return 1
380		;;
381	esac
382	if noafif $1; then
383		return 1
384	fi
385
386	for _arg in $_tmpargs; do
387		case $_arg in
388		[Dd][Hh][Cc][Pp])
389			return 0
390			;;
391		[Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
392			return 0
393			;;
394		[Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
395			return 0
396			;;
397		esac
398	done
399
400	return 1
401}
402
403# syncdhcpif
404#	Returns 0 if the interface should be configured synchronously and
405#	1 otherwise.
406syncdhcpif()
407{
408	local _tmpargs _arg
409	_tmpargs=`_ifconfig_getargs $1`
410
411	if noafif $1; then
412		return 1
413	fi
414
415	for _arg in $_tmpargs; do
416		case $_arg in
417		[Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
418			return 1
419			;;
420		[Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
421			return 0
422			;;
423		esac
424	done
425
426	checkyesno synchronous_dhclient
427}
428
429# wpaif if
430#	Returns 0 if the interface is a WPA interface and 1 otherwise.
431wpaif()
432{
433	local _tmpargs _arg
434	_tmpargs=`_ifconfig_getargs $1`
435
436	for _arg in $_tmpargs; do
437		case $_arg in
438		[Ww][Pp][Aa])
439			return 0
440			;;
441		esac
442	done
443
444	return 1
445}
446
447# hostapif if
448#	Returns 0 if the interface is a HOSTAP interface and 1 otherwise.
449hostapif()
450{
451	local _tmpargs _arg
452	_tmpargs=`_ifconfig_getargs $1`
453
454	for _arg in $_tmpargs; do
455		case $_arg in
456		[Hh][Oo][Ss][Tt][Aa][Pp])
457			return 0
458			;;
459		esac
460	done
461
462	return 1
463}
464
465# vnetif if
466#	Returns 0 and echo jail if "vnet" keyword is specified on the
467#	interface, and 1 otherwise.
468vnetif()
469{
470	local _tmpargs _arg _vnet
471	_tmpargs=`_ifconfig_getargs $1`
472
473	_vnet=0
474	for _arg in $_tmpargs; do
475		case $_arg:$_vnet in
476		vnet:0)	_vnet=1 ;;
477		*:1)	echo $_arg; return 0 ;;
478		esac
479	done
480
481	return 1
482}
483
484# afexists af
485#	Returns 0 if the address family is enabled in the kernel
486#	1 otherwise.
487afexists()
488{
489	local _af
490	_af=$1
491
492	case ${_af} in
493	inet|inet6)
494		check_kern_features ${_af}
495		;;
496	link|ether)
497		return 0
498		;;
499	*)
500		err 1 "afexists(): Unsupported address family: $_af"
501		;;
502	esac
503}
504
505# noafif if
506#	Returns 0 if the interface has no af configuration and 1 otherwise.
507noafif()
508{
509	local _if
510	_if=$1
511
512	case $_if in
513	pflog[0-9]*|\
514	pfsync[0-9]*|\
515	usbus[0-9]*|\
516	an[0-9]*|\
517	ath[0-9]*|\
518	ipw[0-9]*|\
519	ipfw[0-9]*|\
520	iwi[0-9]*|\
521	iwn[0-9]*|\
522	ral[0-9]*|\
523	wi[0-9]*|\
524	wl[0-9]*|\
525	wpi[0-9]*)
526		return 0
527		;;
528	esac
529
530	return 1
531}
532
533# ipv6if if
534#	Returns 0 if the interface should be configured for IPv6 and
535#	1 otherwise.
536ipv6if()
537{
538	local _if _tmpargs i
539	_if=$1
540
541	if ! afexists inet6; then
542		return 1
543	fi
544
545	# lo0 is always IPv6-enabled
546	case $_if in
547	lo0)
548		return 0
549		;;
550	esac
551
552	case "${ipv6_network_interfaces}" in
553	$_if|"$_if "*|*" $_if"|*" $_if "*|[Aa][Uu][Tt][Oo])
554		# True if $ifconfig_IF_ipv6 is defined.
555		_tmpargs=`_ifconfig_getargs $_if ipv6`
556		if [ -n "${_tmpargs}" ]; then
557			return 0
558		fi
559
560		# True if $ipv6_prefix_IF is defined.
561		_tmpargs=`get_if_var $_if ipv6_prefix_IF`
562		if [ -n "${_tmpargs}" ]; then
563			return 0
564		fi
565
566		# backward compatibility: True if $ipv6_ifconfig_IF is defined.
567		_tmpargs=`get_if_var $_if ipv6_ifconfig_IF`
568		if [ -n "${_tmpargs}" ]; then
569			return 0
570		fi
571		;;
572	esac
573
574	return 1
575}
576
577# ipv6_autoconfif if
578#	Returns 0 if the interface should be configured for IPv6 with
579#	Stateless Address Configuration; 1 otherwise.
580ipv6_autoconfif()
581{
582	local _if _tmpargs _arg
583	_if=$1
584
585	case $_if in
586	lo[0-9]*|\
587	stf[0-9]*|\
588	lp[0-9]*|\
589	sl[0-9]*)
590		return 1
591		;;
592	esac
593	if noafif $_if; then
594		return 1
595	fi
596	if ! ipv6if $_if; then
597		return 1
598	fi
599	if checkyesno ipv6_gateway_enable; then
600		return 1
601	fi
602	_tmpargs=`get_if_var $_if ipv6_prefix_IF`
603	if [ -n "${_tmpargs}" ]; then
604		return 1
605	fi
606	# backward compatibility: $ipv6_enable
607	case $ipv6_enable in
608	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
609		if checkyesno ipv6_gateway_enable; then
610			return 1
611		fi
612		case $1 in
613		bridge[0-9]*)
614			# No accept_rtadv by default on if_bridge(4)
615			# to avoid a conflict with the member
616			# interfaces.
617			return 1
618		;;
619		*)
620			return 0
621		;;
622		esac
623	;;
624	esac
625
626	_tmpargs=`_ifconfig_getargs $_if ipv6`
627	for _arg in $_tmpargs; do
628		case $_arg in
629		accept_rtadv)
630			return 0
631			;;
632		esac
633	done
634
635	# backward compatibility: $ipv6_ifconfig_IF
636	_tmpargs=`get_if_var $_if ipv6_ifconfig_IF`
637	for _arg in $_tmpargs; do
638		case $_arg in
639		accept_rtadv)
640			return 0
641			;;
642		esac
643	done
644
645	return 1
646}
647
648# ifexists if
649#	Returns 0 if the interface exists and 1 otherwise.
650ifexists()
651{
652	[ -z "$1" ] && return 1
653	${IFCONFIG_CMD} -n $1 > /dev/null 2>&1
654}
655
656# ifisup if
657#	Returns 0 if the interface exists and UP,
658#	returns 1 if the interface exists and not UP,
659#	returns 2 otherwise.
660ifisup()
661{
662	local _if
663
664	[ -z "$1" ] && return 2
665	_if="$1"
666
667	set -- $(${IFCONFIG_CMD} -n ${_if} 2>/dev/null)
668	case "$1$2" in
669		${_if}:*'<UP'[,\>]*)	return 0 ;;
670		${_if}:*)	 	return 1 ;;
671	esac
672
673	return 2
674}
675
676# ipv4_up if
677#	add IPv4 addresses to the interface $if
678ipv4_up()
679{
680	local _if _ret
681	_if=$1
682	_ret=1
683
684	# Add 127.0.0.1/8 to lo0 unless otherwise specified.
685	if [ "${_if}" = "lo0" ]; then
686		ifconfig_args=`get_if_var ${_if} ifconfig_IF`
687		if [ -z "${ifconfig_args}" ]; then
688			${IFCONFIG_CMD} ${_if} inet 127.0.0.1/8 alias
689		fi
690	fi
691	ifalias ${_if} inet alias && _ret=0
692
693	return $_ret
694}
695
696# ipv6_up if
697#	add IPv6 addresses to the interface $if
698ipv6_up()
699{
700	local _if _ret
701	_if=$1
702	_ret=1
703
704	if ! ipv6if $_if; then
705		return 0
706	fi
707
708	ifalias ${_if} inet6 alias && _ret=0
709	ipv6_prefix_hostid_addr_common ${_if} alias && _ret=0
710
711	return $_ret
712}
713
714# ipv4_down if
715#	remove IPv4 addresses from the interface $if
716ipv4_down()
717{
718	local _if _ifs _ret inetList oldifs _inet
719	_if=$1
720	_ifs="^"
721	_ret=1
722
723	ifalias ${_if} inet -alias && _ret=0
724
725	inetList="`${IFCONFIG_CMD} ${_if} | grep 'inet ' | tr "\n\t" "$_ifs"`"
726
727	oldifs="$IFS"
728	IFS="$_ifs"
729	for _inet in $inetList ; do
730		# get rid of extraneous line
731		case $_inet in
732		inet[[:space:]]*)	;;
733		*)		continue ;;
734		esac
735
736		_inet=`expr "$_inet" : '.*\(inet \([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*'`
737
738		IFS="$oldifs"
739		${IFCONFIG_CMD} ${_if} ${_inet} delete
740		IFS="$_ifs"
741		_ret=0
742	done
743	IFS="$oldifs"
744
745	return $_ret
746}
747
748# ipv6_down if
749#	remove IPv6 addresses from the interface $if
750ipv6_down()
751{
752	local _if _ifs _ret inetList oldifs _inet6
753	_if=$1
754	_ifs="^"
755	_ret=1
756
757	if ! ipv6if $_if; then
758		return 0
759	fi
760
761	ipv6_accept_rtadv_down ${_if} && _ret=0
762	ipv6_prefix_hostid_addr_common ${_if} -alias && _ret=0
763	ifalias ${_if} inet6 -alias && _ret=0
764
765	inetList="`${IFCONFIG_CMD} ${_if} | grep 'inet6 ' | tr "\n\t" "$_ifs"`"
766
767	oldifs="$IFS"
768	IFS="$_ifs"
769	for _inet6 in $inetList ; do
770		# get rid of extraneous line
771		case $_inet6 in
772		inet6[[:space:]]*)	;;
773		*)		continue ;;
774		esac
775
776		_inet6=`expr "$_inet6" : '.*\(inet6 \([0-9a-f:]*\)\).*'`
777
778		IFS="$oldifs"
779		${IFCONFIG_CMD} ${_if} ${_inet6} -alias
780		IFS="$_ifs"
781		_ret=0
782	done
783	IFS="$oldifs"
784
785	return $_ret
786}
787
788# ifalias if af action
789#	Configure or remove aliases for network interface $if.
790#	It returns 0 if at least one alias was configured or
791#	removed, or 1 if there were none.
792#
793ifalias()
794{
795	local _ret
796	_ret=1
797
798	afexists $2 || return $_ret
799
800	case "$2" in
801	inet|inet6|link|ether)
802		ifalias_af_common $1 $2 $3 && _ret=0
803		;;
804	esac
805
806	return $_ret
807}
808
809# ifalias_expand_addr af action addr
810#	Expand address range ("N-M") specification in addr.
811#	"addr" must not include an address-family keyword.
812#	The results will include an address-family keyword.
813#
814ifalias_expand_addr()
815{
816	local _af _action
817
818	_af=$1
819	_action=$2
820	shift 2
821
822	afexists $_af || return
823	ifalias_expand_addr_$_af $_action $*
824}
825
826# ifalias_expand_addr_inet action addr
827#	Helper function for ifalias_expand_addr().  Handles IPv4.
828#
829ifalias_expand_addr_inet()
830{
831	local _action _arg _cidr _cidr_addr _exargs
832	local _ipaddr _plen _range _iphead _iptail _iplow _iphigh _ipcount
833	local _retstr _c
834	_action=$1
835	_arg=$2
836	shift 2
837	_exargs=$*
838	_retstr=
839
840	case $_action:$_arg:$_exargs in
841	*:*--*)		return ;;	# invalid
842	tmp:*[0-9]-[0-9]*:*)		# to be expanded
843		_action="alias"
844	;;
845	*:*[0-9]-[0-9]*:*)		# to be expanded
846	;;
847	tmp:*:*netmask*)		# already expanded w/ netmask option
848		echo ${_arg%/[0-9]*} $_exargs && return
849	;;
850	tmp:*:*)			# already expanded w/o netmask option
851		echo $_arg $_exargs && return
852	;;
853	*:*:*netmask*)			# already expanded w/ netmask option
854		echo inet ${_arg%/[0-9]*} $_exargs && return
855	;;
856	*:*:*)				# already expanded w/o netmask option
857		echo inet $_arg $_exargs && return
858	;;
859	esac
860
861	for _cidr in $_arg; do
862		_ipaddr=${_cidr%%/*}
863		_plen=${_cidr##*/}
864		# When subnet prefix length is not specified, use /32.
865		case $_plen in
866		$_ipaddr)	_plen=32 ;;	# "/" character not found
867		esac
868
869		OIFS=$IFS
870		IFS=. set -- $_ipaddr
871		_range=
872		_iphead=
873		_iptail=
874		for _c in $@; do
875			case $_range:$_c in
876			:[0-9]*-[0-9]*)
877				_range=$_c
878			;;
879			:*)
880				_iphead="${_iphead}${_iphead:+.}${_c}"
881			;;
882			*:*)
883				_iptail="${_iptail}${_iptail:+.}${_c}"
884			;;
885			esac
886		done
887		IFS=$OIFS
888		_iplow=${_range%-*}
889		_iphigh=${_range#*-}
890
891		# clear netmask when removing aliases
892		if [ "$_action" = "-alias" ]; then
893			_plen=""
894		fi
895
896		_ipcount=$_iplow
897		while [ "$_ipcount" -le "$_iphigh" ]; do
898			_retstr="${_retstr} ${_iphead}${_iphead:+.}${_ipcount}${_iptail:+.}${_iptail}${_plen:+/}${_plen}"
899			if [ $_ipcount -gt $(($_iplow + $netif_ipexpand_max)) ]; then
900				warn "Range specification is too large (${_iphead}${_iphead:+.}${_iplow}${_iptail:+.}${_iptail}-${_iphead}${_iphead:+.}${_iphigh}${_iptail:+.}${_iptail}).  ${_iphead}${_iphead:+.}${_iplow}${_iptail:+.}${_iptail}-${_iphead}${_iphead:+.}${_ipcount}${_iptail:+.}${_iptail} was processed.  Increase \$netif_ipexpand_max in rc.conf."
901				break
902			else
903				_ipcount=$(($_ipcount + 1))
904			fi
905			# Forcibly set /32 for remaining aliases.
906			_plen=32
907		done
908	done
909
910	for _c in $_retstr; do
911		ifalias_expand_addr_inet $_action $_c $_exargs
912	done
913}
914
915# ifalias_expand_addr_inet6 action addr
916#	Helper function for ifalias_expand_addr().  Handles IPv6.
917#
918ifalias_expand_addr_inet6()
919{
920	local _action _arg _cidr _cidr_addr _exargs
921	local _ipaddr _plen _ipleft _ipright _iplow _iphigh _ipcount
922	local _ipv4part
923	local _retstr _c
924	_action=$1
925	_arg=$2
926	shift 2
927	_exargs=$*
928	_retstr=
929
930	case $_action:$_arg:$_exargs in
931	*:*--*:*)	return ;;	# invalid
932	tmp:*[0-9a-zA-Z]-[0-9a-zA-Z]*:*)# to be expanded
933		_action="alias"
934	;;
935	*:*[0-9a-zA-Z]-[0-9a-zA-Z]*:*)	# to be expanded
936	;;
937	tmp:*:*prefixlen*)	# already expanded w/ prefixlen option
938		echo ${_arg%/[0-9]*} $_exargs && return
939	;;
940	tmp:*:*)		# already expanded w/o prefixlen option
941		echo $_arg $_exargs && return
942	;;
943	*:*:*prefixlen*)	# already expanded w/ prefixlen option
944		echo inet6 ${_arg%/[0-9]*} $_exargs && return
945	;;
946	*:*:*)			# already expanded w/o prefixlen option
947		echo inet6 $_arg $_exargs && return
948	;;
949	esac
950
951	for _cidr in $_arg; do
952		_ipaddr="${_cidr%%/*}"
953		_plen="${_cidr##*/}"
954
955		case $_action:$_ipaddr:$_cidr in
956		-alias:*:*)		unset _plen ;;
957		*:$_cidr:$_ipaddr)	unset _plen ;;
958		esac
959
960		if [ "${_ipaddr%:*.*.*.*}" = "$_ipaddr" ]; then
961			# Handle !v4mapped && !v4compat addresses.
962
963			# The default prefix length is 64.
964			case $_ipaddr:$_cidr in
965			$_cidr:$_ipaddr)	_plen="64" ;;
966			esac
967			_ipleft=${_ipaddr%-*}
968			_ipright=${_ipaddr#*-}
969			_iplow=${_ipleft##*:}
970			_iphigh=${_ipright%%:*}
971			_ipleft=${_ipleft%:*}
972			_ipright=${_ipright#*:}
973
974			if [ "$_iphigh" = "$_ipright" ]; then
975				unset _ipright
976			else
977				_ipright=:$_ipright
978			fi
979
980			if [ -n "$_iplow" -a -n "$_iphigh" ]; then
981				_iplow=$((0x$_iplow))
982				_iphigh=$((0x$_iphigh))
983				_ipcount=$_iplow
984				while [ $_ipcount -le $_iphigh ]; do
985					_r=`printf "%s:%04x%s%s" \
986					    $_ipleft $_ipcount $_ipright \
987					    ${_plen:+/}$_plen`
988					_retstr="$_retstr $_r"
989					if [ $_ipcount -gt $(($_iplow + $netif_ipexpand_max)) ]
990					then
991						warn "Range specification is too large $(printf '(%s:%x%s-%s:%x%s)' "$_ipleft" "$_iplow" "$_ipright" "$_ipleft" "$_iphigh" "$_ipright"). $(printf '%s:%x%s-%s:%x%s' "$_ipleft" "$_iplow" "$_ipright" "$_ipleft" "$_ipcount" "$_ipright") was processed.  Increase \$netif_ipexpand_max in rc.conf."
992						break
993					else
994						_ipcount=$(($_ipcount + 1))
995					fi
996				done
997			else
998				_retstr="${_ipaddr}${_plen:+/}${_plen}"
999			fi
1000
1001			for _c in $_retstr; do
1002				ifalias_expand_addr_inet6 $_action $_c $_exargs
1003			done
1004		else
1005			# v4mapped/v4compat should handle as an IPv4 alias
1006			_ipv4part=${_ipaddr##*:}
1007
1008			# Adjust prefix length if any.  If not, set the
1009			# default prefix length as 32.
1010			case $_ipaddr:$_cidr in
1011			$_cidr:$_ipaddr)	_plen=32 ;;
1012			*)			_plen=$(($_plen - 96)) ;;
1013			esac
1014
1015			_retstr=`ifalias_expand_addr_inet \
1016			    tmp ${_ipv4part}${_plen:+/}${_plen}`
1017			for _c in $_retstr; do
1018				ifalias_expand_addr_inet $_action $_c $_exargs
1019			done
1020		fi
1021	done
1022}
1023
1024# ifalias_af_common_handler if af action args
1025#	Helper function for ifalias_af_common().
1026#
1027ifalias_af_common_handler()
1028{
1029	local _ret _if _af _action _args _c _tmpargs
1030
1031	_ret=1
1032	_if=$1
1033	_af=$2
1034	_action=$3
1035	shift 3
1036	_args=$*
1037
1038	case $_args in
1039	${_af}[[:space:]]*)	;;
1040	*)	return	;;
1041	esac
1042
1043	# link(ether) does not support address removal.
1044	case $_af:$_action in
1045	link:-alias|ether:-alias)	return ;;
1046	esac
1047
1048	_tmpargs=
1049	for _c in $_args; do
1050		case $_c in
1051		${_af})
1052			case $_tmpargs in
1053			${_af}[[:space:]]*[0-9a-fA-F]-*)
1054				ifalias_af_common_handler $_if $_af $_action \
1055				`ifalias_expand_addr $_af $_action ${_tmpargs#${_af}[[:space:]]}`
1056			;;
1057			${_af}[[:space:]]*)
1058				${IFCONFIG_CMD} $_if $_tmpargs $_action && _ret=0
1059			;;
1060			esac
1061			_tmpargs=$_af
1062		;;
1063		*)
1064			_tmpargs="$_tmpargs $_c"
1065		;;
1066		esac
1067	done
1068	# Process the last component if any.
1069	if [ -n "${_tmpargs}" ]; then
1070		case $_tmpargs in
1071		${_af}[[:space:]]pass[[:space:]]*)
1072			${IFCONFIG_CMD} $_if $_tmpargs $_action && _ret=0
1073		;;
1074		${_af}[[:space:]]*[0-9a-fA-F]-*)
1075			ifalias_af_common_handler $_if $_af $_action \
1076			`ifalias_expand_addr $_af $_action ${_tmpargs#${_af}[[:space:]]}`
1077		;;
1078		${_af}[[:space:]]*)
1079			${IFCONFIG_CMD} $_if $_tmpargs $_action && _ret=0
1080		;;
1081		esac
1082	fi
1083
1084	return $_ret
1085}
1086
1087# ifalias_af_common if af action
1088#	Helper function for ifalias().
1089#
1090ifalias_af_common()
1091{
1092	local _ret _if _af _action alias ifconfig_args _aliasn _c _tmpargs _iaf
1093	local _vif _punct=".-/+"
1094
1095	_ret=1
1096	_aliasn=
1097	_if=$1
1098	_af=$2
1099	_action=$3
1100
1101	# Normalize $_if before using it in a pattern to list_vars()
1102	ltr "$_if" "$_punct" "_" _vif
1103
1104	# ifconfig_IF_aliasN which starts with $_af
1105	for alias in `list_vars ifconfig_${_vif}_alias[0-9]\* |
1106		sort_lite -nk1.$((9+${#_vif}+7))`
1107	do
1108		eval ifconfig_args=\"\$$alias\"
1109		_iaf=
1110		case $ifconfig_args in
1111		inet[[:space:]]*)	_iaf=inet ;;
1112		inet6[[:space:]]*)	_iaf=inet6 ;;
1113		link[[:space:]]*)	_iaf=link ;;
1114		ether[[:space:]]*)	_iaf=ether ;;
1115		esac
1116
1117		case ${_af}:${_action}:${_iaf}:"${ifconfig_args}" in
1118		${_af}:*:${_af}:*)
1119			_aliasn="$_aliasn $ifconfig_args"
1120			;;
1121		${_af}:*:"":"")
1122			break
1123			;;
1124		inet:alias:"":*)
1125			_aliasn="$_aliasn inet $ifconfig_args"
1126			warn "\$${alias} needs leading" \
1127			    "\"inet\" keyword for an IPv4 address."
1128		esac
1129	done
1130
1131	# backward compatibility: ipv6_ifconfig_IF_aliasN.
1132	case $_af in
1133	inet6)
1134		for alias in `list_vars ipv6_ifconfig_${_vif}_alias[0-9]\* |
1135			sort_lite -nk1.$((14+${#_vif}+7))`
1136		do
1137			eval ifconfig_args=\"\$$alias\"
1138			case ${_action}:"${ifconfig_args}" in
1139			*:"")
1140				break
1141			;;
1142			alias:*)
1143				_aliasn="${_aliasn} inet6 ${ifconfig_args}"
1144				warn "\$${alias} is obsolete. " \
1145				    "Use ifconfig_${_vif}_aliasN instead."
1146			;;
1147			esac
1148		done
1149	esac
1150
1151	# backward compatibility: ipv4_addrs_IF.
1152	for _tmpargs in `get_if_var $_if ipv4_addrs_IF`; do
1153		_aliasn="$_aliasn inet $_tmpargs"
1154	done
1155
1156	# Handle ifconfig_IF_aliases, ifconfig_IF_aliasN, and the others.
1157	_tmpargs=
1158	for _c in `get_if_var $_if ifconfig_IF_aliases` $_aliasn; do
1159		case $_c in
1160		inet|inet6|link|ether)
1161			case $_tmpargs in
1162			${_af}[[:space:]]*)
1163				eval ifalias_af_common_handler $_if $_af $_action $_tmpargs && _ret=0
1164			;;
1165			esac
1166			_tmpargs=$_c
1167		;;
1168		*)
1169			_tmpargs="$_tmpargs $_c"
1170		esac
1171	done
1172	# Process the last component
1173	case $_tmpargs in
1174	${_af}[[:space:]]*)
1175		ifalias_af_common_handler $_if $_af $_action $_tmpargs && _ret=0
1176	;;
1177	esac
1178
1179	return $_ret
1180}
1181
1182# ipv6_prefix_hostid_addr_common if action
1183#	Add or remove IPv6 prefix + hostid addr on the interface $if
1184#
1185ipv6_prefix_hostid_addr_common()
1186{
1187	local _if _action prefix j
1188	_if=$1
1189	_action=$2
1190	prefix=`get_if_var ${_if} ipv6_prefix_IF`
1191
1192	if [ -n "${prefix}" ]; then
1193		for j in ${prefix}; do
1194			# The default prefixlen is 64.
1195			plen=${j#*/}
1196			case $j:$plen in
1197			$plen:$j)	plen=64 ;;
1198			*)		j=${j%/*} ;;
1199			esac
1200
1201			# Normalize the last part by removing ":"
1202			j=${j%::*}
1203			j=${j%:}
1204			${IFCONFIG_CMD} ${_if} inet6 $j:: \
1205				prefixlen $plen eui64 ${_action}
1206
1207			# if I am a router, add subnet router
1208			# anycast address (RFC 2373).
1209			if checkyesno ipv6_gateway_enable; then
1210				${IFCONFIG_CMD} ${_if} inet6 $j:: \
1211					prefixlen $plen ${_action} anycast
1212			fi
1213		done
1214	fi
1215}
1216
1217# ipv6_accept_rtadv_up if
1218#	Enable accepting Router Advertisement and send Router
1219#	Solicitation message
1220ipv6_accept_rtadv_up()
1221{
1222	if ipv6_autoconfif $1; then
1223		${IFCONFIG_CMD} $1 inet6 accept_rtadv up
1224		if [ -x /sbin/rtsol ]; then
1225			/sbin/rtsol ${rtsol_flags} $1
1226		fi
1227		return 0
1228	fi
1229	return 1
1230}
1231
1232# ipv6_accept_rtadv_down if
1233#	Disable accepting Router Advertisement
1234ipv6_accept_rtadv_down()
1235{
1236	if ipv6_autoconfif $1; then
1237		${IFCONFIG_CMD} $1 inet6 -accept_rtadv
1238	fi
1239}
1240
1241# ifscript_up if
1242#	Evaluate a startup script for the $if interface.
1243#	It returns 0 if a script was found and processed or
1244#	1 if no script was found.
1245#
1246ifscript_up()
1247{
1248	if [ -r /etc/start_if.$1 ]; then
1249		. /etc/start_if.$1
1250		return 0
1251	else
1252		return 1
1253	fi
1254}
1255
1256# ifscript_down if
1257#	Evaluate a shutdown script for the $if interface.
1258#	It returns 0 if a script was found and processed or
1259#	1 if no script was found.
1260#
1261ifscript_down()
1262{
1263	if [ -r /etc/stop_if.$1 ]; then
1264		. /etc/stop_if.$1
1265		return 0
1266	else
1267		return 1
1268	fi
1269}
1270
1271# wlan_up
1272#	Create IEEE802.11 interfaces.
1273#
1274wlan_up()
1275{
1276	local _list _iflist parent child_wlans child create_args debug_flags
1277	_list=
1278	_iflist=$*
1279
1280	# Parse wlans_$parent="$child ..."
1281	for parent in `set | sed -nE 's/wlans_([a-z]+[a-z0-9]+[0-9]+)=.*/\1/p'`; do
1282		child_wlans=`get_if_var $parent wlans_IF`
1283		for child in ${child_wlans}; do
1284			create_args="wlandev $parent `get_if_var $child create_args_IF`"
1285			debug_flags="`get_if_var $child wlandebug_IF`"
1286			case $_iflist in
1287			""|$child|$child[[:space:]]*|*[[:space:]]$child[[:space:]]*|*[[:space:]]$child)	;;
1288			*)	continue ;;
1289			esac
1290			# Skip if ${child} already exists.
1291			if ${IFCONFIG_CMD} $child > /dev/null 2>&1; then
1292				continue
1293			fi
1294			if expr $child : 'wlan[0-9][0-9]*$' >/dev/null 2>&1; then
1295				${IFCONFIG_CMD} $child create ${create_args} && cfg=0
1296			else
1297				${IFCONFIG_CMD} wlan create ${create_args} name $child && cfg=0
1298			fi
1299			if [ $? -eq 0 ]; then
1300				_list="$_list $child"
1301			fi
1302			if [ -n "${debug_flags}" ]; then
1303				wlandebug -i $child ${debug_flags}
1304			fi
1305		done
1306	done
1307	if [ -n "${_list# }" ]; then
1308		echo "Created wlan(4) interfaces: ${_list# }."
1309	fi
1310	debug "Created wlan(4)s: ${_list# }"
1311}
1312
1313# wlan_down
1314#	Destroy IEEE802.11 interfaces.
1315#
1316wlan_down()
1317{
1318	local _list _iflist parent child_wlans child
1319	_list=
1320	_iflist=$*
1321
1322	# Parse wlans_$parent="$child ..."
1323	for parent in `set | sed -nE 's/wlans_([a-z]+[a-z0-9]+[0-9]+)=.*/\1/p'`; do
1324		child_wlans=`get_if_var $parent wlans_IF`
1325		for child in ${child_wlans}; do
1326			case $_iflist in
1327			""|$child|$child[[:space:]]*|*[[:space:]]$child[[:space:]]*|*[[:space:]]$child)	;;
1328			*)	continue ;;
1329			esac
1330			# Skip if ${child} doesn't exists.
1331			if ! ${IFCONFIG_CMD} $child > /dev/null 2>&1; then
1332				continue
1333			fi
1334			${IFCONFIG_CMD} -n ${child} destroy
1335			if [ $? -eq 0 ]; then
1336				_list="$_list $child"
1337			fi
1338		done
1339	done
1340	if [ -n "${_list# }" ]; then
1341		echo "Destroyed wlan(4) interfaces: ${_list# }."
1342	fi
1343	debug "Destroyed wlan(4)s: ${_list# }"
1344}
1345
1346# clone_up
1347#	Create cloneable interfaces.
1348#
1349clone_up()
1350{
1351	local _list ifn ifopt _iflist _inet6 _n tmpargs
1352	_list=
1353	_iflist=$*
1354
1355	# create_args_IF
1356	for ifn in ${cloned_interfaces}; do
1357		# Parse ifn:ifopt.
1358		OIFS=$IFS; IFS=:; set -- $ifn; ifn=$1; ifopt=$2; IFS=$OIFS
1359		case $_iflist in
1360		""|$ifn|$ifn[[:space:]]*|*[[:space:]]$ifn[[:space:]]*|*[[:space:]]$ifn)	;;
1361		*)	continue ;;
1362		esac
1363		case $ifn in
1364		epair[0-9]*)
1365			# epair(4) uses epair[0-9] for creation and
1366			# epair[0-9][ab] for configuration.
1367			#
1368			# Skip if ${ifn}a or ${ifn}b already exist.
1369			if ${IFCONFIG_CMD} ${ifn}a > /dev/null 2>&1; then
1370				continue
1371			elif ${IFCONFIG_CMD} ${ifn}b > /dev/null 2>&1; then
1372				continue
1373			fi
1374			${IFCONFIG_CMD} ${ifn} create \
1375			    `get_if_var ${ifn} create_args_IF`
1376			if [ $? -eq 0 ]; then
1377				_list="$_list ${ifn}a ${ifn}b"
1378			fi
1379		;;
1380		*)
1381			# Skip if ${ifn} already exists.
1382			if ${IFCONFIG_CMD} $ifn > /dev/null 2>&1; then
1383				continue
1384			fi
1385			${IFCONFIG_CMD} ${ifn} create \
1386			    `get_if_var ${ifn} create_args_IF`
1387			if [ $? -eq 0 ]; then
1388				_list="$_list $ifn"
1389			fi
1390		esac
1391	done
1392	for ifn in ${gif_interfaces}; do
1393		# Parse ifn:ifopt.
1394		OIFS=$IFS; IFS=:; set -- $ifn; ifn=$1; ifopt=$2; IFS=$OIFS
1395		case $_iflist in
1396		""|$ifn|$ifn[[:space:]]*|*[[:space:]]$ifn[[:space:]]*|*[[:space:]]$ifn)	;;
1397		*)	continue ;;
1398		esac
1399		# Skip if ifn already exists.
1400		if ${IFCONFIG_CMD} $ifn > /dev/null 2>&1; then
1401			continue
1402		fi
1403		case $ifn in
1404		gif[0-9]*)
1405			${IFCONFIG_CMD} $ifn create
1406		;;
1407		*)
1408			_n=$(${IFCONFIG_CMD} gif create)
1409			${IFCONFIG_CMD} $_n name $ifn
1410		;;
1411		esac
1412		if [ $? -eq 0 ]; then
1413			_list="$_list $ifn"
1414			tmpargs=$(get_if_var $ifn gifconfig_IF)
1415			_inet6=''
1416			case "$tmpargs" in
1417			'')
1418			;;
1419			inet6[[:space:]]*)
1420				tmpargs=${tmpargs#inet6}
1421				_inet6=inet6
1422				# FALLTHROUGH
1423			;&
1424			*)
1425				${IFCONFIG_CMD} $ifn $_inet6 tunnel $tmpargs
1426			;;
1427			esac
1428		fi
1429	done
1430	if [ -n "${_list# }" ]; then
1431		echo "Created clone interfaces: ${_list# }."
1432	fi
1433	debug "Cloned: ${_list# }"
1434}
1435
1436# clone_down
1437#	Destroy cloned interfaces. Destroyed interfaces are echoed to
1438#	standard output.
1439#
1440clone_down()
1441{
1442	local _list ifn _difn ifopt _iflist _sticky
1443	_list=
1444	_iflist=$*
1445
1446	: ${cloned_interfaces_sticky:=NO}
1447	if checkyesno cloned_interfaces_sticky; then
1448		_sticky=1
1449	else
1450		_sticky=0
1451	fi
1452	for ifn in ${cloned_interfaces} ${gif_interfaces}; do
1453		# Parse ifn:ifopt.
1454		OIFS=$IFS; IFS=:; set -- $ifn; ifn=$1; ifopt=$2; IFS=$OIFS
1455		case $ifopt:$_sticky in
1456		sticky:*)	continue ;;	# :sticky => not destroy
1457		nosticky:*)	;;		# :nosticky => destroy
1458		*:1)		continue ;;	# global sticky knob == 1
1459		esac
1460		case $_iflist in
1461		""|$ifn|$ifn[[:space:]]*|*[[:space:]]$ifn[[:space:]]*|*[[:space:]]$ifn)	;;
1462		*)	continue ;;
1463		esac
1464		case $ifn in
1465		epair[0-9]*)
1466			# Note: epair(4) uses epair[0-9] for removal and
1467			# epair[0-9][ab] for configuration.
1468			#
1469			# Skip if both of ${ifn}a and ${ifn}b do not exist.
1470			if ${IFCONFIG_CMD} ${ifn}a > /dev/null 2>&1; then
1471				_difn=${ifn}a
1472			elif ${IFCONFIG_CMD} ${ifn}b > /dev/null 2>&1; then
1473				_difn=${ifn}b
1474			else
1475				continue
1476			fi
1477			${IFCONFIG_CMD} -n $_difn destroy
1478			if [ $? -eq 0 ]; then
1479				_list="$_list ${ifn}a ${ifn}b"
1480			fi
1481		;;
1482		*)
1483			# Skip if ifn does not exist.
1484			if ! ${IFCONFIG_CMD} $ifn > /dev/null 2>&1; then
1485				continue
1486			fi
1487			${IFCONFIG_CMD} -n ${ifn} destroy
1488			if [ $? -eq 0 ]; then
1489				_list="$_list $ifn"
1490			fi
1491		;;
1492		esac
1493	done
1494	if [ -n "${_list# }" ]; then
1495		echo "Destroyed clone interfaces: ${_list# }."
1496	fi
1497	debug "Destroyed clones: ${_list# }"
1498}
1499
1500# childif_create
1501#	Create and configure child interfaces.  Return 0 if child
1502#	interfaces are created.
1503#
1504childif_create()
1505{
1506	local cfg child child_vlans create_args debug_flags ifn i
1507	cfg=1
1508	ifn=$1
1509
1510	# Create vlan interfaces
1511	child_vlans=`get_if_var $ifn vlans_IF`
1512
1513	if [ -n "${child_vlans}" ]; then
1514		load_kld if_vlan
1515	fi
1516
1517	for child in ${child_vlans}; do
1518		if expr $child : '[1-9][0-9]*$' >/dev/null 2>&1; then
1519			child="${ifn}.${child}"
1520			create_args=`get_if_var $child create_args_IF`
1521			${IFCONFIG_CMD} $child create ${create_args} && cfg=0
1522		else
1523			create_args="vlandev $ifn `get_if_var $child create_args_IF`"
1524			if expr $child : 'vlan[0-9][0-9]*$' >/dev/null 2>&1; then
1525				${IFCONFIG_CMD} $child create ${create_args} && cfg=0
1526			else
1527				i=`${IFCONFIG_CMD} vlan create ${create_args}`
1528				${IFCONFIG_CMD} $i name $child && cfg=0
1529			fi
1530		fi
1531		if autoif $child; then
1532			ifn_start $child
1533		fi
1534	done
1535
1536	return ${cfg}
1537}
1538
1539# childif_destroy
1540#	Destroy child interfaces.
1541#
1542childif_destroy()
1543{
1544	local cfg child child_vlans ifn
1545	cfg=1
1546
1547	child_vlans=`get_if_var $ifn vlans_IF`
1548	for child in ${child_vlans}; do
1549		if expr $child : '[1-9][0-9]*$' >/dev/null 2>&1; then
1550			child="${ifn}.${child}"
1551		fi
1552		if ! ifexists $child; then
1553			continue
1554		fi
1555		${IFCONFIG_CMD} -n $child destroy && cfg=0
1556	done
1557
1558	return ${cfg}
1559}
1560
1561# ng_mkpeer
1562#	Create netgraph nodes.
1563#
1564ng_mkpeer()
1565{
1566	ngctl -f - 2> /dev/null <<EOF
1567mkpeer $*
1568msg dummy nodeinfo
1569EOF
1570}
1571
1572# ng_create_one
1573#	Create netgraph nodes.
1574#
1575ng_create_one()
1576{
1577	local t
1578
1579	ng_mkpeer $* | while read line; do
1580		t=`expr "${line}" : '.* name="\([a-z]*[0-9]*\)" .*'`
1581		if [ -n "${t}" ]; then
1582			echo ${t}
1583			return
1584		fi
1585	done
1586}
1587
1588# ifnet_rename [ifname]
1589#	Rename interfaces if ifconfig_IF_name is defined.
1590#
1591ifnet_rename()
1592{
1593	local _if _ifname
1594
1595	# ifconfig_IF_name
1596	for _if in ${*:-$(${IFCONFIG_CMD} -l)}; do
1597		_ifname=`get_if_var $_if ifconfig_IF_name`
1598		if [ ! -z "$_ifname" ]; then
1599			${IFCONFIG_CMD} $_if name $_ifname
1600		fi
1601	done
1602
1603	return 0
1604}
1605
1606# list_net_interfaces type
1607#	List all network interfaces. The type of interface returned
1608#	can be controlled by the type argument. The type
1609#	argument can be any of the following:
1610#		nodhcp	- all interfaces, excluding DHCP configured interfaces
1611#		dhcp	- list only DHCP configured interfaces
1612#		noautoconf	- all interfaces, excluding IPv6 Stateless
1613#				  Address Autoconf configured interfaces
1614#		autoconf	- list only IPv6 Stateless Address Autoconf
1615#				  configured interfaces
1616#	If no argument is specified all network interfaces are output.
1617#	Note that the list will include cloned interfaces if applicable.
1618#	Cloned interfaces must already exist to have a chance to appear
1619#	in the list if ${network_interfaces} is set to `auto'.
1620#
1621list_net_interfaces()
1622{
1623	local type _tmplist _list _autolist _lo _if
1624	type=$1
1625
1626	# Get a list of ALL the interfaces and make lo0 first if it's there.
1627	#
1628	_tmplist=
1629	case ${network_interfaces} in
1630	[Aa][Uu][Tt][Oo])
1631		_autolist="`${IFCONFIG_CMD} -l`"
1632		_lo=
1633		for _if in ${_autolist} ; do
1634			if autoif $_if; then
1635				if [ "$_if" = "lo0" ]; then
1636					_lo="lo0 "
1637				else
1638					_tmplist="${_tmplist} ${_if}"
1639				fi
1640			fi
1641		done
1642		_tmplist="${_lo}${_tmplist# }"
1643	;;
1644	*)
1645		for _if in ${network_interfaces} ${cloned_interfaces}; do
1646			# epair(4) uses epair[0-9] for creation and
1647			# epair[0-9][ab] for configuration.
1648			case $_if in
1649			epair[0-9]*)
1650				_tmplist="$_tmplist ${_if}a ${_if}b"
1651			;;
1652			*)
1653				_tmplist="$_tmplist $_if"
1654			;;
1655			esac
1656		done
1657		#
1658		# lo0 is effectively mandatory, so help prevent foot-shooting
1659		#
1660		case "$_tmplist" in
1661		lo0|'lo0 '*|*' lo0'|*' lo0 '*)
1662			# This is fine, do nothing
1663			_tmplist="${_tmplist# }"
1664		;;
1665		*)
1666			_tmplist="lo0 ${_tmplist# }"
1667		;;
1668		esac
1669	;;
1670	esac
1671
1672	_list=
1673	case "$type" in
1674	nodhcp)
1675		for _if in ${_tmplist} ; do
1676			if ! dhcpif $_if && \
1677			   [ -n "`_ifconfig_getargs $_if`" ]; then
1678				_list="${_list# } ${_if}"
1679			fi
1680		done
1681	;;
1682	dhcp)
1683		for _if in ${_tmplist} ; do
1684			if dhcpif $_if; then
1685				_list="${_list# } ${_if}"
1686			fi
1687		done
1688	;;
1689	noautoconf)
1690		for _if in ${_tmplist} ; do
1691			if ! ipv6_autoconfif $_if && \
1692			   [ -n "`_ifconfig_getargs $_if ipv6`" ]; then
1693				_list="${_list# } ${_if}"
1694			fi
1695		done
1696	;;
1697	autoconf)
1698		for _if in ${_tmplist} ; do
1699			if ipv6_autoconfif $_if; then
1700				_list="${_list# } ${_if}"
1701			fi
1702		done
1703	;;
1704	*)
1705		_list=${_tmplist}
1706	;;
1707	esac
1708
1709	echo $_list
1710
1711	return 0
1712}
1713
1714# get_default_if -address_family
1715#	Get the interface of the default route for the given address family.
1716#	The -address_family argument must be suitable passing to route(8).
1717#
1718get_default_if()
1719{
1720	local routeget oldifs defif line
1721	defif=
1722	oldifs="$IFS"
1723	IFS="
1724"
1725	for line in `route -n get $1 default 2>/dev/null`; do
1726		case $line in
1727		*interface:*)
1728			defif=${line##*: }
1729			;;
1730		esac
1731	done
1732	IFS=${oldifs}
1733
1734	echo $defif
1735}
1736
1737# hexdigit arg
1738#	Echo decimal number $arg (single digit) in hexadecimal format.
1739hexdigit()
1740{
1741	printf '%x\n' "$1"
1742}
1743
1744# hexprint arg
1745#	Echo decimal number $arg (multiple digits) in hexadecimal format.
1746hexprint()
1747{
1748	printf '%x\n' "$1"
1749}
1750
1751is_wired_interface()
1752{
1753	local media
1754
1755	case `${IFCONFIG_CMD} $1 2>/dev/null` in
1756	*media:?Ethernet*) media=Ethernet ;;
1757	esac
1758
1759	test "$media" = "Ethernet"
1760}
1761
1762# network6_getladdr if [flag]
1763#	Echo link-local address from $if if any.
1764#	If flag is defined, tentative ones will be excluded.
1765network6_getladdr()
1766{
1767	local _if _flag proto addr rest
1768	_if=$1
1769	_flag=$2
1770
1771	${IFCONFIG_CMD} $_if inet6 2>/dev/null | while read proto addr rest; do
1772		case "${proto}/${addr}/${_flag}/${rest}" in
1773		inet6/fe80::*//*)
1774			echo ${addr}
1775		;;
1776		inet6/fe80:://*tentative*)	# w/o flag
1777			sleep `${SYSCTL_N} net.inet6.ip6.dad_count`
1778			network6_getladdr $_if $_flags
1779		;;
1780		inet6/fe80::/*/*tentative*)	# w/ flag
1781			echo ${addr}
1782		;;
1783		*)
1784			continue
1785		;;
1786		esac
1787
1788		return
1789	done
1790}
1791