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