]> CyberLeo.Net >> Repos - FreeBSD/releng/9.1.git/blob - etc/network.subr
MFC of r242187:
[FreeBSD/releng/9.1.git] / etc / network.subr
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 # $FreeBSD$
26 #
27
28 #
29 # Subroutines commonly used from network startup scripts.
30 # Requires that rc.conf be loaded first.
31 #
32
33 # ifn_start ifn
34 #       Bring up and configure an interface.  If some configuration is
35 #       applied, print the interface configuration.
36 #
37 ifn_start()
38 {
39         local ifn cfg
40         ifn="$1"
41         cfg=1
42
43         [ -z "$ifn" ] && err 1 "ifn_start called without an interface"
44
45         ifscript_up ${ifn} && cfg=0
46         ifconfig_up ${ifn} && cfg=0
47         afexists inet && ipv4_up ${ifn} && cfg=0
48         afexists inet6 && ipv6_up ${ifn} && cfg=0
49         afexists ipx && ipx_up ${ifn} && cfg=0
50         childif_create ${ifn} && cfg=0
51
52         return $cfg
53 }
54
55 # ifn_stop ifn
56 #       Shutdown and de-configure an interface.  If action is taken,
57 #       print the interface name.
58 #
59 ifn_stop()
60 {
61         local ifn cfg
62         ifn="$1"
63         cfg=1
64
65         [ -z "$ifn" ] && err 1 "ifn_stop called without an interface"
66
67         afexists ipx && ipx_down ${ifn} && cfg=0
68         afexists inet6 && ipv6_down ${ifn} && cfg=0
69         afexists inet && ipv4_down ${ifn} && cfg=0
70         ifconfig_down ${ifn} && cfg=0
71         ifscript_down ${ifn} && cfg=0
72         childif_destroy ${ifn} && cfg=0
73
74         return $cfg
75 }
76
77 # ifconfig_up if
78 #       Evaluate ifconfig(8) arguments for interface $if and
79 #       run ifconfig(8) with those arguments. It returns 0 if
80 #       arguments were found and executed or 1 if the interface
81 #       had no arguments.  Pseudo arguments DHCP and WPA are handled
82 #       here.
83 #
84 ifconfig_up()
85 {
86         local _cfg _ipv6_opts ifconfig_args
87         _cfg=1
88
89         # Make sure lo0 always comes up.
90         if [ "$1" = "lo0" ]; then
91                 _cfg=0
92         fi
93
94         # ifconfig_IF
95         ifconfig_args=`ifconfig_getargs $1`
96         if [ -n "${ifconfig_args}" ]; then
97                 eval ifconfig $1 ${ifconfig_args}
98                 _cfg=0
99         fi
100
101         # inet6 specific
102         if afexists inet6; then
103                 if checkyesno ipv6_activate_all_interfaces; then
104                         _ipv6_opts="-ifdisabled"
105                 elif [ "$1" != "lo0" ]; then
106                         _ipv6_opts="ifdisabled"
107                 fi
108
109                 # backward compatibility: $ipv6_enable
110                 case $ipv6_enable in
111                 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
112                         if ! checkyesno ipv6_gateway_enable; then
113                                 _ipv6_opts="${_ipv6_opts} accept_rtadv"
114                         fi
115                         ;;
116                 esac
117
118                 case $ipv6_cpe_wanif in
119                 $1)
120                         _ipv6_opts="${_ipv6_opts} -no_radr accept_rtadv"
121                 ;;
122                 esac
123
124                 if [ -n "${_ipv6_opts}" ]; then
125                         ifconfig $1 inet6 ${_ipv6_opts}
126                 fi
127
128                 # ifconfig_IF_ipv6
129                 ifconfig_args=`ifconfig_getargs $1 ipv6`
130                 if [ -n "${ifconfig_args}" ]; then
131                         # backward compatibility: inet6 keyword
132                         case "${ifconfig_args}" in
133                         :*|[0-9a-fA-F]*:*)
134                                 warn "\$ifconfig_$1_ipv6 needs " \
135                                     "\"inet6\" keyword for an IPv6 address."
136                                 ifconfig_args="inet6 ${ifconfig_args}"
137                         ;;
138                         esac
139                         ifconfig $1 inet6 -ifdisabled
140                         eval ifconfig $1 ${ifconfig_args}
141                         _cfg=0
142                 fi
143
144                 # backward compatiblity: $ipv6_ifconfig_IF
145                 ifconfig_args=`get_if_var $1 ipv6_ifconfig_IF`
146                 if [ -n "${ifconfig_args}" ]; then
147                         warn "\$ipv6_ifconfig_$1 is obsolete." \
148                             "  Use ifconfig_$1_ipv6 instead."
149                         ifconfig $1 inet6 -ifdisabled
150                         eval ifconfig $1 inet6 ${ifconfig_args}
151                         _cfg=0
152                 fi
153         fi
154
155         if [ ${_cfg} -eq 0 ]; then
156                 ifconfig $1 up
157         fi
158
159         if wpaif $1; then
160                 /etc/rc.d/wpa_supplicant start $1
161                 _cfg=0          # XXX: not sure this should count
162         fi
163
164         if dhcpif $1; then
165                 if [ $_cfg -ne 0 ] ; then
166                         ifconfig $1 up
167                 fi
168                 if syncdhcpif $1; then
169                         /etc/rc.d/dhclient start $1
170                 fi
171                 _cfg=0
172         fi
173
174         return $_cfg
175 }
176
177 # ifconfig_down if
178 #       returns 1 if wpa_supplicant or dhclient was stopped or
179 #       the interface exists.
180 #
181 ifconfig_down()
182 {
183         local _cfg
184         _cfg=1
185
186         if wpaif $1; then
187                 /etc/rc.d/wpa_supplicant stop $1
188                 _cfg=0
189         fi
190
191         if dhcpif $1; then
192                 /etc/rc.d/dhclient stop $1
193                 _cfg=0
194         fi
195
196         if ifexists $1; then
197                 ifconfig $1 down
198                 _cfg=0
199         fi
200
201         return $_cfg
202 }
203
204 # get_if_var if var [default]
205 #       Return the value of the pseudo-hash corresponding to $if where
206 #       $var is a string containg the sub-string "IF" which will be
207 #       replaced with $if after the characters defined in _punct are
208 #       replaced with '_'. If the variable is unset, replace it with
209 #       $default if given.
210 get_if_var()
211 {
212         local _if _punct _punct_c _var _default prefix suffix
213
214         if [ $# -ne 2 -a $# -ne 3 ]; then
215                 err 3 'USAGE: get_if_var name var [default]'
216         fi
217
218         _if=$1
219         _punct=". - / +"
220         for _punct_c in $_punct; do
221                 _if=`ltr ${_if} ${_punct_c} '_'`
222         done
223         _var=$2
224         _default=$3
225
226         prefix=${_var%%IF*}
227         suffix=${_var##*IF}
228         eval echo \${${prefix}${_if}${suffix}-${_default}}
229 }
230
231 # _ifconfig_getargs if [af]
232 #       Prints the arguments for the supplied interface to stdout.
233 #       Returns 1 if empty.  In general, ifconfig_getargs should be used
234 #       outside this file.
235 _ifconfig_getargs()
236 {
237         local _ifn _af
238         _ifn=$1
239         _af=${2+_$2}
240
241         if [ -z "$_ifn" ]; then
242                 return 1
243         fi
244
245         get_if_var $_ifn ifconfig_IF$_af "$ifconfig_DEFAULT"
246 }
247
248 # ifconfig_getargs if [af]
249 #       Takes the result from _ifconfig_getargs and removes pseudo
250 #       args such as DHCP and WPA.
251 ifconfig_getargs()
252 {
253         local _tmpargs _arg _args
254         _tmpargs=`_ifconfig_getargs $1 $2`
255         if [ $? -eq 1 ]; then
256                 return 1
257         fi
258         _args=
259
260         for _arg in $_tmpargs; do
261                 case $_arg in
262                 [Dd][Hh][Cc][Pp]) ;;
263                 [Nn][Oo][Aa][Uu][Tt][Oo]) ;;
264                 [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]) ;;
265                 [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]) ;;
266                 [Ww][Pp][Aa]) ;;
267                 *)
268                         _args="$_args $_arg"
269                         ;;
270                 esac
271         done
272
273         echo $_args
274 }
275
276 # autoif
277 #       Returns 0 if the interface should be automatically configured at
278 #       boot time and 1 otherwise.
279 autoif()
280 {
281         local _tmpargs _arg
282         _tmpargs=`_ifconfig_getargs $1`
283
284         for _arg in $_tmpargs; do
285                 case $_arg in
286                 [Nn][Oo][Aa][Uu][Tt][Oo])
287                         return 1
288                         ;;
289                 esac
290         done
291
292         return 0
293 }
294
295 # dhcpif if
296 #       Returns 0 if the interface is a DHCP interface and 1 otherwise.
297 dhcpif()
298 {
299         local _tmpargs _arg
300         _tmpargs=`_ifconfig_getargs $1`
301
302         if noafif $1; then
303                 return 1
304         fi
305
306         for _arg in $_tmpargs; do
307                 case $_arg in
308                 [Dd][Hh][Cc][Pp])
309                         return 0
310                         ;;
311                 [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
312                         return 0
313                         ;;
314                 [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
315                         return 0
316                         ;;
317                 esac
318         done
319
320         return 1
321 }
322
323 # syncdhcpif
324 #       Returns 0 if the interface should be configured synchronously and
325 #       1 otherwise.
326 syncdhcpif()
327 {
328         local _tmpargs _arg
329         _tmpargs=`_ifconfig_getargs $1`
330
331         if noafif $1; then
332                 return 1
333         fi
334
335         for _arg in $_tmpargs; do
336                 case $_arg in
337                 [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
338                         return 1
339                         ;;
340                 [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
341                         return 0
342                         ;;
343                 esac
344         done
345
346         checkyesno synchronous_dhclient
347 }
348
349 # wpaif if
350 #       Returns 0 if the interface is a WPA interface and 1 otherwise.
351 wpaif()
352 {
353         local _tmpargs _arg
354         _tmpargs=`_ifconfig_getargs $1`
355
356         for _arg in $_tmpargs; do
357                 case $_arg in
358                 [Ww][Pp][Aa])
359                         return 0
360                         ;;
361                 esac
362         done
363
364         return 1
365 }
366
367 # afexists af
368 #       Returns 0 if the address family is enabled in the kernel
369 #       1 otherwise.
370 afexists()
371 {
372         local _af
373         _af=$1
374
375         case ${_af} in
376         inet|inet6)
377                 check_kern_features ${_af}
378                 ;;
379         ipx)
380                 ${SYSCTL_N} net.ipx > /dev/null 2>&1
381                 ;;
382         atm)
383                 if [ -x /sbin/atmconfig ]; then
384                         /sbin/atmconfig diag list > /dev/null 2>&1
385                 else
386                         return 1
387                 fi
388                 ;;
389         *)
390                 err 1 "afexists(): Unsupported address family: $_af"
391                 ;;
392         esac
393 }
394
395 # noafif if
396 #       Returns 0 if the interface has no af configuration and 1 otherwise.
397 noafif()
398 {
399         local _if
400         _if=$1
401
402         case $_if in
403         pflog[0-9]*|\
404         pfsync[0-9]*|\
405         an[0-9]*|\
406         ath[0-9]*|\
407         ipw[0-9]*|\
408         ipfw[0-9]*|\
409         iwi[0-9]*|\
410         iwn[0-9]*|\
411         ral[0-9]*|\
412         wi[0-9]*|\
413         wl[0-9]*|\
414         wpi[0-9]*)
415                 return 0
416                 ;;
417         esac
418
419         return 1
420 }
421
422 # ipv6if if
423 #       Returns 0 if the interface should be configured for IPv6 and
424 #       1 otherwise.
425 ipv6if()
426 {
427         local _if _tmpargs i
428         _if=$1
429
430         if ! afexists inet6; then
431                 return 1
432         fi
433
434         # lo0 is always IPv6-enabled
435         case $_if in
436         lo0)
437                 return 0
438                 ;;
439         esac
440
441         case "${ipv6_network_interfaces}" in
442         $_if|"$_if "*|*" $_if"|*" $_if "*|[Aa][Uu][Tt][Oo])
443                 # True if $ifconfig_IF_ipv6 is defined.
444                 _tmpargs=`_ifconfig_getargs $_if ipv6`
445                 if [ -n "${_tmpargs}" ]; then
446                         return 0
447                 fi
448
449                 # backward compatibility: True if $ipv6_ifconfig_IF is defined.
450                 _tmpargs=`get_if_var $_if ipv6_ifconfig_IF`
451                 if [ -n "${_tmpargs}" ]; then
452                         return 0
453                 fi
454                 ;;
455         esac
456
457         return 1
458 }
459
460 # ipv6_autoconfif if
461 #       Returns 0 if the interface should be configured for IPv6 with
462 #       Stateless Address Configuration; 1 otherwise.
463 ipv6_autoconfif()
464 {
465         local _if _tmpargs _arg
466         _if=$1
467
468         case $_if in
469         lo0|\
470         stf[0-9]*|\
471         faith[0-9]*|\
472         lp[0-9]*|\
473         sl[0-9]*)
474                 return 1
475                 ;;
476         esac
477         if noafif $_if; then
478                 return 1
479         fi
480         if ! ipv6if $_if; then
481                 return 1
482         fi
483         if checkyesno ipv6_gateway_enable; then
484                 return 1
485         fi
486         _tmpargs=`get_if_var $_if ipv6_prefix_IF`
487         if [ -n "${_tmpargs}" ]; then
488                 return 1
489         fi
490         # backward compatibility: $ipv6_enable
491         case $ipv6_enable in
492         [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
493                 if checkyesno ipv6_gateway_enable; then
494                         return 1
495                 else
496                         return 0
497                 fi
498         ;;
499         esac
500
501         _tmpargs=`_ifconfig_getargs $_if ipv6`
502         for _arg in $_tmpargs; do
503                 case $_arg in
504                 accept_rtadv)
505                         return 0
506                         ;;
507                 esac
508         done
509
510         # backward compatibility: $ipv6_ifconfig_IF
511         _tmpargs=`get_if_var $_if ipv6_ifconfig_IF`
512         for _arg in $_tmpargs; do
513                 case $_arg in
514                 accept_rtadv)
515                         return 0
516                         ;;
517                 esac
518         done
519
520         return 1
521 }
522
523 # ifexists if
524 #       Returns 0 if the interface exists and 1 otherwise.
525 ifexists()
526 {
527         [ -z "$1" ] && return 1
528         ifconfig -n $1 > /dev/null 2>&1
529 }
530
531 # ipv4_up if
532 #       add IPv4 addresses to the interface $if
533 ipv4_up()
534 {
535         local _if _ret
536         _if=$1
537         _ret=1
538
539         # Add 127.0.0.1/8 to lo0 unless otherwise specified.
540         if [ "${_if}" = "lo0" ]; then
541                 ifconfig_args=`get_if_var ${_if} ifconfig_IF`
542                 if [ -z "${ifconfig_args}" ]; then
543                         ifconfig ${_if} inet 127.0.0.1/8 alias
544                 fi
545         fi
546         ifalias_up ${_if} inet && _ret=0
547         ipv4_addrs_common ${_if} alias && _ret=0
548
549         return $_ret
550 }
551
552 # ipv6_up if
553 #       add IPv6 addresses to the interface $if
554 ipv6_up()
555 {
556         local _if _ret
557         _if=$1
558         _ret=1
559
560         if ! ipv6if $_if; then
561                 return 0
562         fi
563
564         ifalias_up ${_if} inet6 && _ret=0
565         ipv6_prefix_hostid_addr_common ${_if} alias && _ret=0
566         ipv6_accept_rtadv_up ${_if} && _ret=0
567
568         # wait for DAD
569         sleep `${SYSCTL_N} net.inet6.ip6.dad_count`
570         sleep 1
571
572         return $_ret
573 }
574
575 # ipv4_down if
576 #       remove IPv4 addresses from the interface $if
577 ipv4_down()
578 {
579         local _if _ifs _ret inetList oldifs _inet
580         _if=$1
581         _ifs="^"
582         _ret=1
583
584         inetList="`ifconfig ${_if} | grep 'inet ' | tr "\n" "$_ifs"`"
585
586         oldifs="$IFS"
587         IFS="$_ifs"
588         for _inet in $inetList ; do
589                 # get rid of extraneous line
590                 [ -z "$_inet" ] && break
591
592                 _inet=`expr "$_inet" : '.*\(inet \([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*'`
593
594                 IFS="$oldifs"
595                 ifconfig ${_if} ${_inet} delete
596                 IFS="$_ifs"
597                 _ret=0
598         done
599         IFS="$oldifs"
600
601         ifalias_down ${_if} inet && _ret=0
602         ipv4_addrs_common ${_if} -alias && _ret=0
603
604         return $_ret
605 }
606
607 # ipv6_down if
608 #       remove IPv6 addresses from the interface $if
609 ipv6_down()
610 {
611         local _if _ifs _ret inetList oldifs _inet6
612         _if=$1
613         _ifs="^"
614         _ret=1
615
616         if ! ipv6if $_if; then
617                 return 0
618         fi
619
620         ipv6_accept_rtadv_down ${_if} && _ret=0
621         ipv6_prefix_hostid_addr_common ${_if} -alias && _ret=0
622         ifalias_down ${_if} inet6 && _ret=0
623
624         inetList="`ifconfig ${_if} | grep 'inet6 ' | tr "\n" "$_ifs"`"
625
626         oldifs="$IFS"
627         IFS="$_ifs"
628         for _inet6 in $inetList ; do
629                 # get rid of extraneous line
630                 [ -z "$_inet6" ] && break
631
632                 _inet6=`expr "$_inet6" : '.*\(inet6 \([0-9a-f:]*\)\).*'`
633
634                 IFS="$oldifs"
635                 ifconfig ${_if} ${_inet6} -alias
636                 IFS="$_ifs"
637                 _ret=0
638         done
639         IFS="$oldifs"
640
641         return $_ret
642 }
643
644 # ipv4_addrs_common if action
645 #       Evaluate the ifconfig_if_ipv4 arguments for interface $if and
646 #       use $action to add or remove IPv4 addresses from $if.
647 ipv4_addrs_common()
648 {
649         local _ret _if _action _cidr _cidr_addr
650         local _ipaddr _netmask _range _ipnet _iplow _iphigh _ipcount
651         _ret=1
652         _if=$1
653         _action=$2
654
655         # get ipv4-addresses
656         cidr_addr=`get_if_var $_if ipv4_addrs_IF`
657
658         for _cidr in ${cidr_addr}; do
659                 _ipaddr=${_cidr%%/*}
660                 _netmask="/"${_cidr##*/}
661                 _range=${_ipaddr##*.}
662                 _ipnet=${_ipaddr%.*}
663                 _iplow=${_range%-*}
664                 _iphigh=${_range#*-}
665
666                 # clear netmask when removing aliases
667                 if [ "${_action}" = "-alias" ]; then
668                         _netmask=""
669                 fi
670
671                 _ipcount=${_iplow}
672                 while [ "${_ipcount}" -le "${_iphigh}" ]; do
673                         eval "ifconfig ${_if} ${_action} ${_ipnet}.${_ipcount}${_netmask}"
674                         _ipcount=$((${_ipcount}+1))
675                         _ret=0
676
677                         # only the first ipaddr in a subnet need the real netmask
678                         if [ "${_action}" != "-alias" ]; then
679                                 _netmask="/32"
680                         fi
681                 done
682         done
683
684         return $_ret
685 }
686
687 # ifalias_up if af
688 #       Configure aliases for network interface $if.
689 #       It returns 0 if at least one alias was configured or
690 #       1 if there were none.
691 #
692 ifalias_up()
693 {
694         local _ret
695         _ret=1
696
697         case "$2" in
698         inet)
699                 _ret=`ifalias_ipv4_up "$1"`
700                 ;;
701         inet6)
702                 _ret=`ifalias_ipv6_up "$1"`
703                 ;;
704         esac
705
706         return $_ret
707 }
708
709 # ifalias_ipv4_up if
710 #       Helper function for ifalias_up().  Handles IPv4.
711 #
712 ifalias_ipv4_up()
713 {
714         local _ret alias ifconfig_args
715         _ret=1
716
717         # ifconfig_IF_aliasN which starts with "inet"
718         alias=0
719         while : ; do
720                 ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
721                 case "${ifconfig_args}" in
722                 inet\ *)
723                         ifconfig $1 ${ifconfig_args} alias && _ret=0
724                         ;;
725                 inet6\ *)
726                         ;;
727                 "")
728                         break
729                         ;;
730                 *)
731                         warn "\$ifconfig_$1_alias${alias} needs " \
732                             "\"inet\" keyword for an IPv4 address."
733                         ifconfig $1 ${ifconfig_args} alias && _ret=0
734                         ;;
735                 esac
736                 alias=$((${alias} + 1))
737         done
738
739         return $_ret
740 }
741
742 # ifalias_ipv6_up if
743 #       Helper function for ifalias_up().  Handles IPv6.
744 #
745 ifalias_ipv6_up()
746 {
747         local _ret alias ifconfig_args
748         _ret=1
749
750         # ifconfig_IF_aliasN which starts with "inet6"
751         alias=0
752         while : ; do
753                 ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
754                 case "${ifconfig_args}" in
755                 inet6\ *)
756                         ifconfig $1 ${ifconfig_args} alias && _ret=0
757                         ;;
758                 "")
759                         break
760                         ;;
761                 esac
762                 alias=$((${alias} + 1))
763         done
764
765         # backward compatibility: ipv6_ifconfig_IF_aliasN.
766         alias=0
767         while : ; do
768                 ifconfig_args=`get_if_var $1 ipv6_ifconfig_IF_alias${alias}`
769                 case "${ifconfig_args}" in
770                 "")
771                         break
772                         ;;
773                 *)
774                         ifconfig $1 inet6 ${ifconfig_args} alias && _ret=0
775                         warn "\$ipv6_ifconfig_$1_alias${alias} is obsolete." \
776                             "  Use ifconfig_$1_aliasN instead."
777                         ;;
778                 esac
779                 alias=$((${alias} + 1))
780         done
781
782         return $_ret
783 }
784
785 # ifalias_down if af
786 #       Remove aliases for network interface $if.
787 #       It returns 0 if at least one alias was removed or
788 #       1 if there were none.
789 #
790 ifalias_down()
791 {
792         local _ret
793         _ret=1
794
795         case "$2" in
796         inet)
797                 _ret=`ifalias_ipv4_down "$1"`
798                 ;;
799         inet6)
800                 _ret=`ifalias_ipv6_down "$1"`
801                 ;;
802         esac
803
804         return $_ret
805 }
806
807 # ifalias_ipv4_down if
808 #       Helper function for ifalias_down().  Handles IPv4.
809 #
810 ifalias_ipv4_down()
811 {
812         local _ret alias ifconfig_args
813         _ret=1
814
815         # ifconfig_IF_aliasN which starts with "inet"
816         alias=0
817         while : ; do
818                 ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
819                 case "${ifconfig_args}" in
820                 inet\ *)
821                         ifconfig $1 ${ifconfig_args} -alias && _ret=0
822                         ;;
823                 "")
824                         break
825                         ;;
826                 esac
827                 alias=$((${alias} + 1))
828         done
829
830         return $_ret
831 }
832
833 # ifalias_ipv6_down if
834 #       Helper function for ifalias_down().  Handles IPv6.
835 #
836 ifalias_ipv6_down()
837 {
838         local _ret alias ifconfig_args
839         _ret=1
840
841         # ifconfig_IF_aliasN which starts with "inet6"
842         alias=0
843         while : ; do
844                 ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
845                 case "${ifconfig_args}" in
846                 inet6\ *)
847                         ifconfig $1 ${ifconfig_args} -alias && _ret=0
848                         ;;
849                 "")
850                         break
851                         ;;
852                 esac
853                 alias=$((${alias} + 1))
854         done
855
856         # backward compatibility: ipv6_ifconfig_IF_aliasN.
857         alias=0
858         while : ; do
859                 ifconfig_args=`get_if_var $1 ipv6_ifconfig_IF_alias${alias}`
860                 case "${ifconfig_args}" in
861                 "")
862                         break
863                         ;;
864                 *)
865                         ifconfig $1 inet6 ${ifconfig_args} -alias && _ret=0
866                         warn "\$ipv6_ifconfig_$1_alias${alias} is obsolete." \
867                             "  Use ifconfig_$1_aliasN instead."
868                         ;;
869                 esac
870                 alias=$((${alias} + 1))
871         done
872
873         return $_ret
874 }
875
876 # ipv6_prefix_hostid_addr_common if action
877 #       Add or remove IPv6 prefix + hostid addr on the interface $if
878 #
879 ipv6_prefix_hostid_addr_common()
880 {
881         local _if _action prefix laddr hostid j address
882         _if=$1
883         _action=$2
884         prefix=`get_if_var ${_if} ipv6_prefix_IF`
885
886         if [ -n "${prefix}" ]; then
887                 laddr=`network6_getladdr ${_if}`
888                 hostid=${laddr#fe80::}
889                 hostid=${hostid%\%*}
890
891                 for j in ${prefix}; do
892                         address=$j\:${hostid}
893                         ifconfig ${_if} inet6 ${address} prefixlen 64 ${_action}
894
895                         # if I am a router, add subnet router
896                         # anycast address (RFC 2373).
897                         if checkyesno ipv6_gateway_enable; then
898                                 ifconfig ${_if} inet6 $j:: prefixlen 64 \
899                                         ${_action} anycast
900                         fi
901                 done
902         fi
903 }
904
905 # ipv6_accept_rtadv_up if
906 #       Enable accepting Router Advertisement and send Router
907 #       Solicitation message
908 ipv6_accept_rtadv_up()
909 {
910         if ipv6_autoconfif $1; then
911                 ifconfig $1 inet6 accept_rtadv up
912                 if ! checkyesno rtsold_enable; then
913                         rtsol ${rtsol_flags} $1
914                 fi
915         fi
916 }
917
918 # ipv6_accept_rtadv_down if
919 #       Disable accepting Router Advertisement
920 ipv6_accept_rtadv_down()
921 {
922         if ipv6_autoconfif $1; then
923                 ifconfig $1 inet6 -accept_rtadv
924         fi
925 }
926
927 # ifscript_up if
928 #       Evaluate a startup script for the $if interface.
929 #       It returns 0 if a script was found and processed or
930 #       1 if no script was found.
931 #
932 ifscript_up()
933 {
934         if [ -r /etc/start_if.$1 ]; then
935                 . /etc/start_if.$1
936                 return 0
937         else
938                 return 1
939         fi
940 }
941
942 # ifscript_down if
943 #       Evaluate a shutdown script for the $if interface.
944 #       It returns 0 if a script was found and processed or
945 #       1 if no script was found.
946 #
947 ifscript_down()
948 {
949         if [ -r /etc/stop_if.$1 ]; then
950                 . /etc/stop_if.$1
951                 return 0
952         else
953                 return 1
954         fi
955 }
956
957 # clone_up
958 #       Create cloneable interfaces.
959 #
960 clone_up()
961 {
962         local _prefix _list ifn
963         _prefix=
964         _list=
965
966         # create_args_IF
967         for ifn in ${cloned_interfaces}; do
968                 ifconfig ${ifn} create `get_if_var ${ifn} create_args_IF`
969                 if [ $? -eq 0 ]; then
970                         _list="${_list}${_prefix}${ifn}"
971                         [ -z "$_prefix" ] && _prefix=' '
972                 fi
973         done
974         debug "Cloned: ${_list}"
975 }
976
977 # clone_down
978 #       Destroy cloned interfaces. Destroyed interfaces are echoed to
979 #       standard output.
980 #
981 clone_down()
982 {
983         local _prefix _list ifn
984         _prefix=
985         _list=
986
987         for ifn in ${cloned_interfaces}; do
988                 ifconfig -n ${ifn} destroy
989                 if [ $? -eq 0 ]; then
990                         _list="${_list}${_prefix}${ifn}"
991                         [ -z "$_prefix" ] && _prefix=' '
992                 fi
993         done
994         debug "Destroyed clones: ${_list}"
995 }
996
997 # childif_create
998 #       Create and configure child interfaces.  Return 0 if child
999 #       interfaces are created.
1000 #
1001 childif_create()
1002 {
1003         local cfg child child_vlans child_wlans create_args debug_flags ifn i
1004         cfg=1
1005         ifn=$1
1006
1007         # Create wireless interfaces
1008         child_wlans=`get_if_var $ifn wlans_IF`
1009
1010         for child in ${child_wlans}; do
1011                 create_args="wlandev $ifn `get_if_var $child create_args_IF`"
1012                 debug_flags="`get_if_var $child wlandebug_IF`"
1013
1014                 if expr $child : 'wlan[0-9][0-9]*$' >/dev/null 2>&1; then
1015                         ifconfig $child create ${create_args} && cfg=0
1016                         if [ -n "${debug_flags}" ]; then
1017                                 wlandebug -i $child ${debug_flags}
1018                         fi
1019                 else
1020                         i=`ifconfig wlan create ${create_args}`
1021                         if [ -n "${debug_flags}" ]; then
1022                                 wlandebug -i $i ${debug_flags}
1023                         fi
1024                         ifconfig $i name $child && cfg=0
1025                 fi
1026                 if autoif $child; then
1027                         ifn_start $child
1028                 fi
1029         done
1030
1031         # Create vlan interfaces
1032         child_vlans=`get_if_var $ifn vlans_IF`
1033
1034         if [ -n "${child_vlans}" ]; then
1035                 load_kld if_vlan
1036         fi
1037
1038         for child in ${child_vlans}; do
1039                 if expr $child : '[1-9][0-9]*$' >/dev/null 2>&1; then
1040                         child="${ifn}.${child}"
1041                         create_args=`get_if_var $child create_args_IF`
1042                         ifconfig $child create ${create_args} && cfg=0
1043                 else
1044                         create_args="vlandev $ifn `get_if_var $child create_args_IF`"
1045                         if expr $child : 'vlan[0-9][0-9]*$' >/dev/null 2>&1; then
1046                                 ifconfig $child create ${create_args} && cfg=0
1047                         else
1048                                 i=`ifconfig vlan create ${create_args}`
1049                                 ifconfig $i name $child && cfg=0
1050                         fi
1051                 fi
1052                 if autoif $child; then
1053                         ifn_start $child
1054                 fi
1055         done
1056
1057         return ${cfg}
1058 }
1059
1060 # childif_destroy
1061 #       Destroy child interfaces.
1062 #
1063 childif_destroy()
1064 {
1065         local cfg child child_vlans child_wlans ifn
1066         cfg=1
1067
1068         child_wlans=`get_if_var $ifn wlans_IF`
1069         for child in ${child_wlans}; do
1070                 if ! ifexists $child; then
1071                         continue
1072                 fi
1073                 ifconfig -n $child destroy && cfg=0
1074         done
1075
1076         child_vlans=`get_if_var $ifn vlans_IF`
1077         for child in ${child_vlans}; do
1078                 if expr $child : '[1-9][0-9]*$' >/dev/null 2>&1; then
1079                         child="${ifn}.${child}"
1080                 fi
1081                 if ! ifexists $child; then
1082                         continue
1083                 fi
1084                 ifconfig -n $child destroy && cfg=0
1085         done
1086
1087         return ${cfg}
1088 }
1089
1090 # ng_mkpeer
1091 #       Create netgraph nodes.
1092 #
1093 ng_mkpeer()
1094 {
1095         ngctl -f - 2> /dev/null <<EOF
1096 mkpeer $*
1097 msg dummy nodeinfo
1098 EOF
1099 }
1100
1101 # ng_create_one
1102 #       Create netgraph nodes.
1103 #
1104 ng_create_one()
1105 {
1106         local t
1107
1108         ng_mkpeer $* | while read line; do
1109                 t=`expr "${line}" : '.* name="\([a-z]*[0-9]*\)" .*'`
1110                 if [ -n "${t}" ]; then
1111                         echo ${t}
1112                         return
1113                 fi
1114         done
1115 }
1116
1117 # gif_up
1118 #       Create gif(4) tunnel interfaces.
1119 gif_up()
1120 {
1121         local i peers
1122
1123         for i in ${gif_interfaces}; do
1124                 peers=`get_if_var $i gifconfig_IF`
1125                 case ${peers} in
1126                 '')
1127                         continue
1128                         ;;
1129                 *)
1130                         if expr $i : 'gif[0-9][0-9]*$' >/dev/null 2>&1; then
1131                                 ifconfig $i create >/dev/null 2>&1
1132                         else
1133                                 gif=`ifconfig gif create`
1134                                 ifconfig $gif name $i
1135                         fi
1136                         ifconfig $i tunnel ${peers}
1137                         ifconfig $i up
1138                         ;;
1139                 esac
1140         done
1141 }
1142
1143 # ng_fec_create ifn
1144 #       Configure Fast EtherChannel for interface $ifn. Returns 0 if
1145 #       FEC arguments were found and configured; returns !0 otherwise.
1146 ng_fec_create()
1147 {
1148          local req_iface iface bogus
1149          req_iface="$1"
1150
1151          ngctl shutdown ${req_iface}: > /dev/null 2>&1
1152
1153          bogus=""
1154          while true; do
1155                  iface=`ng_create_one fec dummy fec`
1156                  if [ -z "${iface}" ]; then
1157                          exit 2
1158                  fi
1159                  if [ "${iface}" = "${req_iface}" ]; then
1160                          break
1161                  fi
1162                  bogus="${bogus} ${iface}"
1163          done
1164
1165          for iface in ${bogus}; do
1166                  ngctl shutdown ${iface}:
1167          done
1168 }
1169
1170 # fec_up
1171 #       Create Fast EtherChannel interfaces.
1172 fec_up()
1173 {
1174         local i j
1175
1176         for i in ${fec_interfaces}; do
1177                 ng_fec_create $i
1178                 for j in `get_if_var $i fecconfig_IF`; do
1179                         case ${j} in
1180                         '')
1181                                 continue
1182                                 ;;
1183                         *)
1184                                 ngctl msg ${i}: add_iface "\"${j}\""
1185                                 ;;
1186                         esac
1187                 done
1188         done
1189 }
1190
1191 # ipx_up ifn
1192 #       Configure any IPX addresses for interface $ifn. Returns 0 if
1193 #       IPX arguments were found and configured; returns 1 otherwise.
1194 #
1195 ipx_up()
1196 {
1197         local ifn
1198         ifn="$1"
1199
1200         # ifconfig_IF_ipx
1201         ifconfig_args=`_ifconfig_getargs $ifn ipx`
1202         if [ -n "${ifconfig_args}" ]; then
1203                 ifconfig ${ifn} ${ifconfig_args}
1204                 return 0
1205         fi
1206
1207         return 1
1208 }
1209
1210 # ipx_down ifn
1211 #       Remove IPX addresses for interface $ifn. Returns 0 if IPX
1212 #       addresses were found and unconfigured. It returns 1, otherwise.
1213 #
1214 ipx_down()
1215 {
1216         local _if _ifs _ret ipxList oldifs _ipx
1217         _if=$1
1218         _ifs="^"
1219         _ret=1
1220         ipxList="`ifconfig ${_if} | grep 'ipx ' | tr "\n" "$_ifs"`"
1221         oldifs="$IFS"
1222
1223         IFS="$_ifs"
1224         for _ipx in $ipxList ; do
1225                 # get rid of extraneous line
1226                 [ -z "$_ipx" ] && break
1227
1228                 _ipx=`expr "$_ipx" : '.*\(ipx [0-9a-h]\{1,8\}H*\.[0-9a-h]\{1,12\}\).*'`
1229
1230                 IFS="$oldifs"
1231                 ifconfig ${_if} ${_ipx} delete
1232                 IFS="$_ifs"
1233                 _ret=0
1234         done
1235         IFS="$oldifs"
1236
1237         return $_ret
1238 }
1239
1240 # ifnet_rename
1241 #       Rename all requested interfaces.
1242 #
1243 ifnet_rename()
1244 {
1245         local _if _ifname
1246
1247         # ifconfig_IF_name
1248         for _if in `ifconfig -l`; do
1249                 _ifname=`get_if_var $_if ifconfig_IF_name`
1250                 if [ ! -z "$_ifname" ]; then
1251                         ifconfig $_if name $_ifname
1252                 fi
1253         done
1254
1255         return 0
1256 }
1257
1258 # list_net_interfaces type
1259 #       List all network interfaces. The type of interface returned
1260 #       can be controlled by the type argument. The type
1261 #       argument can be any of the following:
1262 #               nodhcp  - all interfaces, excluding DHCP configured interfaces
1263 #               dhcp    - list only DHCP configured interfaces
1264 #               noautoconf      - all interfaces, excluding IPv6 Stateless
1265 #                                 Address Autoconf configured interfaces
1266 #               autoconf        - list only IPv6 Stateless Address Autoconf
1267 #                                 configured interfaces
1268 #       If no argument is specified all network interfaces are output.
1269 #       Note that the list will include cloned interfaces if applicable.
1270 #       Cloned interfaces must already exist to have a chance to appear
1271 #       in the list if ${network_interfaces} is set to `auto'.
1272 #
1273 list_net_interfaces()
1274 {
1275         local type _tmplist _list _autolist _lo _if
1276         type=$1
1277
1278         # Get a list of ALL the interfaces and make lo0 first if it's there.
1279         #
1280         _tmplist=
1281         case ${network_interfaces} in
1282         [Aa][Uu][Tt][Oo])
1283                 _autolist="`ifconfig -l`"
1284                 _lo=
1285                 for _if in ${_autolist} ; do
1286                         if autoif $_if; then
1287                                 if [ "$_if" = "lo0" ]; then
1288                                         _lo="lo0 "
1289                                 else
1290                                         _tmplist="${_tmplist} ${_if}"
1291                                 fi
1292                         fi
1293                 done
1294                 _tmplist="${_lo}${_tmplist# }"
1295                 ;;
1296         *)
1297                 _tmplist="${network_interfaces} ${cloned_interfaces}"
1298
1299                 # lo0 is effectively mandatory, so help prevent foot-shooting
1300                 #
1301                 case "$_tmplist" in
1302                 lo0|'lo0 '*|*' lo0'|*' lo0 '*) ;; # This is fine, do nothing
1303                 *)      _tmplist="lo0 ${_tmplist}" ;;
1304                 esac
1305                 ;;
1306         esac
1307
1308         _list=
1309         case "$type" in
1310         nodhcp)
1311                 for _if in ${_tmplist} ; do
1312                         if ! dhcpif $_if && \
1313                            [ -n "`_ifconfig_getargs $_if`" ]; then
1314                                 _list="${_list# } ${_if}"
1315                         fi
1316                 done
1317                 ;;
1318         dhcp)
1319                 for _if in ${_tmplist} ; do
1320                         if dhcpif $_if; then
1321                                 _list="${_list# } ${_if}"
1322                         fi
1323                 done
1324                 ;;
1325         noautoconf)
1326                 for _if in ${_tmplist} ; do
1327                         if ! ipv6_autoconfif $_if && \
1328                            [ -n "`_ifconfig_getargs $_if ipv6`" ]; then
1329                                 _list="${_list# } ${_if}"
1330                         fi
1331                 done
1332                 ;;
1333         autoconf)
1334                 for _if in ${_tmplist} ; do
1335                         if ipv6_autoconfif $_if; then
1336                                 _list="${_list# } ${_if}"
1337                         fi
1338                 done
1339                 ;;
1340         *)
1341                 _list=${_tmplist}
1342                 ;;
1343         esac
1344
1345         echo $_list
1346
1347         return 0
1348 }
1349
1350 # get_default_if -address_family
1351 #       Get the interface of the default route for the given address family.
1352 #       The -address_family argument must be suitable passing to route(8).
1353 #
1354 get_default_if()
1355 {
1356         local routeget oldifs defif line
1357         defif=
1358         oldifs="$IFS"
1359         IFS="
1360 "
1361         for line in `route -n get $1 default 2>/dev/null`; do
1362                 case $line in
1363                 *interface:*)
1364                         defif=${line##*: }
1365                         ;;
1366                 esac
1367         done
1368         IFS=${oldifs}
1369
1370         echo $defif
1371 }
1372
1373 # hexdigit arg
1374 #       Echo decimal number $arg (single digit) in hexadecimal format.
1375 hexdigit()
1376 {
1377         printf '%x\n' "$1"
1378 }
1379
1380 # hexprint arg
1381 #       Echo decimal number $arg (multiple digits) in hexadecimal format.
1382 hexprint()
1383 {
1384         printf '%x\n' "$1"
1385 }
1386
1387 is_wired_interface()
1388 {
1389         local media
1390
1391         case `ifconfig $1 2>/dev/null` in
1392         *media:?Ethernet*) media=Ethernet ;;
1393         esac
1394
1395         test "$media" = "Ethernet"
1396 }
1397
1398 # network6_getladdr if [flag]
1399 #       Echo link-local address from $if if any.
1400 #       If flag is defined, tentative ones will be excluded.
1401 network6_getladdr()
1402 {
1403         local proto addr rest
1404         ifconfig $1 2>/dev/null | while read proto addr rest; do
1405                 case ${proto} in
1406                 inet6)
1407                         case ${addr} in
1408                         fe80::*)
1409                                 if [ -z "$2" ]; then
1410                                         echo ${addr}
1411                                         return
1412                                 fi
1413                                 case ${rest} in
1414                                 *tentative*)
1415                                         continue
1416                                         ;;
1417                                 *)
1418                                         echo ${addr}
1419                                         return
1420                                 esac
1421                         esac
1422                 esac
1423         done
1424 }