summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile11
-rw-r--r--usr.sbin/bluetooth/ath3kfw/Makefile1
-rw-r--r--usr.sbin/bsdinstall/Makefile1
-rw-r--r--usr.sbin/bsdinstall/bsdinstall.8187
-rw-r--r--usr.sbin/bsdinstall/scripts/Makefile3
-rwxr-xr-xusr.sbin/bsdinstall/scripts/auto4
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig168
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig_ipv485
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig_ipv6148
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.32
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.32
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/Makefile2
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.32
-rw-r--r--usr.sbin/diskinfo/diskinfo.c5
-rw-r--r--usr.sbin/fdread/fdread.c2
-rw-r--r--usr.sbin/gpioctl/gpioctl.810
-rw-r--r--usr.sbin/jail/Makefile3
-rw-r--r--usr.sbin/jail/jail.c76
-rw-r--r--usr.sbin/jls/Makefile9
-rw-r--r--usr.sbin/jls/jls.c76
-rw-r--r--usr.sbin/kbdmap/kbdmap.c2
-rw-r--r--usr.sbin/lastlogin/lastlogin.820
-rw-r--r--usr.sbin/lastlogin/lastlogin.c58
-rw-r--r--usr.sbin/makefs/Makefile4
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_write.c8
-rw-r--r--usr.sbin/makefs/ffs.c11
-rw-r--r--usr.sbin/makefs/ffs/ffs_bswap.c8
-rw-r--r--usr.sbin/makefs/ffs/ffs_subr.c9
-rw-r--r--usr.sbin/makefs/makefs.811
-rw-r--r--usr.sbin/makefs/makefs.c41
-rw-r--r--usr.sbin/makefs/makefs.h3
-rw-r--r--usr.sbin/makefs/mtree.c1051
-rw-r--r--usr.sbin/mfiutil/mfi_config.c133
-rw-r--r--usr.sbin/mfiutil/mfi_drive.c122
-rw-r--r--usr.sbin/mfiutil/mfi_evt.c23
-rw-r--r--usr.sbin/mfiutil/mfi_flash.c32
-rw-r--r--usr.sbin/mfiutil/mfi_patrol.c28
-rw-r--r--usr.sbin/mfiutil/mfi_show.c74
-rw-r--r--usr.sbin/mfiutil/mfi_volume.c14
-rw-r--r--usr.sbin/mfiutil/mfiutil.840
-rw-r--r--usr.sbin/mfiutil/mfiutil.c13
-rw-r--r--usr.sbin/mfiutil/mfiutil.h8
-rw-r--r--usr.sbin/mountd/mountd.c243
-rwxr-xr-xusr.sbin/pc-sysinstall/backend-query/enable-net.sh57
-rwxr-xr-xusr.sbin/pc-sysinstall/backend-query/test-netup.sh25
-rwxr-xr-xusr.sbin/pc-sysinstall/backend/functions-cleanup.sh4
-rwxr-xr-xusr.sbin/pc-sysinstall/backend/functions-networking.sh195
-rw-r--r--usr.sbin/pmccontrol/pmccontrol.c25
-rw-r--r--usr.sbin/pw/pw_user.c2
-rw-r--r--usr.sbin/rpc.lockd/lockd.c249
-rw-r--r--usr.sbin/rpc.statd/statd.c240
-rw-r--r--usr.sbin/rtadvd/advcap.c51
-rw-r--r--usr.sbin/rtadvd/config.c1111
-rw-r--r--usr.sbin/rtadvd/config.h10
-rw-r--r--usr.sbin/rtadvd/dump.c217
-rw-r--r--usr.sbin/rtadvd/dump.h6
-rw-r--r--usr.sbin/rtadvd/if.c113
-rw-r--r--usr.sbin/rtadvd/if.h4
-rw-r--r--usr.sbin/rtadvd/pathnames.h5
-rw-r--r--usr.sbin/rtadvd/rrenum.c192
-rw-r--r--usr.sbin/rtadvd/rrenum.h4
-rw-r--r--usr.sbin/rtadvd/rtadvd.847
-rw-r--r--usr.sbin/rtadvd/rtadvd.c1292
-rw-r--r--usr.sbin/rtadvd/rtadvd.conf3
-rw-r--r--usr.sbin/rtadvd/rtadvd.conf.5111
-rw-r--r--usr.sbin/rtadvd/rtadvd.h227
-rw-r--r--usr.sbin/rtadvd/timer.c120
-rw-r--r--usr.sbin/rtadvd/timer.h61
-rw-r--r--usr.sbin/rtsold/dump.c89
-rw-r--r--usr.sbin/rtsold/if.c58
-rw-r--r--usr.sbin/rtsold/probe.c9
-rw-r--r--usr.sbin/rtsold/rtsock.c8
-rw-r--r--usr.sbin/rtsold/rtsol.c572
-rw-r--r--usr.sbin/rtsold/rtsold.829
-rw-r--r--usr.sbin/rtsold/rtsold.c435
-rw-r--r--usr.sbin/rtsold/rtsold.h66
-rw-r--r--usr.sbin/tcpdrop/tcpdrop.c3
-rw-r--r--usr.sbin/usbdump/usbdump.810
-rw-r--r--usr.sbin/ypserv/yp_main.c2
79 files changed, 6257 insertions, 2148 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index 7fc531a..f448f03 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -3,7 +3,7 @@
.include <bsd.own.mk>
-SUBDIR= adduser \
+SUBDIR= adduser \
arp \
bootparamd \
burncd \
@@ -34,7 +34,6 @@ SUBDIR= adduser \
inetd \
iostat \
kldxref \
- lastlogin \
mailwrapper \
makefs \
manctl \
@@ -89,7 +88,6 @@ SUBDIR= adduser \
trpt \
tzsetup \
ugidfw \
- utxrm \
vipw \
wake \
watch \
@@ -99,7 +97,6 @@ SUBDIR= adduser \
# NB: keep these sorted by MK_* knobs
.if ${MK_ACCT} != "no"
-SUBDIR+= ac
SUBDIR+= accton
SUBDIR+= sa
.endif
@@ -299,6 +296,12 @@ SUBDIR+= usbconfig
SUBDIR+= usbdump
.endif
+.if ${MK_UTMPX} != "no"
+SUBDIR+= ac
+SUBDIR+= lastlogin
+SUBDIR+= utxrm
+.endif
+
.if ${MK_WIRELESS} != "no"
SUBDIR+= ancontrol
SUBDIR+= wlandebug
diff --git a/usr.sbin/bluetooth/ath3kfw/Makefile b/usr.sbin/bluetooth/ath3kfw/Makefile
index 0ff010f..373655b 100644
--- a/usr.sbin/bluetooth/ath3kfw/Makefile
+++ b/usr.sbin/bluetooth/ath3kfw/Makefile
@@ -2,7 +2,6 @@
PROG= ath3kfw
MAN= ath3kfw.8
-WARNS?= 6
DPADD+= ${LIBUSB}
LDADD+= -lusb
diff --git a/usr.sbin/bsdinstall/Makefile b/usr.sbin/bsdinstall/Makefile
index 5e39b0b..e72b5d3 100644
--- a/usr.sbin/bsdinstall/Makefile
+++ b/usr.sbin/bsdinstall/Makefile
@@ -2,5 +2,6 @@
SUBDIR= distextract distfetch partedit scripts
SCRIPTS= bsdinstall
+MAN= bsdinstall.8
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdinstall/bsdinstall.8 b/usr.sbin/bsdinstall/bsdinstall.8
new file mode 100644
index 0000000..4b8b51e
--- /dev/null
+++ b/usr.sbin/bsdinstall/bsdinstall.8
@@ -0,0 +1,187 @@
+.\"-
+.\" Copyright (c) 2011 Nathan Whitehorn <nwhitehorn@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 11, 2011
+.Dt bsdinstall 8
+.Os
+.Sh NAME
+.Nm bsdinstall
+.Nd system installer
+.Sh SYNOPSIS
+.Nm
+.Op Ar target
+.Op Ar ...
+.Sh DESCRIPTION
+.Nm
+is used for installation of new systems, both for system setup from
+installation media (e.g. CD-ROMs) and for use on live systems to prepare
+VM images and jails.
+.Pp
+Much like
+.Xr make 1 , Nm
+takes a target and possible parameters of the target as arguments. If
+invoked with no arguments, it will invoke the
+.Cm auto
+target, which provides a standard interactive installation, invoking the
+others in sequence. To perform a scripted installation, these subtargets
+can be invoked separately by an installation script.
+.Sh TARGETS
+Most of the following targets are only useful for scripting the installer.
+For interactive use, most users will be interested only in the
+.Cm auto
+and
+.Cm jail
+targets.
+.Bl -tag -width ".Cm jail Ar destination"
+.It Cm auto
+Run the standard interactive installation, including disk partitioning.
+.It Cm jail Ar destination
+Sets up a new chroot system at
+.Pa destination ,
+suitable for use with
+.Xr jail 8 .
+Behavior is generally similar to
+.Cm auto ,
+except that disk partitioning and network setup are skipped and a kernel is
+not installed into the new system.
+.It Cm keymap
+If the current controlling TTY is a
+.Xr syscons 4
+console, asks the user to set the current keymap, and saves the result to the
+new system's
+.Pa rc.conf .
+.It Cm hostname
+Prompts the user for a host name for the new system and saves the result to the
+new system's
+.Pa rc.conf .
+If
+.Ev BSDINSTALL_CONFIGCURRENT
+is set, also sets the host name of the current system.
+.It Cm netconfig
+Interactively configures network interfaces (first invoking
+.Cm wlanconfig
+on wireless interfaces), saving the result to the new system's
+.Pa rc.conf
+and
+.Pa resolv.conf .
+If
+.Ev BSDINSTALL_CONFIGCURRENT
+is set, also configures the network interfaces of the current system to match.
+.It Cm autopart
+Provides the installer's interactive guided disk partitioner for single-disk
+installations. Partitions disks, runs
+.Xr newfs 8 ,
+and writes the new system's
+.Pa fstab .
+.It Cm partedit
+Provides the installer's interactive manual disk partitioner, with support
+for multi disk setups, non-UFS file systems, and manual selection of
+partition schemes. Partitions disks, runs
+.Xr newfs 8 ,
+and writes the new system's
+.Pa fstab .
+.It Cm mount
+Mounts the file systems previously configured by
+.Cm autopart
+or
+.Cm partedit
+under
+.Ev BSDINSTALL_CHROOT .
+.It Cm distfetch
+Fetches the distributions in
+.Ev DISTRIBUTIONS
+to
+.Ev BSDINSTALL_DISTDIR
+from
+.Ev BSDINSTALL_DISTSITE .
+.It Cm checksum
+Verifies the checksums of the distributions listed in
+.Ev DISTRIBUTIONS
+against the distribution manifest.
+.It Cm distextract
+Extracts the distributions listed in
+.Ev DISTRIBUTIONS
+into
+.Ev BSDINSTALL_CHROOT .
+.It Cm rootpass
+Interactively invokes
+.Xr passwd 1
+in the new system to set the root user's password.
+.It Cm adduser
+Interactively invokes
+.Xr adduser 8
+in the new system.
+.It Cm time
+Interactively sets the time, date, and time zone of the new system.
+.It Cm services
+Queries the user for the system daemons to begin at system startup,
+writing the result into the new system's
+.Pa rc.conf .
+.It Cm config
+Installs the configuration files destined for the new system (e.g. rc.conf
+fragments generated by
+.Cm netconfig ,
+etc.) onto the new system.
+.El
+.Sh ENVIRONMENT VARIABLES
+The following environment variables control various aspects of the installation
+process. Many are used internally during installation and have reasonable
+default values for most installation scenarios. Others are set by various
+interactive user prompts, and can be usefully overridden when making scripted
+or customized installers.
+.Bl -tag -width ".Ev BSDINSTALL_DISTDIR"
+.It Ev DISTRIBUTIONS
+The set of distributions to install (e.g. "base kernel ports"). Default: none
+.It Ev BSDINSTALL_DISTDIR
+The directory in which the distribution files can be found (or to which they
+should be downloaded). Default:
+.Pa /usr/freebsd-dist
+.It Ev BSDINSTALL_CHROOT
+The directory into which the distribution files should be unpacked and the
+directory at which the root file system of the new system should be mounted.
+Default:
+.Pa /mnt
+.It Ev BSDINSTALL_LOG
+Path to a log file for the installation. Default:
+.Pa /tmp/bsdinstall_log
+.It Ev BSDINSTALL_TMPETC
+Directory where files destined for the new system's
+.Pa /etc
+will be stored until the
+.Cm config
+target is executed. If this directory does not already exist, it will be
+created. Default:
+.Pa /tmp/bsdinstall_etc
+.El
+.Sh HISTORY
+This version of
+.Nm
+first appeared in
+.Fx 9.0 .
+.Sh AUTHORS
+.An -nosplit
+.An Nathan Whitehorn Aq nwhitehorn@FreeBSD.org
diff --git a/usr.sbin/bsdinstall/scripts/Makefile b/usr.sbin/bsdinstall/scripts/Makefile
index 8ad6744..e32fda6 100644
--- a/usr.sbin/bsdinstall/scripts/Makefile
+++ b/usr.sbin/bsdinstall/scripts/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
SCRIPTS= auto adduser checksum config hostname jail keymap mirrorselect \
- mount netconfig rootpass services time umount wlanconfig
+ mount netconfig netconfig_ipv4 netconfig_ipv6 rootpass services \
+ time umount wlanconfig
BINDIR= /usr/libexec/bsdinstall
NO_MAN= true
diff --git a/usr.sbin/bsdinstall/scripts/auto b/usr.sbin/bsdinstall/scripts/auto
index c163c2c..bdc5fc4 100755
--- a/usr.sbin/bsdinstall/scripts/auto
+++ b/usr.sbin/bsdinstall/scripts/auto
@@ -105,7 +105,7 @@ case $? in
1) # Shell
clear
echo "Use this shell to set up partitions for the new system. When finished, mount the system at $BSDINSTALL_CHROOT and place an fstab file for the new system at $PATH_FSTAB. Then type 'exit'. You can also enter the partition editor at any time by entering 'bsdinstall partedit'."
- sh
+ sh 2>&1
;;
3) # Manual
bsdinstall partedit || error
@@ -199,7 +199,7 @@ finalconfig() {
clear
echo This shell is operating in a chroot in the new system. \
When finished making configuration changes, type \"exit\".
- chroot "$BSDINSTALL_CHROOT" /bin/sh
+ chroot "$BSDINSTALL_CHROOT" /bin/sh 2>&1
# Don't hose local rc.conf changes
cp $BSDINSTALL_CHROOT/etc/rc.conf $BSDINSTALL_TMPETC/rc.conf.manual
finalconfig
diff --git a/usr.sbin/bsdinstall/scripts/netconfig b/usr.sbin/bsdinstall/scripts/netconfig
index 0374d12..b78e330 100755
--- a/usr.sbin/bsdinstall/scripts/netconfig
+++ b/usr.sbin/bsdinstall/scripts/netconfig
@@ -2,6 +2,11 @@
#-
# Copyright (c) 2011 Nathan Whitehorn
# All rights reserved.
+# Copyright (c) 2011 The FreeBSD Foundation
+# All rights reserved.
+#
+# Portions of this software were developed by Bjoern Zeeb
+# under sponsorship from the FreeBSD Foundation.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -36,8 +41,6 @@ DIALOG_TAGS=""
: ${DIALOG_ITEM_HELP=4}
: ${DIALOG_ESC=255}
-echo -n > $BSDINSTALL_TMPETC/rc.conf.net
-
for IF in `ifconfig -l`; do
test "$IF" = "lo0" && continue
(ifconfig -g wlan | egrep -wq $IF) && continue
@@ -51,12 +54,14 @@ INTERFACE=`echo $DIALOG_TAGS | xargs dialog --backtitle 'FreeBSD Installer' --ti
if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi
exec 3>&-
+: > $BSDINSTALL_TMPETC/._rc.conf.net
+
# Do a dirty check to see if this a wireless interface -- there should be a
# better way
IFCONFIG_PREFIX=""
if ifconfig $INTERFACE | grep -q 'media: IEEE 802.11 Wireless'; then
NEXT_WLAN_IFACE=wlan0 # XXX
- echo wlans_$INTERFACE=\"$NEXT_WLAN_IFACE\" >> $BSDINSTALL_TMPETC/rc.conf.net
+ echo wlans_$INTERFACE=\"$NEXT_WLAN_IFACE\" >> $BSDINSTALL_TMPETC/._rc.conf.net
IFCONFIG_PREFIX="WPA "
if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
ifconfig $NEXT_WLAN_IFACE create wlandev $INTERFACE
@@ -66,56 +71,129 @@ if ifconfig $INTERFACE | grep -q 'media: IEEE 802.11 Wireless'; then
INTERFACE="$NEXT_WLAN_IFACE"
fi
-dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --yesno 'Would you like to use DHCP to configure this interface?' 0 0
-if [ $? -eq $DIALOG_OK ]; then
- echo ifconfig_$INTERFACE=\"${IFCONFIG_PREFIX}DHCP\" >> $BSDINSTALL_TMPETC/rc.conf.net
+IPV6_AVAIL=0
+IPV4_AVAIL=0
+sysctl -N kern.features.inet6 > /dev/null 2>&1
+case $? in
+0) IPV6_AVAIL=1 ;;
+esac
+sysctl -N kern.features.inet > /dev/null 2>&1
+case $? in
+0) IPV4_AVAIL=1 ;;
+esac
- if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
- dialog --backtitle 'FreeBSD Installer' --infobox "Acquiring DHCP lease..." 0 0
- dhclient $INTERFACE 2>> $BSDINSTALL_LOG
- if [ $? -ne 0 ]; then
- dialog --backtitle 'FreeBSD Installer' --msgbox "DHCP lease acquisition failed." 0 0
- exec $0
- fi
+if [ ${IPV4_AVAIL} -eq 1 ]; then
+ dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
+ --yesno 'Would you like to configure IPv4 for this interface?' 0 0
+ if [ $? -eq $DIALOG_OK ]; then
+ bsdinstall netconfig_ipv4 ${INTERFACE} "${IFCONFIG_PREFIX}" || \
+ exec $0
+ else
+ IPV4_AVAIL=0
+ fi
+fi
+# In case wlanconfig left an option and we do not support IPv4 we need to write
+# it out on its own. We cannot write it out with IPv6 as that suffix.
+if [ ${IPV4_AVAIL} -eq 0 -a -n ${IFCONFIG_PREFIX} ]; then
+ echo ifconfig_${INTERFACE}=\"${IFCONFIG_PREFIX}\" >> $BSDINSTALL_TMPETC/._rc.conf.net
+fi
+if [ ${IPV6_AVAIL} -eq 1 ]; then
+ dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
+ --yesno 'Would you like to configure IPv6 for this interface?' 0 0
+ if [ $? -eq $DIALOG_OK ]; then
+ bsdinstall netconfig_ipv6 ${INTERFACE} || exec $0
+ else
+ IPV6_AVAIL=0
fi
- exit 0
fi
-IP_ADDRESS=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $2); }'`
-NETMASK=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $4); }'`
-ROUTER=`netstat -rn -f inet | awk '/default/ {printf("%s\n", $2);}'`
+SEARCH=""
+IP4_1=""
+IP4_2=""
+IP6_1=""
+IP6_2=""
+while read key value; do
+ case "${key}" in
+ search) SEARCH="${value}" ;;
+ nameserver) # is more trick as we have to distinguish v4 and v6
+ case "${value}" in
+ [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)
+ if [ -z "${IP4_1}" ] ; then
+ IP4_1="${value}"
+ elif [ -z "${IP4_2}" ]; then
+ IP4_2="${value}"
+ fi
+ ;;
+ [0-9A-Fa-f:]*:*)
+ if [ -z "${IP6_1}" ] ; then
+ IP6_1="${value}"
+ elif [ -z "${IP6_2}" ]; then
+ IP6_2="${value}"
+ fi
+ ;;
+ esac
+ ;;
+ # ignore others
+ esac
+done < ${BSDINSTALL_TMPETC}/resolv.conf
+
+RESOLV=""
+if [ ${IPV6_AVAIL} -eq 1 -a ${IPV4_AVAIL} -eq 1 ]; then
+ RESOLV="
+ 'Search' 1 0 \"${SEARCH}\" 1 16 50 0 0
+ 'Nameserver' 2 0 \"Nameserver\" 2 16 50 0 2
+ 'IPv6 DNS #1' 2 0 \"${IP6_1}\" 2 16 50 0 0
+ 'IPv6 DNS #2' 3 0 \"${IP6_2}\" 3 16 50 0 0
+ 'IPv4 DNS #1' 4 0 \"${IP4_1}\" 4 16 16 0 0
+ 'IPv4 DNS #2' 5 0 \"${IP4_2}\" 5 16 16 0 0"
+elif [ ${IPV6_AVAIL} -eq 1 ]; then
+ RESOLV="
+ 'Search' 1 0 \"${SEARCH}\" 1 16 50 0 0
+ 'Nameserver' 2 0 \"Nameserver\" 2 16 50 0 2
+ 'IPv6 DNS #1' 2 0 \"${IP6_1}\" 2 16 50 0 0
+ 'IPv6 DNS #2' 3 0 \"${IP6_2}\" 3 16 50 0 0"
+elif [ ${IPV4_AVAIL} -eq 1 ]; then
+ RESOLV="
+ 'Search' 1 0 \"${SEARCH}\" 1 16 50 0 0
+ 'Nameserver' 2 0 \"Nameserver\" 2 16 50 0 2
+ 'IPv4 DNS #1' 2 0 \"${IP4_1}\" 2 16 16 0 0
+ 'IPv4 DNS #2' 3 0 \"${IP4_2}\" 3 16 16 0 0"
+else
+ exit 0
+fi
exec 3>&1
-IF_CONFIG=$(dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --form 'Static Network Interface Configuration' 0 0 0 \
- 'IP Address' 1 0 "$IP_ADDRESS" 1 20 16 0 \
- 'Subnet Mask' 2 0 "$NETMASK" 2 20 16 0 \
- 'Default Router' 3 0 "$ROUTER" 3 20 16 0 \
- \
- 'Nameserver' 5 0 "" 5 20 16 0 \
- 'Search Domain' 6 0 "" 6 20 20 0 \
+RESOLV=$(echo "${RESOLV}" | xargs dialog --backtitle 'FreeBSD Installer' \
+ --title 'Network Configuration' \
+ --mixedform 'Resovler Configuration' 0 0 0 \
2>&1 1>&3)
if [ $? -eq $DIALOG_CANCEL ]; then exec $0; fi
exec 3>&-
-echo $INTERFACE $IF_CONFIG |
- awk -v prefix="$IFCONFIG_PREFIX" '{
- printf("ifconfig_%s=\"%s%s netmask %s\"\n", $1, prefix, $2, $3);
- printf("defaultrouter=\"%s\"\n", $4);
- }' >> $BSDINSTALL_TMPETC/rc.conf.net
-
-if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
- . $BSDINSTALL_TMPETC/rc.conf.net
- ifconfig $INTERFACE `eval echo \\\$ifconfig_$INTERFACE`
- route delete default
- route add default $defaultrouter
-fi
-
-
-echo $IF_CONFIG |
- awk '{
- if ($4 != "")
- printf("nameserver %s\n", $4);
- if ($5 != "")
- printf("search %s\n", $5);
- }' > $BSDINSTALL_TMPETC/resolv.conf
+echo ${RESOLV} | tr ' ' '\n' | \
+awk '
+BEGIN {
+ search=-1;
+}
+{
+ if (/^[[:space:]]+$/) {
+ next;
+ }
+ if (/^Nameserver$/) {
+ printf "\n";
+ search=0;
+ next;
+ }
+ if (search == -1) {
+ printf "search ";
+ search=1;
+ }
+ if (search > 0) {
+ printf "%s%s", (search > 1) ? " " : "", $1;
+ search++;
+ next;
+ }
+ printf "nameserver %s\n", $1;
+}' > ${BSDINSTALL_TMPETC}/resolv.conf
+mv $BSDINSTALL_TMPETC/._rc.conf.net $BSDINSTALL_TMPETC/rc.conf.net
diff --git a/usr.sbin/bsdinstall/scripts/netconfig_ipv4 b/usr.sbin/bsdinstall/scripts/netconfig_ipv4
new file mode 100755
index 0000000..72dc0ee
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/netconfig_ipv4
@@ -0,0 +1,85 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+: ${DIALOG_OK=0}
+: ${DIALOG_CANCEL=1}
+: ${DIALOG_HELP=2}
+: ${DIALOG_EXTRA=3}
+: ${DIALOG_ITEM_HELP=4}
+: ${DIALOG_ESC=255}
+
+INTERFACE=$1
+IFCONFIG_PREFIX="$2"
+case "${INTERFACE}" in
+"") dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
+ --msgbox 'No interface specified for IPv4 configuration.' 0 0
+ exit 1
+ ;;
+esac
+
+dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --yesno 'Would you like to use DHCP to configure this interface?' 0 0
+if [ $? -eq $DIALOG_OK ]; then
+ echo ifconfig_$INTERFACE=\"${IFCONFIG_PREFIX}DHCP\" >> $BSDINSTALL_TMPETC/._rc.conf.net
+
+ if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ dialog --backtitle 'FreeBSD Installer' --infobox "Acquiring DHCP lease..." 0 0
+ dhclient $INTERFACE 2>> $BSDINSTALL_LOG
+ if [ $? -ne 0 ]; then
+ dialog --backtitle 'FreeBSD Installer' --msgbox "DHCP lease acquisition failed." 0 0
+ exec $0 ${INTERFACE} "${IFCONFIG_PREFIX}"
+ fi
+ fi
+ exit 0
+fi
+
+IP_ADDRESS=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $2); }'`
+NETMASK=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $4); }'`
+ROUTER=`netstat -rn -f inet | awk '/default/ {printf("%s\n", $2);}'`
+
+exec 3>&1
+IF_CONFIG=$(dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --form 'Static Network Interface Configuration' 0 0 0 \
+ 'IP Address' 1 0 "$IP_ADDRESS" 1 20 16 0 \
+ 'Subnet Mask' 2 0 "$NETMASK" 2 20 16 0 \
+ 'Default Router' 3 0 "$ROUTER" 3 20 16 0 \
+2>&1 1>&3)
+if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi
+exec 3>&-
+
+echo $INTERFACE $IF_CONFIG |
+ awk -v prefix="$IFCONFIG_PREFIX" '{
+ printf("ifconfig_%s=\"%s inet %s netmask %s\"\n", $1, prefix, $2, $3);
+ printf("defaultrouter=\"%s\"\n", $4);
+ }' >> $BSDINSTALL_TMPETC/._rc.conf.net
+
+if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ . $BSDINSTALL_TMPETC/._rc.conf.net
+ ifconfig $INTERFACE inet `eval echo \\\$ifconfig_$INTERFACE`
+ route delete -inet default
+ route add -inet default $defaultrouter
+fi
+
diff --git a/usr.sbin/bsdinstall/scripts/netconfig_ipv6 b/usr.sbin/bsdinstall/scripts/netconfig_ipv6
new file mode 100755
index 0000000..8bff816
--- /dev/null
+++ b/usr.sbin/bsdinstall/scripts/netconfig_ipv6
@@ -0,0 +1,148 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011 Nathan Whitehorn
+# All rights reserved.
+# Copyright (c) 2011 The FreeBSD Foundation
+# All rights reserved.
+#
+# Portions of this software were developed by Bjoern Zeeb
+# under sponsorship from the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+#
+# TODO:
+# - Add DHCPv6 support once FreeBSD ships with it.
+#
+
+: ${DIALOG_OK=0}
+: ${DIALOG_CANCEL=1}
+: ${DIALOG_HELP=2}
+: ${DIALOG_EXTRA=3}
+: ${DIALOG_ITEM_HELP=4}
+: ${DIALOG_ESC=255}
+
+INTERFACE=$1
+case "${INTERFACE}" in
+"") dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
+ --msgbox 'No interface specified for IPv6 configuration.' 0 0
+ exit 1
+ ;;
+esac
+
+AGAIN=""
+while : ; do
+ MSG="Would you like to try stateless address autoconfiguration (SLAAC)${AGAIN}?"
+ dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
+ --yesno "${MSG}" 0 0
+ if [ $? -eq $DIALOG_OK ]; then
+ if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ dialog --backtitle 'FreeBSD Installer' \
+ --infobox "Sending Router Solicitation ..." 0 0
+ ifconfig ${INTERFACE} inet6 -ifdisabled accept_rtadv up
+ rtsol -F $INTERFACE 2>> $BSDINSTALL_LOG
+ if [ $? -ne 0 ]; then
+ dialog --backtitle 'FreeBSD Installer' --msgbox "SLAAC failed." 0 0
+ AGAIN=" again"
+ continue
+ fi
+ fi
+ echo ifconfig_${INTERFACE}_ipv6=\"inet6 accept_rtadv\" >> $BSDINSTALL_TMPETC/._rc.conf.net
+ exit 0
+ else
+ break
+ fi
+done
+
+ROUTER6=`netstat -Wrn -f inet6 | awk '/default/ {printf("%s\n", $2);}'`
+ADDRS=`ifconfig ${INTERFACE} inet6 | \
+awk -v dfr="${ROUTER6}" '
+BEGIN {
+ n=0;
+}
+{
+ if (/inet6/) {
+ if (match($2, "^fe80:")) { next; };
+ # For the moment ignore all but the first address; it might confuse the user.
+ if (n > 0) { next; };
+ n++;
+ printf "\"IPv6 Address\" %d 0 \"%s/%s\" %d 16 50 0 0 ", n, $2, $4, n;
+ }
+}
+END {
+ if (n == 0) {
+ n++;
+ printf "\"IPv6 Address\" %d 0 \"\" %d 16 50 0 0 ", n, n;
+ }
+ n++;
+ # Nasty trick adding a (hidden, same y) read-only field as a marker
+ # to separate interface address(es) from the default router.
+ printf "\"Default Router\" %d 0 \"%s\" %d 16 50 0 2 ", n, "DefaultRouter", n;
+ printf "\"Default Router\" %d 0 \"%s\" %d 16 50 0 0 ", n, dfr, n;
+}'`
+
+exec 3>&1
+IF_CONFIG=$(echo ${ADDRS} | xargs dialog --backtitle 'FreeBSD Installer' \
+ --title 'Network Configuration' \
+ --mixedform 'Static IPv6 Network Interface Configuration' 0 0 0 \
+2>&1 1>&3)
+if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi
+exec 3>&-
+
+echo ${IF_CONFIG} | tr ' ' '\n' | \
+awk -v iface="${INTERFACE}" '
+BEGIN {
+ dfr=0;
+ count=0;
+}
+{
+ if (/^[[:space:]]+$/) {
+ next;
+ }
+ if (/DefaultRouter/) {
+ dfr=1;
+ next;
+ }
+ if (dfr == 1) {
+ printf("ipv6_defaultrouter=\"%s\"\n", $1);
+ next;
+ }
+ if (count > 0) {
+ # Ignore all but the first IP address for now.
+ next;
+ }
+ count++;
+ if (!match($1, "/")) {
+ sub("$", "/64", $1);
+ }
+ printf("ifconfig_%s_ipv6=\"inet6 %s\"\n", iface, $1);
+}' >> $BSDINSTALL_TMPETC/._rc.conf.net
+
+if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+ . $BSDINSTALL_TMPETC/._rc.conf.net
+ ifconfig ${INTERFACE} `eval echo \\\$ifconfig_${INTERFACE}_ipv6`
+ route delete default
+ route add default ${ipv6_defaultrouter}
+fi
+
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3 b/usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3
index ebcf286..b77b5f7 100644
--- a/usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/snmp_bridge.3
@@ -26,7 +26,7 @@
.\" $FreeBSD$
.\"
.Dd August 6, 2007
-.Dt snmp_bridge 3
+.Dt SNMP_BRIDGE 3
.Os
.Sh NAME
.Nm snmp_bridge
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3 b/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
index 403d605..774c027 100644
--- a/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/snmp_hostres.3
@@ -29,7 +29,7 @@
.\" $FreeBSD$
.\"
.Dd January 3, 2006
-.Dt snmp_hostres 3
+.Dt SNMP_HOSTRES 3
.Os
.Sh NAME
.Nm snmp_hostres
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile b/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile
index 9b8628b..6a53d46 100644
--- a/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile
@@ -6,8 +6,6 @@ MOD= wlan
SRCS= wlan_snmp.c wlan_sys.c
CFLAGS+= -DSNMPTREE_TYPES
-WARNS= 6
-
XSYM= begemotWlan
BMIBS= BEGEMOT-WIRELESS-MIB.txt
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.3 b/usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.3
index 9f366f1..20256f0 100644
--- a/usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.3
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/snmp_wlan.3
@@ -29,7 +29,7 @@
.\" $FreeBSD$
.\"
.Dd June 28, 2010
-.Dt snmp_wlan 3
+.Dt SNMP_WLAN 3
.Os
.Sh NAME
.Nm snmp_wlan
diff --git a/usr.sbin/diskinfo/diskinfo.c b/usr.sbin/diskinfo/diskinfo.c
index 2f00936..168a909 100644
--- a/usr.sbin/diskinfo/diskinfo.c
+++ b/usr.sbin/diskinfo/diskinfo.c
@@ -39,6 +39,7 @@
#include <paths.h>
#include <err.h>
#include <sys/disk.h>
+#include <sys/param.h>
#include <sys/time.h>
static void
@@ -57,7 +58,7 @@ int
main(int argc, char **argv)
{
int i, ch, fd, error, exitval = 0;
- char buf[BUFSIZ], ident[DISK_IDENT_SIZE];
+ char buf[BUFSIZ], ident[DISK_IDENT_SIZE], physpath[MAXPATHLEN];
off_t mediasize, stripesize, stripeoffset;
u_int sectorsize, fwsectors, fwheads;
@@ -151,6 +152,8 @@ main(int argc, char **argv)
}
if (ioctl(fd, DIOCGIDENT, ident) == 0)
printf("\t%-12s\t# Disk ident.\n", ident);
+ if (ioctl(fd, DIOCGPHYSPATH, physpath) == 0)
+ printf("\t%-12s\t# Physical path\n", physpath);
}
printf("\n");
if (opt_c)
diff --git a/usr.sbin/fdread/fdread.c b/usr.sbin/fdread/fdread.c
index 1aae665..ba9c758 100644
--- a/usr.sbin/fdread/fdread.c
+++ b/usr.sbin/fdread/fdread.c
@@ -149,7 +149,7 @@ main(int argc, char **argv)
err(EX_OSERR, "cannot create output file %s", fname);
}
- if ((fd = open(_devname, O_RDWR)) == -1)
+ if ((fd = open(_devname, O_RDONLY)) == -1)
err(EX_OSERR, "cannot open device %s", _devname);
return (numids? doreadid(fd, numids, trackno): doread(fd, of, _devname));
diff --git a/usr.sbin/gpioctl/gpioctl.8 b/usr.sbin/gpioctl/gpioctl.8
index ca14bec..4ceecf6 100644
--- a/usr.sbin/gpioctl/gpioctl.8
+++ b/usr.sbin/gpioctl/gpioctl.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 27, 2010
+.Dd May 25, 2011
.Dt GPIOCTL 1
.Os
.Sh NAME
@@ -93,17 +93,17 @@ be verbose: for each listed pin print current configuration
.Sh EXAMPLES
.Bl -bullet
.It
-List pins available on GPIO controller defined by device /dev/gpioctl0
+List pins available on GPIO controller defined by device /dev/gpioc0
.Pp
-gpioctl -f /dev/gpioctl0 -l
+gpioctl -f /dev/gpioc0 -l
.It
Set the value of pin 12 to 1
.Pp
-gpioctl -f /dev/gpioctl0 12 1
+gpioctl -f /dev/gpioc0 12 1
.It
Configure pin 12 to be input pin
.Pp
-gpioctl -f /dev/gpioctl0 -c 12 IN
+gpioctl -f /dev/gpioc0 -c 12 IN
.El
.Sh HISTORY
The
diff --git a/usr.sbin/jail/Makefile b/usr.sbin/jail/Makefile
index de35dcf..52d237b 100644
--- a/usr.sbin/jail/Makefile
+++ b/usr.sbin/jail/Makefile
@@ -10,5 +10,8 @@ LDADD= -ljail -lutil
.if ${MK_INET6_SUPPORT} != "no"
CFLAGS+= -DINET6
.endif
+.if ${MK_INET_SUPPORT} != "no"
+CFLAGS+= -DINET
+.endif
.include <bsd.prog.mk>
diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c
index 0722bfd..fc4f71c 100644
--- a/usr.sbin/jail/jail.c
+++ b/usr.sbin/jail/jail.c
@@ -54,12 +54,18 @@ static struct jailparam *params;
static char **param_values;
static int nparams;
-static char *ip4_addr;
#ifdef INET6
+static int ip6_ok;
static char *ip6_addr;
#endif
+#ifdef INET
+static int ip4_ok;
+static char *ip4_addr;
+#endif
+#if defined(INET6) || defined(INET)
static void add_ip_addr(char **addrp, char *newaddr);
+#endif
#ifdef INET6
static void add_ip_addr46(char *newaddr);
#endif
@@ -194,6 +200,13 @@ main(int argc, char **argv)
if (uflag)
GET_USER_INFO;
+#ifdef INET6
+ ip6_ok = feature_present("inet6");
+#endif
+#ifdef INET
+ ip4_ok = feature_present("inet");
+#endif
+
if (jailname)
set_param("name", jailname);
if (securelevel)
@@ -207,10 +220,12 @@ main(int argc, char **argv)
break;
}
if (hflag) {
+#ifdef INET
if (!strncmp(argv[i], "ip4.addr=", 9)) {
add_ip_addr(&ip4_addr, argv[i] + 9);
break;
}
+#endif
#ifdef INET6
if (!strncmp(argv[i], "ip6.addr=", 9)) {
add_ip_addr(&ip6_addr, argv[i] + 9);
@@ -231,12 +246,14 @@ main(int argc, char **argv)
set_param("host.hostname", argv[1]);
if (hflag)
add_ip_addrinfo(0, argv[1]);
+#if defined(INET6) || defined(INET)
if (argv[2][0] != '\0')
#ifdef INET6
add_ip_addr46(argv[2]);
#else
add_ip_addr(&ip4_addr, argv[2]);
#endif
+#endif
cmdarg = 3;
/* Emulate the defaults from security.jail.* sysctls */
sysvallen = sizeof(sysval);
@@ -259,8 +276,10 @@ main(int argc, char **argv)
}
}
}
+#ifdef INET
if (ip4_addr != NULL)
set_param("ip4.addr", ip4_addr);
+#endif
#ifdef INET6
if (ip6_addr != NULL)
set_param("ip6.addr", ip6_addr);
@@ -297,14 +316,19 @@ main(int argc, char **argv)
for (i = 0; i < nparams; i++)
if (!strcmp(params[i].jp_name, "path"))
break;
-#ifdef INET6
+#if defined(INET6) && defined(INET)
fprintf(fp, "%d\t%s\t%s\t%s%s%s\t%s\n",
jid, i < nparams
? (char *)params[i].jp_value : argv[0],
argv[1], ip4_addr ? ip4_addr : "",
ip4_addr && ip4_addr[0] && ip6_addr && ip6_addr[0]
? "," : "", ip6_addr ? ip6_addr : "", argv[3]);
-#else
+#elif defined(INET6)
+ fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
+ jid, i < nparams
+ ? (char *)params[i].jp_value : argv[0],
+ argv[1], ip6_addr ? ip6_addr : "", argv[3]);
+#elif defined(INET)
fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
jid, i < nparams
? (char *)params[i].jp_value : argv[0],
@@ -348,6 +372,7 @@ main(int argc, char **argv)
err(1, "execvp: %s", argv[cmdarg]);
}
+#if defined(INET6) || defined(INET)
static void
add_ip_addr(char **addrp, char *value)
{
@@ -368,6 +393,7 @@ add_ip_addr(char **addrp, char *value)
*addrp = addr;
}
}
+#endif
#ifdef INET6
static void
@@ -391,23 +417,24 @@ static void
add_ip_addrinfo(int ai_flags, char *value)
{
struct addrinfo hints, *ai0, *ai;
- struct in_addr addr4;
- size_t size;
- int error, ip4ok;
- int mib[4];
+ int error;
+#ifdef INET
char avalue4[INET_ADDRSTRLEN];
+ struct in_addr addr4;
+#endif
#ifdef INET6
- struct in6_addr addr6;
- int ip6ok;
char avalue6[INET6_ADDRSTRLEN];
+ struct in6_addr addr6;
#endif
/* Look up the hostname (or get the address) */
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
-#ifdef INET6
+#if defined(INET6) && defined(INET)
hints.ai_family = PF_UNSPEC;
-#else
+#elif defined(INET6)
+ hints.ai_family = PF_INET6;
+#elif defined(INET)
hints.ai_family = PF_INET;
#endif
hints.ai_flags = ai_flags;
@@ -415,32 +442,12 @@ add_ip_addrinfo(int ai_flags, char *value)
if (error != 0)
errx(1, "hostname %s: %s", value, gai_strerror(error));
- /*
- * Silently ignore unsupported address families from DNS lookups.
- * But if this is a numeric address, let the kernel give the error.
- */
- if (ai_flags & AI_NUMERICHOST)
- ip4ok =
-#ifdef INET6
- ip6ok =
-#endif
- 1;
- else {
- size = 4;
- ip4ok = (sysctlnametomib("security.jail.param.ip4", mib,
- &size) == 0);
-#ifdef INET6
- size = 4;
- ip6ok = (sysctlnametomib("security.jail.param.ip6", mib,
- &size) == 0);
-#endif
- }
-
/* Convert the addresses to ASCII so set_param can convert them back. */
for (ai = ai0; ai; ai = ai->ai_next)
switch (ai->ai_family) {
+#ifdef INET
case AF_INET:
- if (!ip4ok)
+ if (!ip4_ok && (ai_flags & AI_NUMERICHOST) == 0)
break;
memcpy(&addr4, &((struct sockaddr_in *)
(void *)ai->ai_addr)->sin_addr, sizeof(addr4));
@@ -449,9 +456,10 @@ add_ip_addrinfo(int ai_flags, char *value)
err(1, "inet_ntop");
add_ip_addr(&ip4_addr, avalue4);
break;
+#endif
#ifdef INET6
case AF_INET6:
- if (!ip6ok)
+ if (!ip6_ok && (ai_flags & AI_NUMERICHOST) == 0)
break;
memcpy(&addr6, &((struct sockaddr_in6 *)
(void *)ai->ai_addr)->sin6_addr, sizeof(addr6));
diff --git a/usr.sbin/jls/Makefile b/usr.sbin/jls/Makefile
index e1157af..b297cc4 100644
--- a/usr.sbin/jls/Makefile
+++ b/usr.sbin/jls/Makefile
@@ -1,8 +1,17 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
PROG= jls
MAN= jls.8
DPADD= ${LIBJAIL}
LDADD= -ljail
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+= -DINET6
+.endif
+.if ${MK_INET_SUPPORT} != "no"
+CFLAGS+= -DINET
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/jls/jls.c b/usr.sbin/jls/jls.c
index 2c1655b..6568a1d 100644
--- a/usr.sbin/jls/jls.c
+++ b/usr.sbin/jls/jls.c
@@ -59,6 +59,12 @@ __FBSDID("$FreeBSD$");
static struct jailparam *params;
static int *param_parent;
static int nparams;
+#ifdef INET6
+static int ip6_ok;
+#endif
+#ifdef INET
+static int ip4_ok;
+#endif
static int add_param(const char *name, void *value, size_t valuelen,
struct jailparam *source, unsigned flags);
@@ -112,6 +118,13 @@ main(int argc, char **argv)
errx(1, "usage: jls [-dhnqv] [-j jail] [param ...]");
}
+#ifdef INET6
+ ip6_ok = feature_present("inet6");
+#endif
+#ifdef INET
+ ip4_ok = feature_present("inet");
+#endif
+
/* Add the parameters to print. */
if (optind == argc) {
if (pflags & (PRINT_HEADER | PRINT_NAMEVAL))
@@ -124,13 +137,24 @@ main(int argc, char **argv)
add_param("name", NULL, (size_t)0, NULL, JP_USER);
add_param("dying", NULL, (size_t)0, NULL, JP_USER);
add_param("cpuset.id", NULL, (size_t)0, NULL, JP_USER);
- add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER);
- add_param("ip6.addr", NULL, (size_t)0, NULL,
- JP_USER | JP_OPT);
+#ifdef INET
+ if (ip4_ok)
+ add_param("ip4.addr", NULL, (size_t)0, NULL,
+ JP_USER);
+#endif
+#ifdef INET6
+ if (ip6_ok)
+ add_param("ip6.addr", NULL, (size_t)0, NULL,
+ JP_USER | JP_OPT);
+#endif
} else {
pflags |= PRINT_DEFAULT;
add_param("jid", NULL, (size_t)0, NULL, JP_USER);
- add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER);
+#ifdef INET
+ if (ip4_ok)
+ add_param("ip4.addr", NULL, (size_t)0, NULL,
+ JP_USER);
+#endif
add_param("host.hostname", NULL, (size_t)0, NULL,
JP_USER);
add_param("path", NULL, (size_t)0, NULL, JP_USER);
@@ -327,7 +351,7 @@ print_jail(int pflags, int jflags)
{
char *nname;
char **param_values;
- int i, ai, jid, count, spc;
+ int i, ai, jid, count, n, spc;
char ipbuf[INET6_ADDRSTRLEN];
jid = jailparam_get(params, nparams, jflags);
@@ -345,31 +369,45 @@ print_jail(int pflags, int jflags)
*(int *)params[4].jp_value ? "DYING" : "ACTIVE",
"",
*(int *)params[5].jp_value);
- count = params[6].jp_valuelen / sizeof(struct in_addr);
- for (ai = 0; ai < count; ai++)
- if (inet_ntop(AF_INET,
- &((struct in_addr *)params[6].jp_value)[ai],
- ipbuf, sizeof(ipbuf)) == NULL)
- err(1, "inet_ntop");
- else
- printf("%6s %-15.15s\n", "", ipbuf);
- if (!strcmp(params[7].jp_name, "ip6.addr")) {
- count = params[7].jp_valuelen / sizeof(struct in6_addr);
+ n = 6;
+#ifdef INET
+ if (ip4_ok && !strcmp(params[n].jp_name, "ip.addr")) {
+ count = params[n].jp_valuelen / sizeof(struct in_addr);
+ for (ai = 0; ai < count; ai++)
+ if (inet_ntop(AF_INET,
+ &((struct in_addr *)params[n].jp_value)[ai],
+ ipbuf, sizeof(ipbuf)) == NULL)
+ err(1, "inet_ntop");
+ else
+ printf("%6s %-15.15s\n", "", ipbuf);
+ n++;
+ }
+#endif
+#ifdef INET6
+ if (ip6_ok && !strcmp(params[n].jp_name, "ip6.addr")) {
+ count = params[n].jp_valuelen / sizeof(struct in6_addr);
for (ai = 0; ai < count; ai++)
if (inet_ntop(AF_INET6,
- &((struct in6_addr *)params[7].jp_value)[ai],
+ &((struct in6_addr *)
+ params[n].jp_value)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
err(1, "inet_ntop");
else
printf("%6s %s\n", "", ipbuf);
+ n++;
}
+#endif
} else if (pflags & PRINT_DEFAULT)
printf("%6d %-15.15s %-29.29s %.74s\n",
*(int *)params[0].jp_value,
- params[1].jp_valuelen == 0 ? "-"
+#ifdef INET
+ (!ip4_ok || params[1].jp_valuelen == 0) ? "-"
: inet_ntoa(*(struct in_addr *)params[1].jp_value),
- (char *)params[2].jp_value,
- (char *)params[3].jp_value);
+#else
+ "-",
+#endif
+ (char *)params[2-!ip4_ok].jp_value,
+ (char *)params[3-!ip4_ok].jp_value);
else {
param_values = alloca(nparams * sizeof(*param_values));
for (i = 0; i < nparams; i++) {
diff --git a/usr.sbin/kbdmap/kbdmap.c b/usr.sbin/kbdmap/kbdmap.c
index 93c5a08..c993389 100644
--- a/usr.sbin/kbdmap/kbdmap.c
+++ b/usr.sbin/kbdmap/kbdmap.c
@@ -226,10 +226,10 @@ get_font(void)
}
}
}
+ fclose(fp);
} else
fprintf(stderr, "Could not open %s for reading\n", sysconfig);
- fclose(fp);
return fnt;
}
diff --git a/usr.sbin/lastlogin/lastlogin.8 b/usr.sbin/lastlogin/lastlogin.8
index 0630163..fdbc871 100644
--- a/usr.sbin/lastlogin/lastlogin.8
+++ b/usr.sbin/lastlogin/lastlogin.8
@@ -31,7 +31,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 11, 1996
+.Dd June 6, 2011
.Dt LASTLOGIN 8
.Os
.Sh NAME
@@ -39,6 +39,8 @@
.Nd indicate last login time of users
.Sh SYNOPSIS
.Nm
+.Op Fl f Ar file
+.Op Fl rt
.Op Ar user ...
.Sh DESCRIPTION
The
@@ -54,8 +56,8 @@ If more than one
.Ar user
is given, the session information for each user is printed in
the order given on the command line.
-Otherwise, information
-for all users is printed, sorted by name.
+Otherwise, information for all users is printed.
+By default, the entries are sorted by user name.
.Pp
The
.Nm
@@ -63,6 +65,18 @@ utility differs from
.Xr last 1
in that it only prints information regarding the very last login session.
The last login database is never turned over or deleted in standard usage.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl f Ar file
+Open last login database
+.Ar file
+instead of the system-wide database.
+.It Fl r
+Print the entries in reverse sorted order.
+.It Fl t
+Sort the elements by last login time, instead of user name.
+.El
.Sh FILES
.Bl -tag -width /var/log/utx.lastlogin -compact
.It Pa /var/log/utx.lastlogin
diff --git a/usr.sbin/lastlogin/lastlogin.c b/usr.sbin/lastlogin/lastlogin.c
index 4c08547..2f8dd78 100644
--- a/usr.sbin/lastlogin/lastlogin.c
+++ b/usr.sbin/lastlogin/lastlogin.c
@@ -47,30 +47,59 @@ __RCSID("$NetBSD: lastlogin.c,v 1.4 1998/02/03 04:45:35 perry Exp $");
int main(int, char **);
static void output(struct utmpx *);
static void usage(void);
+static int utcmp_user(const void *, const void *);
+
+static int order = 1;
+static const char *file = NULL;
+static int (*utcmp)(const void *, const void *) = utcmp_user;
static int
-utcmp(const void *u1, const void *u2)
+utcmp_user(const void *u1, const void *u2)
{
- return (strcmp(((const struct utmpx *)u1)->ut_user,
+ return (order * strcmp(((const struct utmpx *)u1)->ut_user,
((const struct utmpx *)u2)->ut_user));
}
+static int
+utcmp_time(const void *u1, const void *u2)
+{
+ time_t t1, t2;
+
+ t1 = ((const struct utmpx *)u1)->ut_tv.tv_sec;
+ t2 = ((const struct utmpx *)u2)->ut_tv.tv_sec;
+ return (t1 < t2 ? order : t1 > t2 ? -order : 0);
+}
+
int
main(int argc, char *argv[])
{
int ch, i, ulistsize;
struct utmpx *u, *ulist;
- while ((ch = getopt(argc, argv, "")) != -1) {
- usage();
+ while ((ch = getopt(argc, argv, "f:rt")) != -1) {
+ switch (ch) {
+ case 'f':
+ file = optarg;
+ break;
+ case 'r':
+ order = -1;
+ break;
+ case 't':
+ utcmp = utcmp_time;
+ break;
+ default:
+ usage();
+ }
}
+ argc -= optind;
+ argv += optind;
- /* Process usernames given on the command line. */
- if (argc > 1) {
- for (i = 1; i < argc; ++i) {
- if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)
- errx(1, "failed to open lastlog database");
+ if (argc > 0) {
+ /* Process usernames given on the command line. */
+ for (i = 0; i < argc; i++) {
+ if (setutxdb(UTXDB_LASTLOGIN, file) != 0)
+ err(1, "failed to open lastlog database");
if ((u = getutxuser(argv[i])) == NULL) {
warnx("user '%s' not found", argv[i]);
continue;
@@ -78,11 +107,10 @@ main(int argc, char *argv[])
output(u);
endutxent();
}
- }
- /* Read all lastlog entries, looking for active ones */
- else {
- if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)
- errx(1, "failed to open lastlog database");
+ } else {
+ /* Read all lastlog entries, looking for active ones. */
+ if (setutxdb(UTXDB_LASTLOGIN, file) != 0)
+ err(1, "failed to open lastlog database");
ulist = NULL;
ulistsize = 0;
while ((u = getutxent()) != NULL) {
@@ -119,6 +147,6 @@ output(struct utmpx *u)
static void
usage(void)
{
- fprintf(stderr, "usage: lastlogin [user ...]\n");
+ fprintf(stderr, "usage: lastlogin [-f file] [-rt] [user ...]\n");
exit(1);
}
diff --git a/usr.sbin/makefs/Makefile b/usr.sbin/makefs/Makefile
index 37eeb38..6fa0679 100644
--- a/usr.sbin/makefs/Makefile
+++ b/usr.sbin/makefs/Makefile
@@ -7,6 +7,7 @@ CFLAGS+=-I${.CURDIR}
SRCS= cd9660.c ffs.c \
getid.c \
makefs.c \
+ mtree.c \
walk.c
MAN= makefs.8
@@ -26,4 +27,7 @@ SRCS+= misc.c spec.c
.PATH: ${.CURDIR}/../../sys/ufs/ffs
SRCS+= ffs_tables.c
+DPADD= ${LIBSBUF}
+LDADD= -lsbuf
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/makefs/cd9660/cd9660_write.c b/usr.sbin/makefs/cd9660/cd9660_write.c
index 46d4a34..4622701 100644
--- a/usr.sbin/makefs/cd9660/cd9660_write.c
+++ b/usr.sbin/makefs/cd9660/cd9660_write.c
@@ -294,10 +294,12 @@ cd9660_write_file(FILE *fd, cd9660node *writenode)
INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32,
__func__, (int)inode->st.st_ino, inode->ino));
inode->flags |= FI_WRITTEN;
- cd9660_compute_full_filename(writenode,
- temp_file_name, 0);
+ if (writenode->node->contents == NULL)
+ cd9660_compute_full_filename(writenode,
+ temp_file_name, 0);
ret = cd9660_copy_file(fd, writenode->fileDataSector,
- temp_file_name);
+ (writenode->node->contents != NULL) ?
+ writenode->node->contents : temp_file_name);
if (ret == 0)
goto out;
}
diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c
index a3c9d68..f833cf5 100644
--- a/usr.sbin/makefs/ffs.c
+++ b/usr.sbin/makefs/ffs.c
@@ -776,9 +776,11 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
continue; /* skip hard-linked entries */
cur->inode->flags |= FI_WRITTEN;
- if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
- >= sizeof(path))
- errx(1, "Pathname too long.");
+ if (cur->contents == NULL) {
+ if (snprintf(path, sizeof(path), "%s/%s", dir,
+ cur->name) >= sizeof(path))
+ errx(1, "Pathname too long.");
+ }
if (cur->child != NULL)
continue; /* child creates own inode */
@@ -802,7 +804,8 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
if (membuf != NULL) {
ffs_write_file(&din, cur->inode->ino, membuf, fsopts);
} else if (S_ISREG(cur->type)) {
- ffs_write_file(&din, cur->inode->ino, path, fsopts);
+ ffs_write_file(&din, cur->inode->ino,
+ (cur->contents) ? cur->contents : path, fsopts);
} else {
assert (! S_ISDIR(cur->type));
ffs_write_inode(&din, cur->inode->ino, fsopts);
diff --git a/usr.sbin/makefs/ffs/ffs_bswap.c b/usr.sbin/makefs/ffs/ffs_bswap.c
index 18ace03..a1a1c46 100644
--- a/usr.sbin/makefs/ffs/ffs_bswap.c
+++ b/usr.sbin/makefs/ffs/ffs_bswap.c
@@ -41,14 +41,6 @@ __FBSDID("$FreeBSD$");
#include <ufs/ufs/dinode.h>
#include "ffs/ufs_bswap.h"
#include <ufs/ffs/fs.h>
-/* XXX temporary */
-struct ufsmount;
-struct bufobj;
-struct mount;
-struct vnode;
-typedef int vfs_vget_t(struct mount *mp, ino_t ino, int flags,
- struct vnode **vpp);
-#include <ufs/ffs/ffs_extern.h>
#if !defined(_KERNEL)
#include <stddef.h>
diff --git a/usr.sbin/makefs/ffs/ffs_subr.c b/usr.sbin/makefs/ffs/ffs_subr.c
index 5f9b6f2..b857a58 100644
--- a/usr.sbin/makefs/ffs/ffs_subr.c
+++ b/usr.sbin/makefs/ffs/ffs_subr.c
@@ -38,15 +38,8 @@ __FBSDID("$FreeBSD$");
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
-/* XXX temporary */
-struct ufsmount;
-struct bufobj;
-struct mount;
-struct vnode;
-typedef int vfs_vget_t(struct mount *mp, ino_t ino, int flags,
- struct vnode **vpp);
-#include <ufs/ffs/ffs_extern.h>
#include "ffs/ufs_bswap.h"
+
void panic __P((const char *, ...))
__attribute__((__noreturn__,__format__(__printf__,1,2)));
diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
index b9fb10e..9fe5c01 100644
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -40,7 +40,7 @@
.Os
.Sh NAME
.Nm makefs
-.Nd create a file system image from a directory tree
+.Nd create a file system image from a directory tree or a mtree manifest
.Sh SYNOPSIS
.Nm
.Op Fl x
@@ -57,14 +57,16 @@
.Op Fl s Ar image-size
.Op Fl t Ar fs-type
.Ar image-file
-.Ar directory
+.Ar directory | manifest
.Sh DESCRIPTION
The utility
.Nm
creates a file system image into
.Ar image-file
from the directory tree
-.Ar directory .
+.Ar directory
+or from the mtree manifest
+.Ar manifest .
No special devices or privileges are required to perform this task.
.Pp
The options are as follows:
@@ -106,6 +108,8 @@ as an
.Xr mtree 8
.Sq specfile
specification.
+This option has no effect when the image is created from a mtree manifest
+rather than a directory.
.Pp
If a specfile entry exists in the underlying file system, its
permissions and modification time will be used unless specifically
@@ -330,6 +334,7 @@ Use RockRidge extensions (for longer filenames, etc.).
Volume set identifier of the image.
.El
.Sh SEE ALSO
+.Xr mtree 5 ,
.Xr mtree 8 ,
.Xr newfs 8
.Sh HISTORY
diff --git a/usr.sbin/makefs/makefs.c b/usr.sbin/makefs/makefs.c
index 60b6916..a186014 100644
--- a/usr.sbin/makefs/makefs.c
+++ b/usr.sbin/makefs/makefs.c
@@ -38,6 +38,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/types.h>
+#include <sys/stat.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@@ -80,11 +82,13 @@ int main(int, char *[]);
int
main(int argc, char *argv[])
{
+ struct stat sb;
struct timeval start;
fstype_t *fstype;
fsinfo_t fsoptions;
fsnode *root;
int ch, len;
+ char *subtree;
char *specfile;
setprogname(argv[0]);
@@ -244,26 +248,47 @@ main(int argc, char *argv[])
if (fsoptions.onlyspec != 0 && specfile == NULL)
errx(1, "-x requires -F mtree-specfile.");
- /* walk the tree */
- TIMER_START(start);
- root = walk_dir(argv[1], NULL);
- TIMER_RESULTS(start, "walk_dir");
+ /* Accept '-' as meaning "read from standard input". */
+ if (strcmp(argv[1], "-") == 0)
+ sb.st_mode = S_IFREG;
+ else {
+ if (stat(argv[1], &sb) == -1)
+ err(1, "Can't stat `%s'", argv[1]);
+ }
+
+ switch (sb.st_mode & S_IFMT) {
+ case S_IFDIR: /* walk the tree */
+ subtree = argv[1];
+ TIMER_START(start);
+ root = walk_dir(subtree, NULL);
+ TIMER_RESULTS(start, "walk_dir");
+ break;
+ case S_IFREG: /* read the manifest file */
+ subtree = ".";
+ TIMER_START(start);
+ root = read_mtree(argv[1], NULL);
+ TIMER_RESULTS(start, "manifest");
+ break;
+ default:
+ errx(1, "%s: not a file or directory", argv[1]);
+ /* NOTREACHED */
+ }
if (specfile) { /* apply a specfile */
TIMER_START(start);
- apply_specfile(specfile, argv[1], root, fsoptions.onlyspec);
+ apply_specfile(specfile, subtree, root, fsoptions.onlyspec);
TIMER_RESULTS(start, "apply_specfile");
}
if (debug & DEBUG_DUMP_FSNODES) {
- printf("\nparent: %s\n", argv[1]);
+ printf("\nparent: %s\n", subtree);
dump_fsnodes(".", root);
putchar('\n');
}
/* build the file system */
TIMER_START(start);
- fstype->make_fs(argv[0], argv[1], root, &fsoptions);
+ fstype->make_fs(argv[0], subtree, root, &fsoptions);
TIMER_RESULTS(start, "make_fs");
free_fsnodes(root);
@@ -311,7 +336,7 @@ usage(void)
"usage: %s [-t fs-type] [-o fs-options] [-d debug-mask] [-B endian]\n"
"\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-s image-size]\n"
"\t[-b free-blocks] [-f free-files] [-F mtree-specfile] [-x]\n"
-"\t[-N userdb-dir] image-file directory\n",
+"\t[-N userdb-dir] image-file directory | manifest\n",
prog);
exit(1);
}
diff --git a/usr.sbin/makefs/makefs.h b/usr.sbin/makefs/makefs.h
index 997c4db..6556ec0 100644
--- a/usr.sbin/makefs/makefs.h
+++ b/usr.sbin/makefs/makefs.h
@@ -93,11 +93,13 @@ typedef struct _fsnode {
uint32_t type; /* type of entry */
fsinode *inode; /* actual inode data */
char *symlink; /* symlink target */
+ char *contents; /* file to provide contents */
char *name; /* file name */
int flags; /* misc flags */
} fsnode;
#define FSNODE_F_HASSPEC 0x01 /* fsnode has a spec entry */
+#define FSNODE_F_OPTIONAL 0x02 /* fsnode is optional */
/*
* fsinfo_t - contains various settings and parameters pertaining to
@@ -147,6 +149,7 @@ typedef struct {
void apply_specfile(const char *, const char *, fsnode *, int);
void dump_fsnodes(const char *, fsnode *);
const char * inode_type(mode_t);
+fsnode * read_mtree(const char *, fsnode *);
int set_option(option_t *, const char *, const char *);
fsnode * walk_dir(const char *, fsnode *);
void free_fsnodes(fsnode *);
diff --git a/usr.sbin/makefs/mtree.c b/usr.sbin/makefs/mtree.c
new file mode 100644
index 0000000..5d88ad6
--- /dev/null
+++ b/usr.sbin/makefs/mtree.c
@@ -0,0 +1,1051 @@
+/*-
+ * Copyright (c) 2011 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/sbuf.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "makefs.h"
+
+#define IS_DOT(nm) ((nm)[0] == '.' && (nm)[1] == '\0')
+#define IS_DOTDOT(nm) ((nm)[0] == '.' && (nm)[1] == '.' && (nm)[2] == '\0')
+
+struct mtree_fileinfo {
+ SLIST_ENTRY(mtree_fileinfo) next;
+ FILE *fp;
+ const char *name;
+ u_int line;
+};
+
+/* Global state used while parsing. */
+static SLIST_HEAD(, mtree_fileinfo) mtree_fileinfo =
+ SLIST_HEAD_INITIALIZER(mtree_fileinfo);
+static fsnode *mtree_root;
+static fsnode *mtree_current;
+static fsnode mtree_global;
+static fsinode mtree_global_inode;
+static u_int errors, warnings;
+
+static void mtree_error(const char *, ...) __printflike(1, 2);
+static void mtree_warning(const char *, ...) __printflike(1, 2);
+
+static int
+mtree_file_push(const char *name, FILE *fp)
+{
+ struct mtree_fileinfo *fi;
+
+ fi = malloc(sizeof(*fi));
+ if (fi == NULL)
+ return (ENOMEM);
+
+ if (strcmp(name, "-") == 0)
+ fi->name = strdup("(stdin)");
+ else
+ fi->name = strdup(name);
+ if (fi->name == NULL) {
+ free(fi);
+ return (ENOMEM);
+ }
+
+ fi->fp = fp;
+ fi->line = 0;
+
+ SLIST_INSERT_HEAD(&mtree_fileinfo, fi, next);
+ return (0);
+}
+
+static void
+mtree_print(const char *msgtype, const char *fmt, va_list ap)
+{
+ struct mtree_fileinfo *fi;
+
+ if (msgtype != NULL) {
+ fi = SLIST_FIRST(&mtree_fileinfo);
+ if (fi != NULL)
+ fprintf(stderr, "%s:%u: ", fi->name, fi->line);
+ fprintf(stderr, "%s: ", msgtype);
+ }
+ vfprintf(stderr, fmt, ap);
+}
+
+static void
+mtree_error(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ mtree_print("error", fmt, ap);
+ va_end(ap);
+
+ errors++;
+ fputc('\n', stderr);
+}
+
+static void
+mtree_warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ mtree_print("warning", fmt, ap);
+ va_end(ap);
+
+ warnings++;
+ fputc('\n', stderr);
+}
+
+/* mtree_resolve() sets errno to indicate why NULL was returned. */
+static char *
+mtree_resolve(const char *spec, int *istemp)
+{
+ struct sbuf *sb;
+ char *res, *var;
+ const char *base, *p, *v;
+ size_t len;
+ int c, error, quoted, subst;
+
+ len = strlen(spec);
+ if (len == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ c = (len > 1) ? (spec[0] == spec[len - 1]) ? spec[0] : 0 : 0;
+ *istemp = (c == '`') ? 1 : 0;
+ subst = (c == '`' || c == '"') ? 1 : 0;
+ quoted = (subst || c == '\'') ? 1 : 0;
+
+ if (!subst) {
+ res = strdup(spec + quoted);
+ if (res != NULL && quoted)
+ res[len - 2] = '\0';
+ return (res);
+ }
+
+ sb = sbuf_new_auto();
+ if (sb == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ base = spec + 1;
+ len -= 2;
+ error = 0;
+ while (len > 0) {
+ p = strchr(base, '$');
+ if (p == NULL) {
+ sbuf_bcat(sb, base, len);
+ base += len;
+ len = 0;
+ continue;
+ }
+ /* The following is safe. spec always starts with a quote. */
+ if (p[-1] == '\\')
+ p--;
+ if (base != p) {
+ sbuf_bcat(sb, base, p - base);
+ len -= p - base;
+ base = p;
+ }
+ if (*p == '\\') {
+ sbuf_putc(sb, '$');
+ base += 2;
+ len -= 2;
+ continue;
+ }
+ /* Skip the '$'. */
+ base++;
+ len--;
+ /* Handle ${X} vs $X. */
+ v = base;
+ if (*base == '{') {
+ p = strchr(v, '}');
+ if (p == NULL)
+ p = v;
+ } else
+ p = v;
+ len -= (p + 1) - base;
+ base = p + 1;
+
+ if (v == p) {
+ sbuf_putc(sb, *v);
+ continue;
+ }
+
+ error = ENOMEM;
+ var = calloc(p - v, 1);
+ if (var == NULL)
+ break;
+
+ memcpy(var, v + 1, p - v - 1);
+ if (strcmp(var, ".CURDIR") == 0) {
+ res = getcwd(NULL, 0);
+ if (res == NULL)
+ break;
+ } else if (strcmp(var, ".PROG") == 0) {
+ res = strdup(getprogname());
+ if (res == NULL)
+ break;
+ } else {
+ v = getenv(var);
+ if (v != NULL) {
+ res = strdup(v);
+ if (res == NULL)
+ break;
+ } else
+ res = NULL;
+ }
+ error = 0;
+
+ if (res != NULL) {
+ sbuf_cat(sb, res);
+ free(res);
+ }
+ free(var);
+ }
+
+ sbuf_finish(sb);
+ res = (error == 0) ? strdup(sbuf_data(sb)) : NULL;
+ sbuf_delete(sb);
+ if (res == NULL)
+ errno = ENOMEM;
+ return (res);
+}
+
+static int
+skip_over(FILE *fp, const char *cs)
+{
+ int c;
+
+ c = getc(fp);
+ while (c != EOF && strchr(cs, c) != NULL)
+ c = getc(fp);
+ if (c != EOF) {
+ ungetc(c, fp);
+ return (0);
+ }
+ return (ferror(fp) ? errno : -1);
+}
+
+static int
+skip_to(FILE *fp, const char *cs)
+{
+ int c;
+
+ c = getc(fp);
+ while (c != EOF && strchr(cs, c) == NULL)
+ c = getc(fp);
+ if (c != EOF) {
+ ungetc(c, fp);
+ return (0);
+ }
+ return (ferror(fp) ? errno : -1);
+}
+
+static int
+read_word(FILE *fp, char *buf, size_t bufsz)
+{
+ struct mtree_fileinfo *fi;
+ size_t idx, qidx;
+ int c, done, error, esc, qlvl;
+
+ if (bufsz == 0)
+ return (EINVAL);
+
+ done = 0;
+ esc = 0;
+ idx = 0;
+ qidx = -1;
+ qlvl = 0;
+ do {
+ c = getc(fp);
+ switch (c) {
+ case EOF:
+ buf[idx] = '\0';
+ error = ferror(fp) ? errno : -1;
+ if (error == -1)
+ mtree_error("unexpected end of file");
+ return (error);
+ case '\\':
+ esc++;
+ if (esc == 1)
+ continue;
+ break;
+ case '`':
+ case '\'':
+ case '"':
+ if (esc)
+ break;
+ if (qlvl == 0) {
+ qlvl++;
+ qidx = idx;
+ } else if (c == buf[qidx]) {
+ qlvl--;
+ if (qlvl > 0) {
+ do {
+ qidx--;
+ } while (buf[qidx] != '`' &&
+ buf[qidx] != '\'' &&
+ buf[qidx] != '"');
+ } else
+ qidx = -1;
+ } else {
+ qlvl++;
+ qidx = idx;
+ }
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ if (!esc && qlvl == 0) {
+ ungetc(c, fp);
+ c = '\0';
+ done = 1;
+ break;
+ }
+ if (c == '\n') {
+ /*
+ * We going to eat the newline ourselves.
+ */
+ if (qlvl > 0)
+ mtree_warning("quoted word straddles "
+ "onto next line.");
+ fi = SLIST_FIRST(&mtree_fileinfo);
+ fi->line++;
+ }
+ break;
+ case 'a':
+ if (esc)
+ c = '\a';
+ break;
+ case 'b':
+ if (esc)
+ c = '\b';
+ break;
+ case 'f':
+ if (esc)
+ c = '\f';
+ break;
+ case 'n':
+ if (esc)
+ c = '\n';
+ break;
+ case 'r':
+ if (esc)
+ c = '\r';
+ break;
+ case 't':
+ if (esc)
+ c = '\t';
+ break;
+ case 'v':
+ if (esc)
+ c = '\v';
+ break;
+ }
+ buf[idx++] = c;
+ esc = 0;
+ } while (idx < bufsz && !done);
+
+ if (idx >= bufsz) {
+ mtree_error("word too long to fit buffer (max %zu characters)",
+ bufsz);
+ skip_to(fp, " \t\n");
+ }
+ return (0);
+}
+
+static fsnode *
+create_node(const char *name, u_int type, fsnode *parent, fsnode *global)
+{
+ fsnode *n;
+
+ n = calloc(1, sizeof(*n));
+ if (n == NULL)
+ return (NULL);
+
+ n->name = strdup(name);
+ if (n->name == NULL) {
+ free(n);
+ return (NULL);
+ }
+
+ n->type = (type == 0) ? global->type : type;
+ n->parent = parent;
+
+ n->inode = calloc(1, sizeof(*n->inode));
+ if (n->inode == NULL) {
+ free(n->name);
+ free(n);
+ return (NULL);
+ }
+
+ /* Assign global options/defaults. */
+ bcopy(global->inode, n->inode, sizeof(*n->inode));
+ n->inode->st.st_mode = (n->inode->st.st_mode & ~S_IFMT) | n->type;
+
+ if (n->type == S_IFLNK)
+ n->symlink = global->symlink;
+ else if (n->type == S_IFREG)
+ n->contents = global->contents;
+
+ return (n);
+}
+
+static void
+destroy_node(fsnode *n)
+{
+
+ assert(n != NULL);
+ assert(n->name != NULL);
+ assert(n->inode != NULL);
+
+ free(n->inode);
+ free(n->name);
+ free(n);
+}
+
+static int
+read_number(const char *tok, u_int base, intmax_t *res, intmax_t min,
+ intmax_t max)
+{
+ char *end;
+ intmax_t val;
+
+ val = strtoimax(tok, &end, base);
+ if (end == tok || end[0] != '\0')
+ return (EINVAL);
+ if (val < min || val > max)
+ return (EDOM);
+ *res = val;
+ return (0);
+}
+
+static int
+read_mtree_keywords(FILE *fp, fsnode *node)
+{
+ char keyword[PATH_MAX];
+ char *name, *p, *value;
+ struct group *grent;
+ struct passwd *pwent;
+ struct stat *st, sb;
+ intmax_t num;
+ u_long flset, flclr;
+ int error, istemp, type;
+
+ st = &node->inode->st;
+ do {
+ error = skip_over(fp, " \t");
+ if (error)
+ break;
+
+ error = read_word(fp, keyword, sizeof(keyword));
+ if (error)
+ break;
+
+ if (keyword[0] == '\0')
+ break;
+
+ value = strchr(keyword, '=');
+ if (value != NULL)
+ *value++ = '\0';
+
+ /*
+ * We use EINVAL, ENOATTR, ENOSYS and ENXIO to signal
+ * certain conditions:
+ * EINVAL - Value provided for a keyword that does
+ * not take a value. The value is ignored.
+ * ENOATTR - Value missing for a keyword that needs
+ * a value. The keyword is ignored.
+ * ENOSYS - Unsupported keyword encountered. The
+ * keyword is ignored.
+ * ENXIO - Value provided for a keyword that does
+ * not take a value. The value is ignored.
+ */
+ switch (keyword[0]) {
+ case 'c':
+ if (strcmp(keyword, "contents") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ node->contents = strdup(value);
+ } else
+ error = ENOSYS;
+ break;
+ case 'f':
+ if (strcmp(keyword, "flags") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ flset = flclr = 0;
+ if (!strtofflags(&value, &flset, &flclr)) {
+ st->st_flags &= ~flclr;
+ st->st_flags |= flset;
+ } else
+ error = errno;
+ } else
+ error = ENOSYS;
+ break;
+ case 'g':
+ if (strcmp(keyword, "gid") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ error = read_number(value, 10, &num,
+ 0, UINT_MAX);
+ if (!error)
+ st->st_gid = num;
+ } else if (strcmp(keyword, "gname") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ grent = getgrnam(value);
+ if (grent != NULL)
+ st->st_gid = grent->gr_gid;
+ else
+ error = errno;
+ } else
+ error = ENOSYS;
+ break;
+ case 'l':
+ if (strcmp(keyword, "link") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ node->symlink = strdup(value);
+ } else
+ error = ENOSYS;
+ break;
+ case 'm':
+ if (strcmp(keyword, "mode") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ if (value[0] >= '0' && value[0] <= '9') {
+ error = read_number(value, 8, &num,
+ 0, 07777);
+ if (!error) {
+ st->st_mode &= S_IFMT;
+ st->st_mode |= num;
+ }
+ } else {
+ /* Symbolic mode not supported. */
+ error = EINVAL;
+ break;
+ }
+ } else
+ error = ENOSYS;
+ break;
+ case 'o':
+ if (strcmp(keyword, "optional") == 0) {
+ if (value != NULL)
+ error = ENXIO;
+ node->flags |= FSNODE_F_OPTIONAL;
+ } else
+ error = ENOSYS;
+ break;
+ case 's':
+ if (strcmp(keyword, "size") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ error = read_number(value, 10, &num,
+ 0, INTMAX_MAX);
+ if (!error)
+ st->st_size = num;
+ } else
+ error = ENOSYS;
+ break;
+ case 't':
+ if (strcmp(keyword, "time") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ p = strchr(value, '.');
+ if (p != NULL)
+ *p++ = '\0';
+ error = read_number(value, 10, &num, 0,
+ INTMAX_MAX);
+ if (error)
+ break;
+ st->st_atime = num;
+ st->st_ctime = num;
+ st->st_mtime = num;
+ error = read_number(p, 10, &num, 0,
+ INTMAX_MAX);
+ if (error)
+ break;
+ if (num != 0)
+ error = EINVAL;
+ } else if (strcmp(keyword, "type") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ if (strcmp(value, "dir") == 0)
+ node->type = S_IFDIR;
+ else if (strcmp(value, "file") == 0)
+ node->type = S_IFREG;
+ else if (strcmp(value, "link") == 0)
+ node->type = S_IFLNK;
+ else
+ error = EINVAL;
+ } else
+ error = ENOSYS;
+ break;
+ case 'u':
+ if (strcmp(keyword, "uid") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ error = read_number(value, 10, &num,
+ 0, UINT_MAX);
+ if (!error)
+ st->st_uid = num;
+ } else if (strcmp(keyword, "uname") == 0) {
+ if (value == NULL) {
+ error = ENOATTR;
+ break;
+ }
+ pwent = getpwnam(value);
+ if (pwent != NULL)
+ st->st_uid = pwent->pw_uid;
+ else
+ error = errno;
+ } else
+ error = ENOSYS;
+ break;
+ default:
+ error = ENOSYS;
+ break;
+ }
+
+ switch (error) {
+ case EINVAL:
+ mtree_error("%s: invalid value '%s'", keyword, value);
+ break;
+ case ENOATTR:
+ mtree_error("%s: keyword needs a value", keyword);
+ break;
+ case ENOSYS:
+ mtree_warning("%s: unsupported keyword", keyword);
+ break;
+ case ENXIO:
+ mtree_error("%s: keyword does not take a value",
+ keyword);
+ break;
+ }
+ } while (1);
+
+ if (error)
+ return (error);
+
+ st->st_mode = (st->st_mode & ~S_IFMT) | node->type;
+
+ /* Nothing more to do for the global defaults. */
+ if (node->name == NULL)
+ return (0);
+
+ /*
+ * Be intelligent about the file type.
+ */
+ if (node->contents != NULL) {
+ if (node->symlink != NULL) {
+ mtree_error("%s: both link and contents keywords "
+ "defined", node->name);
+ return (0);
+ }
+ type = S_IFREG;
+ } else
+ type = (node->symlink != NULL) ? S_IFLNK : S_IFDIR;
+
+ if (node->type == 0)
+ node->type = type;
+
+ if (node->type != type) {
+ mtree_error("%s: file type and defined keywords to not match",
+ node->name);
+ return (0);
+ }
+
+ st->st_mode = (st->st_mode & ~S_IFMT) | node->type;
+
+ if (node->contents == NULL)
+ return (0);
+
+ name = mtree_resolve(node->contents, &istemp);
+ if (name == NULL)
+ return (errno);
+
+ if (stat(name, &sb) != 0) {
+ mtree_error("%s: contents file '%s' not found", node->name,
+ name);
+ free(name);
+ return (0);
+ }
+
+ free(node->contents);
+ node->contents = name;
+ st->st_size = sb.st_size;
+ return (0);
+}
+
+static int
+read_mtree_command(FILE *fp)
+{
+ char cmd[10];
+ int error;
+
+ error = read_word(fp, cmd, sizeof(cmd));
+ if (error)
+ goto out;
+
+ error = read_mtree_keywords(fp, &mtree_global);
+
+ out:
+ skip_to(fp, "\n");
+ (void)getc(fp);
+ return (error);
+}
+
+static int
+read_mtree_spec1(FILE *fp, bool def, const char *name)
+{
+ fsnode *last, *node, *parent;
+ u_int type;
+ int error;
+
+ assert(name[0] != '\0');
+
+ /*
+ * Treat '..' specially, because it only changes our current
+ * directory. We don't create a node for it. We simply ignore
+ * any keywords that may appear on the line as well.
+ * Going up a directory is a little non-obvious. A directory
+ * node has a corresponding '.' child. The parent of '.' is
+ * not the '.' node of the parent directory, but the directory
+ * node within the parent to which the child relates. However,
+ * going up a directory means we need to find the '.' node to
+ * which the directoy node is linked. This we can do via the
+ * first * pointer, because '.' is always the first entry in a
+ * directory.
+ */
+ if (IS_DOTDOT(name)) {
+ /* This deals with NULL pointers as well. */
+ if (mtree_current == mtree_root) {
+ mtree_warning("ignoring .. in root directory");
+ return (0);
+ }
+
+ node = mtree_current;
+
+ assert(node != NULL);
+ assert(IS_DOT(node->name));
+ assert(node->first == node);
+
+ /* Get the corresponding directory node in the parent. */
+ node = mtree_current->parent;
+
+ assert(node != NULL);
+ assert(!IS_DOT(node->name));
+
+ node = node->first;
+
+ assert(node != NULL);
+ assert(IS_DOT(node->name));
+ assert(node->first == node);
+
+ mtree_current = node;
+ return (0);
+ }
+
+ /*
+ * If we don't have a current directory and the first specification
+ * (either implicit or defined) is not '.', then we need to create
+ * a '.' node first (using a recursive call).
+ */
+ if (!IS_DOT(name) && mtree_current == NULL) {
+ error = read_mtree_spec1(fp, false, ".");
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Lookup the name in the current directory (if we have a current
+ * directory) to make sure we do not create multiple nodes for the
+ * same component. For non-definitions, if we find a node with the
+ * same name, simply change the current directory. For definitions
+ * more happens.
+ */
+ last = NULL;
+ node = mtree_current;
+ while (node != NULL) {
+ assert(node->first == mtree_current);
+
+ if (strcmp(name, node->name) == 0) {
+ if (def == true) {
+ mtree_error("duplicate definition of %s",
+ name);
+ return (0);
+ }
+
+ if (node->type != S_IFDIR) {
+ mtree_error("%s is not a directory", name);
+ return (0);
+ }
+
+ assert(!IS_DOT(name));
+
+ node = node->child;
+
+ assert(node != NULL);
+ assert(IS_DOT(node->name));
+
+ mtree_current = node;
+ return (0);
+ }
+
+ last = node;
+ node = last->next;
+ }
+
+ parent = (mtree_current != NULL) ? mtree_current->parent : NULL;
+ type = (def == false || IS_DOT(name)) ? S_IFDIR : 0;
+ node = create_node(name, type, parent, &mtree_global);
+ if (node == NULL)
+ return (ENOMEM);
+
+ if (def == true) {
+ error = read_mtree_keywords(fp, node);
+ if (error) {
+ destroy_node(node);
+ return (error);
+ }
+ }
+
+ node->first = (mtree_current != NULL) ? mtree_current : node;
+
+ if (last != NULL)
+ last->next = node;
+
+ if (node->type != S_IFDIR)
+ return (0);
+
+ if (!IS_DOT(node->name)) {
+ parent = node;
+ node = create_node(".", S_IFDIR, parent, parent);
+ if (node == NULL) {
+ last->next = NULL;
+ destroy_node(parent);
+ return (ENOMEM);
+ }
+ parent->child = node;
+ node->first = node;
+ }
+
+ assert(node != NULL);
+ assert(IS_DOT(node->name));
+ assert(node->first == node);
+
+ mtree_current = node;
+ if (mtree_root == NULL)
+ mtree_root = node;
+
+ return (0);
+}
+
+static int
+read_mtree_spec(FILE *fp)
+{
+ char pathspec[PATH_MAX];
+ char *cp;
+ int error;
+
+ error = read_word(fp, pathspec, sizeof(pathspec));
+ if (error)
+ goto out;
+
+ cp = strchr(pathspec, '/');
+ if (cp != NULL) {
+ /* Absolute pathname */
+ mtree_current = mtree_root;
+
+ do {
+ *cp++ = '\0';
+
+ /* Disallow '.' and '..' as components. */
+ if (IS_DOT(pathspec) || IS_DOTDOT(pathspec)) {
+ mtree_error("absolute path cannot contain . "
+ "or .. components");
+ goto out;
+ }
+
+ /* Ignore multiple adjacent slashes. */
+ if (pathspec[0] != '\0')
+ error = read_mtree_spec1(fp, false, pathspec);
+ memmove(pathspec, cp, strlen(cp) + 1);
+ cp = strchr(pathspec, '/');
+ } while (!error && cp != NULL);
+
+ /* Disallow '.' and '..' as the last component. */
+ if (!error && (IS_DOT(pathspec) || IS_DOTDOT(pathspec))) {
+ mtree_error("absolute path cannot contain . or .. "
+ "components");
+ goto out;
+ }
+ }
+
+ /* Ignore absolute specfications that end with a slash. */
+ if (!error && pathspec[0] != '\0')
+ error = read_mtree_spec1(fp, true, pathspec);
+
+ out:
+ skip_to(fp, "\n");
+ (void)getc(fp);
+ return (error);
+}
+
+fsnode *
+read_mtree(const char *fname, fsnode *node)
+{
+ struct mtree_fileinfo *fi;
+ FILE *fp;
+ int c, error;
+
+ /* We do not yet support nesting... */
+ assert(node == NULL);
+
+ if (strcmp(fname, "-") == 0)
+ fp = stdin;
+ else {
+ fp = fopen(fname, "r");
+ if (fp == NULL)
+ err(1, "Can't open `%s'", fname);
+ }
+
+ error = mtree_file_push(fname, fp);
+ if (error)
+ goto out;
+
+ bzero(&mtree_global, sizeof(mtree_global));
+ bzero(&mtree_global_inode, sizeof(mtree_global_inode));
+ mtree_global.inode = &mtree_global_inode;
+ mtree_global_inode.nlink = 1;
+ mtree_global_inode.st.st_atime = mtree_global_inode.st.st_ctime =
+ mtree_global_inode.st.st_mtime = time(NULL);
+ errors = warnings = 0;
+
+ setgroupent(1);
+ setpassent(1);
+
+ mtree_root = node;
+ mtree_current = node;
+ do {
+ /* Start of a new line... */
+ fi = SLIST_FIRST(&mtree_fileinfo);
+ fi->line++;
+
+ error = skip_over(fp, " \t");
+ if (error)
+ break;
+
+ c = getc(fp);
+ if (c == EOF) {
+ error = ferror(fp) ? errno : -1;
+ break;
+ }
+
+ switch (c) {
+ case '\n': /* empty line */
+ error = 0;
+ break;
+ case '#': /* comment -- skip to end of line. */
+ error = skip_to(fp, "\n");
+ if (!error)
+ (void)getc(fp);
+ break;
+ case '/': /* special commands */
+ error = read_mtree_command(fp);
+ break;
+ default: /* specification */
+ ungetc(c, fp);
+ error = read_mtree_spec(fp);
+ break;
+ }
+ } while (!error);
+
+ endpwent();
+ endgrent();
+
+ if (error <= 0 && (errors || warnings)) {
+ warnx("%u error(s) and %u warning(s) in mtree manifest",
+ errors, warnings);
+ if (errors)
+ exit(1);
+ }
+
+ out:
+ if (error > 0)
+ errc(1, error, "Error reading mtree file");
+
+ if (fp != stdin)
+ fclose(fp);
+
+ if (mtree_root != NULL)
+ return (mtree_root);
+
+ /* Handle empty specifications. */
+ node = create_node(".", S_IFDIR, NULL, &mtree_global);
+ node->first = node;
+ return (node);
+}
diff --git a/usr.sbin/mfiutil/mfi_config.c b/usr.sbin/mfiutil/mfi_config.c
index fdda117..f6f1a9d 100644
--- a/usr.sbin/mfiutil/mfi_config.c
+++ b/usr.sbin/mfiutil/mfi_config.c
@@ -85,6 +85,7 @@ mfi_config_read(int fd, struct mfi_config_data **configp)
{
struct mfi_config_data *config;
uint32_t config_size;
+ int error;
/*
* Keep fetching the config in a loop until we have a large enough
@@ -97,8 +98,12 @@ fetch:
if (config == NULL)
return (-1);
if (mfi_dcmd_command(fd, MFI_DCMD_CFG_READ, config,
- config_size, NULL, 0, NULL) < 0)
+ config_size, NULL, 0, NULL) < 0) {
+ error = errno;
+ free(config);
+ errno = error;
return (-1);
+ }
if (config->size > config_size) {
config_size = config->size;
@@ -162,12 +167,14 @@ clear_config(int ac, char **av)
if (!mfi_reconfig_supported()) {
warnx("The current mfi(4) driver does not support "
"configuration changes.");
+ close(fd);
return (EOPNOTSUPP);
}
if (mfi_ld_get_list(fd, &list, NULL) < 0) {
error = errno;
warn("Failed to get volume list");
+ close(fd);
return (error);
}
@@ -175,6 +182,7 @@ clear_config(int ac, char **av)
if (mfi_volume_busy(fd, list.ld_list[i].ld.v.target_id)) {
warnx("Volume %s is busy and cannot be deleted",
mfi_volume_name(fd, list.ld_list[i].ld.v.target_id));
+ close(fd);
return (EBUSY);
}
}
@@ -185,12 +193,14 @@ clear_config(int ac, char **av)
ch = getchar();
if (ch != 'y' && ch != 'Y') {
printf("\nAborting\n");
+ close(fd);
return (0);
}
if (mfi_dcmd_command(fd, MFI_DCMD_CFG_CLEAR, NULL, 0, NULL, 0, NULL) < 0) {
error = errno;
warn("Failed to clear configuration");
+ close(fd);
return (error);
}
@@ -336,17 +346,21 @@ parse_array(int fd, int raid_type, char *array_str, struct array_info *info)
for (pinfo = info->drives; (cp = strsep(&array_str, ",")) != NULL;
pinfo++) {
error = mfi_lookup_drive(fd, cp, &device_id);
- if (error)
+ if (error) {
+ free(info->drives);
return (error);
+ }
if (mfi_pd_get_info(fd, device_id, pinfo, NULL) < 0) {
error = errno;
warn("Failed to fetch drive info for drive %s", cp);
+ free(info->drives);
return (error);
}
if (pinfo->fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
warnx("Drive %u is not available", device_id);
+ free(info->drives);
return (EINVAL);
}
}
@@ -405,8 +419,10 @@ build_array(int fd, char *arrayp, struct array_info *array_info,
ar->array_ref = find_next_array(state);
for (i = 0; i < array_info->drive_count; i++) {
if (verbose)
- printf("Adding drive %u to array %u\n",
+ printf("Adding drive %s to array %u\n",
+ mfi_drive_name(NULL,
array_info->drives[i].ref.v.device_id,
+ MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS),
ar->array_ref);
if (ar->size > array_info->drives[i].coerced_size)
ar->size = array_info->drives[i].coerced_size;
@@ -551,7 +567,12 @@ create_volume(int ac, char **av)
return (EINVAL);
}
-
+ bzero(&state, sizeof(state));
+ config = NULL;
+ arrays = NULL;
+ narrays = 0;
+ error = 0;
+
fd = mfi_open(mfi_unit);
if (fd < 0) {
error = errno;
@@ -562,7 +583,8 @@ create_volume(int ac, char **av)
if (!mfi_reconfig_supported()) {
warnx("The current mfi(4) driver does not support "
"configuration changes.");
- return (EOPNOTSUPP);
+ error = EOPNOTSUPP;
+ goto error;
}
/* Lookup the RAID type first. */
@@ -575,7 +597,8 @@ create_volume(int ac, char **av)
if (raid_type == -1) {
warnx("Unknown or unsupported volume type %s", av[1]);
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
/* Parse any options. */
@@ -603,7 +626,8 @@ create_volume(int ac, char **av)
break;
case '?':
default:
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
}
ac -= optind;
@@ -613,7 +637,8 @@ create_volume(int ac, char **av)
narrays = ac;
if (narrays == 0) {
warnx("At least one drive list is required");
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
switch (raid_type) {
case RT_RAID0:
@@ -623,7 +648,8 @@ create_volume(int ac, char **av)
case RT_CONCAT:
if (narrays != 1) {
warnx("Only one drive list can be specified");
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
break;
case RT_RAID10:
@@ -632,24 +658,27 @@ create_volume(int ac, char **av)
if (narrays < 1) {
warnx("RAID10, RAID50, and RAID60 require at least "
"two drive lists");
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
if (narrays > MFI_MAX_SPAN_DEPTH) {
warnx("Volume spans more than %d arrays",
MFI_MAX_SPAN_DEPTH);
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
break;
}
arrays = calloc(narrays, sizeof(*arrays));
if (arrays == NULL) {
warnx("malloc failed");
- return (ENOMEM);
+ error = ENOMEM;
+ goto error;
}
for (i = 0; i < narrays; i++) {
error = parse_array(fd, raid_type, av[i], &arrays[i]);
if (error)
- return (error);
+ goto error;
}
switch (raid_type) {
@@ -660,7 +689,8 @@ create_volume(int ac, char **av)
if (arrays[i].drive_count != arrays[0].drive_count) {
warnx("All arrays must contain the same "
"number of drives");
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
}
break;
@@ -673,7 +703,7 @@ create_volume(int ac, char **av)
if (mfi_config_read(fd, &config) < 0) {
error = errno;
warn("Failed to read configuration");
- return (error);
+ goto error;
}
p = (char *)config->array;
state.array_ref = 0xffff;
@@ -683,7 +713,8 @@ create_volume(int ac, char **av)
state.arrays = calloc(config->array_count, sizeof(int));
if (state.arrays == NULL) {
warnx("malloc failed");
- return (ENOMEM);
+ error = ENOMEM;
+ goto error;
}
for (i = 0; i < config->array_count; i++) {
ar = (struct mfi_array *)p;
@@ -699,7 +730,8 @@ create_volume(int ac, char **av)
state.volumes = calloc(config->log_drv_count, sizeof(int));
if (state.volumes == NULL) {
warnx("malloc failed");
- return (ENOMEM);
+ error = ENOMEM;
+ goto error;
}
for (i = 0; i < config->log_drv_count; i++) {
ld = (struct mfi_ld_config *)p;
@@ -739,7 +771,8 @@ create_volume(int ac, char **av)
config = calloc(1, config_size);
if (config == NULL) {
warnx("malloc failed");
- return (ENOMEM);
+ error = ENOMEM;
+ goto error;
}
config->size = config_size;
config->array_count = narrays;
@@ -776,21 +809,20 @@ create_volume(int ac, char **av)
NULL, 0, NULL) < 0) {
error = errno;
warn("Failed to add volume");
- return (error);
+ /* FALLTHROUGH */
}
+error:
/* Clean up. */
free(config);
- if (state.log_drv_count > 0)
- free(state.volumes);
- if (state.array_count > 0)
- free(state.arrays);
+ free(state.volumes);
+ free(state.arrays);
for (i = 0; i < narrays; i++)
free(arrays[i].drives);
free(arrays);
close(fd);
- return (0);
+ return (error);
}
MFI_COMMAND(top, create, create_volume);
@@ -831,24 +863,28 @@ delete_volume(int ac, char **av)
if (!mfi_reconfig_supported()) {
warnx("The current mfi(4) driver does not support "
"configuration changes.");
+ close(fd);
return (EOPNOTSUPP);
}
if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
error = errno;
warn("Invalid volume %s", av[1]);
+ close(fd);
return (error);
}
if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
error = errno;
warn("Failed to get info for volume %d", target_id);
+ close(fd);
return (error);
}
if (mfi_volume_busy(fd, target_id)) {
warnx("Volume %s is busy and cannot be deleted",
mfi_volume_name(fd, target_id));
+ close(fd);
return (EBUSY);
}
@@ -857,6 +893,7 @@ delete_volume(int ac, char **av)
sizeof(mbox), NULL) < 0) {
error = errno;
warn("Failed to delete volume");
+ close(fd);
return (error);
}
@@ -891,40 +928,44 @@ add_spare(int ac, char **av)
return (error);
}
+ config = NULL;
+ spare = NULL;
error = mfi_lookup_drive(fd, av[1], &device_id);
if (error)
- return (error);
+ goto error;
if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
error = errno;
warn("Failed to fetch drive info");
- return (error);
+ goto error;
}
if (info.fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
warnx("Drive %u is not available", device_id);
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
if (ac > 2) {
if (mfi_lookup_volume(fd, av[2], &target_id) < 0) {
error = errno;
warn("Invalid volume %s", av[2]);
- return (error);
+ goto error;
}
}
if (mfi_config_read(fd, &config) < 0) {
error = errno;
warn("Failed to read configuration");
- return (error);
+ goto error;
}
spare = malloc(sizeof(struct mfi_spare) + sizeof(uint16_t) *
config->array_count);
if (spare == NULL) {
warnx("malloc failed");
- return (ENOMEM);
+ error = ENOMEM;
+ goto error;
}
bzero(spare, sizeof(struct mfi_spare));
spare->ref = info.ref;
@@ -937,7 +978,8 @@ add_spare(int ac, char **av)
if (ar->size > info.coerced_size) {
warnx("Spare isn't large enough for array %u",
ar->array_ref);
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
p += config->array_size;
}
@@ -950,7 +992,8 @@ add_spare(int ac, char **av)
ld = mfi_config_lookup_volume(config, target_id);
if (ld == NULL) {
warnx("Did not find volume %d", target_id);
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
spare->spare_type |= MFI_SPARE_DEDICATED;
@@ -960,29 +1003,33 @@ add_spare(int ac, char **av)
ld->span[i].array_ref);
if (ar == NULL) {
warnx("Missing array; inconsistent config?");
- return (ENXIO);
+ error = ENXIO;
+ goto error;
}
if (ar->size > info.coerced_size) {
warnx("Spare isn't large enough for array %u",
ar->array_ref);
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
spare->array_ref[i] = ar->array_ref;
}
}
- free(config);
if (mfi_dcmd_command(fd, MFI_DCMD_CFG_MAKE_SPARE, spare,
sizeof(struct mfi_spare) + sizeof(uint16_t) * spare->array_count,
NULL, 0, NULL) < 0) {
error = errno;
warn("Failed to assign spare");
- return (error);
+ /* FALLTHROUGH. */
}
+error:
+ free(spare);
+ free(config);
close(fd);
- return (0);
+ return (error);
}
MFI_COMMAND(top, add, add_spare);
@@ -1007,18 +1054,22 @@ remove_spare(int ac, char **av)
}
error = mfi_lookup_drive(fd, av[1], &device_id);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
/* Get the info for this drive. */
if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
error = errno;
warn("Failed to fetch info for drive %u", device_id);
+ close(fd);
return (error);
}
if (info.fw_state != MFI_PD_STATE_HOT_SPARE) {
warnx("Drive %u is not a hot spare", device_id);
+ close(fd);
return (EINVAL);
}
@@ -1027,6 +1078,7 @@ remove_spare(int ac, char **av)
sizeof(mbox), NULL) < 0) {
error = errno;
warn("Failed to delete spare");
+ close(fd);
return (error);
}
@@ -1151,6 +1203,7 @@ debug_config(int ac, char **av)
if (mfi_config_read(fd, &config) < 0) {
error = errno;
warn("Failed to get config");
+ close(fd);
return (error);
}
@@ -1190,17 +1243,21 @@ dump(int ac, char **av)
warn("Failed to read debug command");
if (error == ENOENT)
error = EOPNOTSUPP;
+ close(fd);
return (error);
}
config = malloc(len);
if (config == NULL) {
warnx("malloc failed");
+ close(fd);
return (ENOMEM);
}
if (sysctlbyname(buf, config, &len, NULL, 0) < 0) {
error = errno;
warn("Failed to read debug command");
+ free(config);
+ close(fd);
return (error);
}
dump_config(fd, config);
diff --git a/usr.sbin/mfiutil/mfi_drive.c b/usr.sbin/mfiutil/mfi_drive.c
index 75c4a53..6341fd8 100644
--- a/usr.sbin/mfiutil/mfi_drive.c
+++ b/usr.sbin/mfiutil/mfi_drive.c
@@ -45,6 +45,87 @@
MFI_TABLE(top, drive);
+/*
+ * Print the name of a drive either by drive number as %2u or by enclosure:slot
+ * as Exx:Sxx (or both). Use default unless command line options override it
+ * and the command allows this (which we usually do unless we already print
+ * both). We prefer pinfo if given, otherwise try to look it up by device_id.
+ */
+const char *
+mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t device_id, uint32_t def)
+{
+ struct mfi_pd_info info;
+ static char buf[16];
+ char *p;
+ int error, fd, len;
+
+ if ((def & MFI_DNAME_HONOR_OPTS) != 0 &&
+ (mfi_opts & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) != 0)
+ def = mfi_opts & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID);
+
+ buf[0] = '\0';
+ if (pinfo == NULL && def & MFI_DNAME_ES) {
+ /* Fallback in case of error, just ignore flags. */
+ if (device_id == 0xffff)
+ snprintf(buf, sizeof(buf), "MISSING");
+ else
+ snprintf(buf, sizeof(buf), "%2u", device_id);
+
+ fd = mfi_open(mfi_unit);
+ if (fd < 0) {
+ warn("mfi_open");
+ return (buf);
+ }
+
+ /* Get the info for this drive. */
+ if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
+ warn("Failed to fetch info for drive %2u", device_id);
+ close(fd);
+ return (buf);
+ }
+
+ close(fd);
+ pinfo = &info;
+ }
+
+ p = buf;
+ len = sizeof(buf);
+ if (def & MFI_DNAME_DEVICE_ID) {
+ if (device_id == 0xffff)
+ error = snprintf(p, len, "MISSING");
+ else
+ error = snprintf(p, len, "%2u", device_id);
+ if (error >= 0) {
+ p += error;
+ len -= error;
+ }
+ }
+ if ((def & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) ==
+ (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID) && len >= 2) {
+ *p++ = ' ';
+ len--;
+ *p = '\0';
+ len--;
+ }
+ if (def & MFI_DNAME_ES) {
+ if (pinfo->encl_device_id == 0xffff)
+ error = snprintf(p, len, "S%u",
+ pinfo->slot_number);
+ else if (pinfo->encl_device_id == pinfo->ref.v.device_id)
+ error = snprintf(p, len, "E%u",
+ pinfo->encl_index);
+ else
+ error = snprintf(p, len, "E%u:S%u",
+ pinfo->encl_index, pinfo->slot_number);
+ if (error >= 0) {
+ p += error;
+ len -= error;
+ }
+ }
+
+ return (buf);
+}
+
const char *
mfi_pdstate(enum mfi_pd_state state)
{
@@ -310,19 +391,23 @@ drive_set_state(char *drive, uint16_t new_state)
}
error = mfi_lookup_drive(fd, drive, &device_id);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
/* Get the info for this drive. */
if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
error = errno;
warn("Failed to fetch info for drive %u", device_id);
+ close(fd);
return (error);
}
/* Try to change the state. */
if (info.fw_state == new_state) {
warnx("Drive %u is already in the desired state", device_id);
+ close(fd);
return (EINVAL);
}
@@ -334,6 +419,7 @@ drive_set_state(char *drive, uint16_t new_state)
error = errno;
warn("Failed to set drive %u to %s", device_id,
mfi_pdstate(new_state));
+ close(fd);
return (error);
}
@@ -406,19 +492,23 @@ start_rebuild(int ac, char **av)
}
error = mfi_lookup_drive(fd, av[1], &device_id);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
/* Get the info for this drive. */
if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
error = errno;
warn("Failed to fetch info for drive %u", device_id);
+ close(fd);
return (error);
}
/* Check the state, must be REBUILD. */
if (info.fw_state != MFI_PD_STATE_REBUILD) {
warnx("Drive %d is not in the REBUILD state", device_id);
+ close(fd);
return (EINVAL);
}
@@ -428,6 +518,7 @@ start_rebuild(int ac, char **av)
NULL) < 0) {
error = errno;
warn("Failed to start rebuild on drive %u", device_id);
+ close(fd);
return (error);
}
close(fd);
@@ -458,19 +549,23 @@ abort_rebuild(int ac, char **av)
}
error = mfi_lookup_drive(fd, av[1], &device_id);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
/* Get the info for this drive. */
if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
error = errno;
warn("Failed to fetch info for drive %u", device_id);
+ close(fd);
return (error);
}
/* Check the state, must be REBUILD. */
if (info.fw_state != MFI_PD_STATE_REBUILD) {
warn("Drive %d is not in the REBUILD state", device_id);
+ close(fd);
return (EINVAL);
}
@@ -480,6 +575,7 @@ abort_rebuild(int ac, char **av)
NULL) < 0) {
error = errno;
warn("Failed to abort rebuild on drive %u", device_id);
+ close(fd);
return (error);
}
close(fd);
@@ -509,13 +605,16 @@ drive_progress(int ac, char **av)
}
error = mfi_lookup_drive(fd, av[1], &device_id);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
/* Get the info for this drive. */
if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
error = errno;
warn("Failed to fetch info for drive %u", device_id);
+ close(fd);
return (error);
}
close(fd);
@@ -529,7 +628,9 @@ drive_progress(int ac, char **av)
mfi_display_progress("Clear", &info.prog_info.clear);
if ((info.prog_info.active & (MFI_PD_PROGRESS_REBUILD |
MFI_PD_PROGRESS_PATROL | MFI_PD_PROGRESS_CLEAR)) == 0)
- printf("No activity in progress for drive %u.\n", device_id);
+ printf("No activity in progress for drive %s.\n",
+ mfi_drive_name(NULL, device_id,
+ MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
return (0);
}
@@ -570,13 +671,16 @@ drive_clear(int ac, char **av)
}
error = mfi_lookup_drive(fd, av[1], &device_id);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
/* Get the info for this drive. */
if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
error = errno;
warn("Failed to fetch info for drive %u", device_id);
+ close(fd);
return (error);
}
@@ -586,6 +690,7 @@ drive_clear(int ac, char **av)
warn("Failed to %s clear on drive %u",
opcode == MFI_DCMD_PD_CLEAR_START ? "start" : "stop",
device_id);
+ close(fd);
return (error);
}
@@ -626,8 +731,10 @@ drive_locate(int ac, char **av)
}
error = mfi_lookup_drive(fd, av[1], &device_id);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
mbox_store_device_id(&mbox[0], device_id);
@@ -638,6 +745,7 @@ drive_locate(int ac, char **av)
warn("Failed to %s locate on drive %u",
opcode == MFI_DCMD_PD_LOCATE_START ? "start" : "stop",
device_id);
+ close(fd);
return (error);
}
close(fd);
diff --git a/usr.sbin/mfiutil/mfi_evt.c b/usr.sbin/mfiutil/mfi_evt.c
index b9288d8..336fbd3 100644
--- a/usr.sbin/mfiutil/mfi_evt.c
+++ b/usr.sbin/mfiutil/mfi_evt.c
@@ -83,6 +83,7 @@ show_logstate(int ac, char **av)
if (mfi_event_get_info(fd, &info, NULL) < 0) {
error = errno;
warn("Failed to get event log info");
+ close(fd);
return (error);
}
@@ -362,8 +363,8 @@ mfi_decode_evt(int fd, struct mfi_evt_detail *detail, int verbose)
{
printf("%5d (%s/%s/%s) - ", detail->seq, format_timestamp(detail->time),
- format_locale(detail->class.members.locale),
- format_class(detail->class.members.class));
+ format_locale(detail->evt_class.members.locale),
+ format_class(detail->evt_class.members.evt_class));
switch (detail->arg_type) {
case MR_EVT_ARGS_NONE:
break;
@@ -550,6 +551,7 @@ show_events(int ac, char **av)
if (mfi_event_get_info(fd, &info, NULL) < 0) {
error = errno;
warn("Failed to get event log info");
+ close(fd);
return (error);
}
@@ -557,7 +559,7 @@ show_events(int ac, char **av)
num_events = 15;
filter.members.reserved = 0;
filter.members.locale = MFI_EVT_LOCALE_ALL;
- filter.members.class = MFI_EVT_CLASS_WARNING;
+ filter.members.evt_class = MFI_EVT_CLASS_WARNING;
start = info.boot_seq_num;
stop = info.newest_seq_num;
verbose = 0;
@@ -567,9 +569,10 @@ show_events(int ac, char **av)
while ((ch = getopt(ac, av, "c:l:n:v")) != -1) {
switch (ch) {
case 'c':
- if (parse_class(optarg, &filter.members.class) < 0) {
+ if (parse_class(optarg, &filter.members.evt_class) < 0) {
error = errno;
warn("Error parsing event class");
+ close(fd);
return (error);
}
break;
@@ -577,6 +580,7 @@ show_events(int ac, char **av)
if (parse_locale(optarg, &filter.members.locale) < 0) {
error = errno;
warn("Error parsing event locale");
+ close(fd);
return (error);
}
break;
@@ -584,6 +588,7 @@ show_events(int ac, char **av)
val = strtol(optarg, &cp, 0);
if (*cp != '\0' || val <= 0) {
warnx("Invalid event count");
+ close(fd);
return (EINVAL);
}
num_events = val;
@@ -593,6 +598,7 @@ show_events(int ac, char **av)
break;
case '?':
default:
+ close(fd);
return (EINVAL);
}
}
@@ -604,28 +610,33 @@ show_events(int ac, char **av)
(num_events - 1);
if (size > getpagesize()) {
warnx("Event count is too high");
+ close(fd);
return (EINVAL);
}
/* Handle optional start and stop sequence numbers. */
if (ac > 2) {
warnx("show events: extra arguments");
+ close(fd);
return (EINVAL);
}
if (ac > 0 && parse_seq(&info, av[0], &start) < 0) {
error = errno;
warn("Error parsing starting sequence number");
+ close(fd);
return (error);
}
if (ac > 1 && parse_seq(&info, av[1], &stop) < 0) {
error = errno;
warn("Error parsing ending sequence number");
+ close(fd);
return (error);
}
list = malloc(size);
if (list == NULL) {
warnx("malloc failed");
+ close(fd);
return (ENOMEM);
}
for (seq = start;;) {
@@ -633,6 +644,8 @@ show_events(int ac, char **av)
&status) < 0) {
error = errno;
warn("Failed to fetch events");
+ free(list);
+ close(fd);
return (error);
}
if (status == MFI_STAT_NOT_FOUND) {
@@ -642,6 +655,8 @@ show_events(int ac, char **av)
}
if (status != MFI_STAT_OK) {
warnx("Error fetching events: %s", mfi_status(status));
+ free(list);
+ close(fd);
return (EIO);
}
diff --git a/usr.sbin/mfiutil/mfi_flash.c b/usr.sbin/mfiutil/mfi_flash.c
index 4039beb..6d07cb0 100644
--- a/usr.sbin/mfiutil/mfi_flash.c
+++ b/usr.sbin/mfiutil/mfi_flash.c
@@ -136,21 +136,25 @@ flash_adapter(int ac, char **av)
return (error);
}
+ buf = NULL;
+ fd = -1;
+
if (fstat(flash, &sb) < 0) {
error = errno;
warn("fstat(%s)", av[1]);
- return (error);
+ goto error;
}
if (sb.st_size % 1024 != 0 || sb.st_size > 0x7fffffff) {
warnx("Invalid flash file size");
- return (EINVAL);
+ error = EINVAL;
+ goto error;
}
fd = mfi_open(mfi_unit);
if (fd < 0) {
error = errno;
warn("mfi_open");
- return (error);
+ goto error;
}
/* First, ask the firmware to allocate space for the flash file. */
@@ -158,14 +162,16 @@ flash_adapter(int ac, char **av)
mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_OPEN, NULL, 0, mbox, 4, &status);
if (status != MFI_STAT_OK) {
warnx("Failed to alloc flash memory: %s", mfi_status(status));
- return (EIO);
+ error = EIO;
+ goto error;
}
/* Upload the file 64k at a time. */
buf = malloc(FLASH_BUF_SIZE);
if (buf == NULL) {
warnx("malloc failed");
- return (ENOMEM);
+ error = ENOMEM;
+ goto error;
}
offset = 0;
while (sb.st_size > 0) {
@@ -174,7 +180,8 @@ flash_adapter(int ac, char **av)
warnx("Bad read from flash file");
mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
NULL, 0, NULL);
- return (ENXIO);
+ error = ENXIO;
+ goto error;
}
mbox_store_word(mbox, offset);
@@ -184,12 +191,12 @@ flash_adapter(int ac, char **av)
warnx("Flash download failed: %s", mfi_status(status));
mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
NULL, 0, NULL);
- return (ENXIO);
+ error = ENXIO;
+ goto error;
}
sb.st_size -= nread;
offset += nread;
}
- close(flash);
/* Kick off the flash. */
printf("WARNING: Firmware flash in progress, do not reboot machine... ");
@@ -198,12 +205,17 @@ flash_adapter(int ac, char **av)
NULL, 0, &status);
if (status != MFI_STAT_OK) {
printf("failed:\n\t%s\n", mfi_status(status));
- return (ENXIO);
+ error = ENXIO;
+ goto error;
}
printf("finished\n");
error = display_pending_firmware(fd);
- close(fd);
+error:
+ free(buf);
+ if (fd >= 0)
+ close(fd);
+ close(flash);
return (error);
}
diff --git a/usr.sbin/mfiutil/mfi_patrol.c b/usr.sbin/mfiutil/mfi_patrol.c
index da7ddb5..dd348ad 100644
--- a/usr.sbin/mfiutil/mfi_patrol.c
+++ b/usr.sbin/mfiutil/mfi_patrol.c
@@ -80,7 +80,7 @@ show_patrol(int ac, char **av)
struct mfi_pr_status status;
struct mfi_pd_list *list;
struct mfi_pd_info info;
- char label[16];
+ char label[24];
time_t now;
uint32_t at;
int error, fd;
@@ -96,8 +96,10 @@ show_patrol(int ac, char **av)
time(&now);
mfi_get_time(fd, &at);
error = patrol_get_props(fd, &prop);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
printf("Operation Mode: ");
switch (prop.op_mode) {
case MFI_PR_OPMODE_AUTO:
@@ -128,6 +130,7 @@ show_patrol(int ac, char **av)
sizeof(status), NULL, 0, NULL) < 0) {
error = errno;
warn("Failed to get patrol read properties");
+ close(fd);
return (error);
}
printf("Runs Completed: %u\n", status.num_iteration);
@@ -153,6 +156,7 @@ show_patrol(int ac, char **av)
if (mfi_pd_get_list(fd, &list, NULL) < 0) {
error = errno;
warn("Failed to get drive list");
+ close(fd);
return (error);
}
@@ -165,15 +169,20 @@ show_patrol(int ac, char **av)
error = errno;
warn("Failed to fetch info for drive %u",
list->addr[i].device_id);
+ free(list);
+ close(fd);
return (error);
}
if (info.prog_info.active & MFI_PD_PROGRESS_PATROL) {
- snprintf(label, sizeof(label), " Drive %u",
- list->addr[i].device_id);
+ snprintf(label, sizeof(label), " Drive %s",
+ mfi_drive_name(NULL,
+ list->addr[i].device_id,
+ MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
mfi_display_progress(label,
&info.prog_info.patrol);
}
}
+ free(list);
}
close(fd);
@@ -198,6 +207,7 @@ start_patrol(int ac, char **av)
0) {
error = errno;
warn("Failed to start patrol read");
+ close(fd);
return (error);
}
@@ -223,6 +233,7 @@ stop_patrol(int ac, char **av)
0) {
error = errno;
warn("Failed to stop patrol read");
+ close(fd);
return (error);
}
@@ -289,8 +300,10 @@ patrol_config(int ac, char **av)
}
error = patrol_get_props(fd, &prop);
- if (error)
+ if (error) {
+ close(fd);
return (error);
+ }
prop.op_mode = op_mode;
if (op_mode == MFI_PR_OPMODE_AUTO) {
if (ac > 2)
@@ -298,8 +311,10 @@ patrol_config(int ac, char **av)
if (ac > 3) {
time(&now);
mfi_get_time(fd, &at);
- if (at == 0)
+ if (at == 0) {
+ close(fd);
return (ENXIO);
+ }
prop.next_exec = at + next_exec;
printf("Starting next patrol read at %s",
adapter_time(now, at, prop.next_exec));
@@ -309,6 +324,7 @@ patrol_config(int ac, char **av)
sizeof(prop), NULL, 0, NULL) < 0) {
error = errno;
warn("Failed to set patrol read properties");
+ close(fd);
return (error);
}
diff --git a/usr.sbin/mfiutil/mfi_show.c b/usr.sbin/mfiutil/mfi_show.c
index 22a735d..d1f0071 100644
--- a/usr.sbin/mfiutil/mfi_show.c
+++ b/usr.sbin/mfiutil/mfi_show.c
@@ -71,6 +71,7 @@ show_adapter(int ac, char **av)
if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
error = errno;
warn("Failed to get controller info");
+ close(fd);
return (error);
}
printf("mfi%d Adapter:\n", mfi_unit);
@@ -158,10 +159,12 @@ show_battery(int ac, char **av)
sizeof(cap), NULL, 0, &status) < 0) {
if (status == MFI_STAT_NO_HW_PRESENT) {
printf("mfi%d: No battery present\n", mfi_unit);
+ close(fd);
return (0);
}
error = errno;
warn("Failed to get capacity info");
+ close(fd);
return (error);
}
@@ -169,6 +172,7 @@ show_battery(int ac, char **av)
sizeof(design), NULL, 0, NULL) < 0) {
error = errno;
warn("Failed to get design info");
+ close(fd);
return (error);
}
@@ -176,6 +180,7 @@ show_battery(int ac, char **av)
NULL, 0, NULL) < 0) {
error = errno;
warn("Failed to get status");
+ close(fd);
return (error);
}
@@ -253,7 +258,7 @@ print_ld(struct mfi_ld_info *info, int state_len)
}
static void
-print_pd(struct mfi_pd_info *info, int state_len, int location)
+print_pd(struct mfi_pd_info *info, int state_len)
{
const char *s;
char buf[6];
@@ -268,15 +273,6 @@ print_pd(struct mfi_pd_info *info, int state_len, int location)
s = mfi_pd_inq_string(info);
if (s != NULL)
printf(" %s", s);
- if (!location)
- return;
- if (info->encl_device_id == 0xffff)
- printf(" slot %d", info->slot_number);
- else if (info->encl_device_id == info->ref.v.device_id)
- printf(" enclosure %d", info->encl_index);
- else
- printf(" enclosure %d, slot %d", info->encl_index,
- info->slot_number);
}
static int
@@ -308,6 +304,7 @@ show_config(int ac, char **av)
if (mfi_config_read(fd, &config) < 0) {
error = errno;
warn("Failed to get config");
+ close(fd);
return (error);
}
@@ -323,16 +320,16 @@ show_config(int ac, char **av)
ar->num_drives);
for (j = 0; j < ar->num_drives; j++) {
device_id = ar->pd[j].ref.v.device_id;
- if (device_id == 0xffff)
- printf(" drive MISSING\n");
- else {
- printf(" drive %u ", device_id);
+ printf(" drive %s ", mfi_drive_name(NULL,
+ device_id,
+ MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
+ if (device_id != 0xffff) {
if (mfi_pd_get_info(fd, device_id, &pinfo,
NULL) < 0)
printf("%s",
mfi_pdstate(ar->pd[j].fw_state));
else
- print_pd(&pinfo, -1, 1);
+ print_pd(&pinfo, -1);
printf("\n");
}
}
@@ -361,13 +358,14 @@ show_config(int ac, char **av)
for (i = 0; i < config->spares_count; i++) {
sp = (struct mfi_spare *)p;
- printf(" %s spare %u ",
+ printf(" %s spare %s ",
sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" :
- "global", sp->ref.v.device_id);
+ "global", mfi_drive_name(NULL, sp->ref.v.device_id,
+ MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0)
printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE));
else
- print_pd(&pinfo, -1, 1);
+ print_pd(&pinfo, -1);
if (sp->spare_type & MFI_SPARE_DEDICATED) {
printf(" backs:\n");
for (j = 0; j < sp->array_count; j++)
@@ -376,6 +374,7 @@ show_config(int ac, char **av)
printf("\n");
p += config->spares_size;
}
+ free(config);
close(fd);
return (0);
@@ -406,6 +405,7 @@ show_volumes(int ac, char **av)
if (mfi_ld_get_list(fd, &list, NULL) < 0) {
error = errno;
warn("Failed to get volume list");
+ close(fd);
return (error);
}
@@ -431,6 +431,7 @@ show_volumes(int ac, char **av)
error = errno;
warn("Failed to get info for volume %d",
list.ld_list[i].ld.v.target_id);
+ close(fd);
return (error);
}
printf("%6s ",
@@ -483,10 +484,11 @@ show_drives(int ac, char **av)
return (error);
}
+ list = NULL;
if (mfi_pd_get_list(fd, &list, NULL) < 0) {
error = errno;
warn("Failed to get drive list");
- return (error);
+ goto error;
}
/* Walk the list of drives to determine width of state column. */
@@ -500,7 +502,7 @@ show_drives(int ac, char **av)
error = errno;
warn("Failed to fetch info for drive %u",
list->addr[i].device_id);
- return (error);
+ goto error;
}
len = strlen(mfi_pdstate(info.fw_state));
if (len > state_len)
@@ -521,15 +523,21 @@ show_drives(int ac, char **av)
error = errno;
warn("Failed to fetch info for drive %u",
list->addr[i].device_id);
- return (error);
+ goto error;
}
- print_pd(&info, state_len, 1);
+ printf("%s ", mfi_drive_name(&info, list->addr[i].device_id,
+ MFI_DNAME_DEVICE_ID));
+ print_pd(&info, state_len);
+ printf(" %s", mfi_drive_name(&info, list->addr[i].device_id,
+ MFI_DNAME_ES));
printf("\n");
}
+error:
+ free(list);
close(fd);
- return (0);
+ return (error);
}
MFI_COMMAND(show, drives, show_drives);
@@ -586,6 +594,7 @@ show_firmware(int ac, char **av)
if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
error = errno;
warn("Failed to get controller info");
+ close(fd);
return (error);
}
@@ -627,7 +636,6 @@ show_progress(int ac, char **av)
struct mfi_pd_info pinfo;
int busy, error, fd;
u_int i;
-
uint16_t device_id;
uint8_t target_id;
@@ -642,25 +650,29 @@ show_progress(int ac, char **av)
warn("mfi_open");
return (error);
}
- busy = 0;
if (mfi_ld_get_list(fd, &llist, NULL) < 0) {
error = errno;
warn("Failed to get volume list");
+ close(fd);
return (error);
}
if (mfi_pd_get_list(fd, &plist, NULL) < 0) {
error = errno;
warn("Failed to get drive list");
+ close(fd);
return (error);
}
+ busy = 0;
for (i = 0; i < llist.ld_count; i++) {
target_id = llist.ld_list[i].ld.v.target_id;
if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) {
error = errno;
warn("Failed to get info for volume %s",
mfi_volume_name(fd, target_id));
+ free(plist);
+ close(fd);
return (error);
}
if (linfo.progress.active & MFI_LD_PROGRESS_CC) {
@@ -697,27 +709,33 @@ show_progress(int ac, char **av)
if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) {
error = errno;
warn("Failed to fetch info for drive %u", device_id);
+ free(plist);
+ close(fd);
return (error);
}
if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) {
- printf("drive %u ", device_id);
+ printf("drive %s ", mfi_drive_name(NULL, device_id,
+ MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
mfi_display_progress("Rebuild", &pinfo.prog_info.rbld);
busy = 1;
}
if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) {
- printf("drive %u ", device_id);
+ printf("drive %s ", mfi_drive_name(NULL, device_id,
+ MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
mfi_display_progress("Patrol Read",
&pinfo.prog_info.patrol);
busy = 1;
}
if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) {
- printf("drive %u ", device_id);
+ printf("drive %s ", mfi_drive_name(NULL, device_id,
+ MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
mfi_display_progress("Clear", &pinfo.prog_info.clear);
busy = 1;
}
}
+ free(plist);
close(fd);
if (!busy)
diff --git a/usr.sbin/mfiutil/mfi_volume.c b/usr.sbin/mfiutil/mfi_volume.c
index 1e679c4..0d9300a 100644
--- a/usr.sbin/mfiutil/mfi_volume.c
+++ b/usr.sbin/mfiutil/mfi_volume.c
@@ -174,12 +174,14 @@ volume_cache(int ac, char **av)
if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
error = errno;
warn("Invalid volume: %s", av[1]);
+ close(fd);
return (error);
}
if (mfi_ld_get_props(fd, target_id, &props) < 0) {
error = errno;
warn("Failed to fetch volume properties");
+ close(fd);
return (error);
}
@@ -264,6 +266,7 @@ volume_cache(int ac, char **av)
else if (strcmp(av[2], "read-ahead") == 0) {
if (ac < 4) {
warnx("cache: read-ahead setting required");
+ close(fd);
return (EINVAL);
}
if (strcmp(av[3], "none") == 0)
@@ -275,6 +278,7 @@ volume_cache(int ac, char **av)
MR_LD_CACHE_READ_ADAPTIVE;
else {
warnx("cache: invalid read-ahead setting");
+ close(fd);
return (EINVAL);
}
error = update_cache_policy(fd, &props, policy,
@@ -283,6 +287,7 @@ volume_cache(int ac, char **av)
} else if (strcmp(av[2], "bad-bbu-write-cache") == 0) {
if (ac < 4) {
warnx("cache: bad BBU setting required");
+ close(fd);
return (EINVAL);
}
if (strcmp(av[3], "enable") == 0)
@@ -291,6 +296,7 @@ volume_cache(int ac, char **av)
policy = 0;
else {
warnx("cache: invalid bad BBU setting");
+ close(fd);
return (EINVAL);
}
error = update_cache_policy(fd, &props, policy,
@@ -298,6 +304,7 @@ volume_cache(int ac, char **av)
} else if (strcmp(av[2], "write-cache") == 0) {
if (ac < 4) {
warnx("cache: write-cache setting required");
+ close(fd);
return (EINVAL);
}
if (strcmp(av[3], "enable") == 0)
@@ -308,6 +315,7 @@ volume_cache(int ac, char **av)
policy = MR_PD_CACHE_UNCHANGED;
else {
warnx("cache: invalid write-cache setting");
+ close(fd);
return (EINVAL);
}
error = 0;
@@ -331,6 +339,7 @@ volume_cache(int ac, char **av)
}
} else {
warnx("cache: Invalid command");
+ close(fd);
return (EINVAL);
}
}
@@ -367,12 +376,14 @@ volume_name(int ac, char **av)
if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
error = errno;
warn("Invalid volume: %s", av[1]);
+ close(fd);
return (error);
}
if (mfi_ld_get_props(fd, target_id, &props) < 0) {
error = errno;
warn("Failed to fetch volume properties");
+ close(fd);
return (error);
}
@@ -383,6 +394,7 @@ volume_name(int ac, char **av)
if (mfi_ld_set_props(fd, &props) < 0) {
error = errno;
warn("Failed to set volume properties");
+ close(fd);
return (error);
}
@@ -415,6 +427,7 @@ volume_progress(int ac, char **av)
if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
error = errno;
warn("Invalid volume: %s", av[1]);
+ close(fd);
return (error);
}
@@ -423,6 +436,7 @@ volume_progress(int ac, char **av)
error = errno;
warn("Failed to fetch info for volume %s",
mfi_volume_name(fd, target_id));
+ close(fd);
return (error);
}
diff --git a/usr.sbin/mfiutil/mfiutil.8 b/usr.sbin/mfiutil/mfiutil.8
index d5178a0..dcd17f5 100644
--- a/usr.sbin/mfiutil/mfiutil.8
+++ b/usr.sbin/mfiutil/mfiutil.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 29, 2011
+.Dd June 20, 2011
.Dt MFIUTIL 8
.Os
.Sh NAME
@@ -43,6 +43,8 @@
.Op Fl u Ar unit
.Cm show battery
.Nm
+.Op Fl d
+.Op Fl e
.Op Fl u Ar unit
.Cm show config
.Nm
@@ -63,9 +65,13 @@
.Op Fl u Ar unit
.Cm show logstate
.Nm
+.Op Fl d
+.Op Fl e
.Op Fl u Ar unit
.Cm show patrol
.Nm
+.Op Fl d
+.Op Fl e
.Op Fl u Ar unit
.Cm show progress
.Nm
@@ -155,15 +161,19 @@ If no unit is specified,
then unit 0 is used.
.El
.Pp
-Volumes may be specified in two forms.
-First,
-a volume may be identified by its target ID.
-Second,
-on the volume may be specified by the corresponding
-.Em mfidX
-device,
-such as
-.Em mfid0 .
+Various commands accept either or both of the two options:
+.Bl -tag -width indent
+.It Fl d
+Print numeric device IDs as drive identifier.
+This is the default.
+Useful in combination with
+.Fl e
+to print both, numeric device IDs and enclosure:slot information.
+.It Fl e
+Print drive identifiers in enclosure:slot form.
+See next paragraph on format details in context of input rather than
+output.
+.El
.Pp
Drives may be specified in two forms.
First,
@@ -184,6 +194,16 @@ and
is the slot for each drive as displayed in
.Cm show drives .
.Pp
+Volumes may be specified in two forms.
+First,
+a volume may be identified by its target ID.
+Second,
+on the volume may be specified by the corresponding
+.Em mfidX
+device,
+such as
+.Em mfid0 .
+.Pp
The
.Nm
utility supports several different groups of commands.
diff --git a/usr.sbin/mfiutil/mfiutil.c b/usr.sbin/mfiutil/mfiutil.c
index 1bce79e..43bb6bb 100644
--- a/usr.sbin/mfiutil/mfiutil.c
+++ b/usr.sbin/mfiutil/mfiutil.c
@@ -45,11 +45,13 @@ MFI_TABLE(top, abort);
int mfi_unit;
+u_int mfi_opts;
+
static void
usage(void)
{
- fprintf(stderr, "usage: mfiutil [-u unit] <command> ...\n\n");
+ fprintf(stderr, "usage: mfiutil [-de] [-u unit] <command> ...\n\n");
fprintf(stderr, "Commands include:\n");
fprintf(stderr, " version\n");
fprintf(stderr, " show adapter - display controller information\n");
@@ -58,6 +60,7 @@ usage(void)
fprintf(stderr, " show drives - list physical drives\n");
fprintf(stderr, " show events - display event log\n");
fprintf(stderr, " show firmware - list firmware images\n");
+ fprintf(stderr, " show logstate - display event log sequence numbers\n");
fprintf(stderr, " show volumes - list logical volumes\n");
fprintf(stderr, " show patrol - display patrol read status\n");
fprintf(stderr, " show progress - display status of active operations\n");
@@ -107,8 +110,14 @@ main(int ac, char **av)
struct mfiutil_command **cmd;
int ch;
- while ((ch = getopt(ac, av, "u:")) != -1) {
+ while ((ch = getopt(ac, av, "deu:")) != -1) {
switch (ch) {
+ case 'd':
+ mfi_opts |= MFI_DNAME_DEVICE_ID;
+ break;
+ case 'e':
+ mfi_opts |= MFI_DNAME_ES;
+ break;
case 'u':
mfi_unit = atoi(optarg);
break;
diff --git a/usr.sbin/mfiutil/mfiutil.h b/usr.sbin/mfiutil/mfiutil.h
index b080b50..232831e 100644
--- a/usr.sbin/mfiutil/mfiutil.h
+++ b/usr.sbin/mfiutil/mfiutil.h
@@ -115,7 +115,13 @@ struct mfiutil_command {
} \
MFI_COMMAND(set, name, mfiutil_ ## name ## _table_handler)
+/* Drive name printing options */
+#define MFI_DNAME_ES 0x0001 /* E%u:S%u */
+#define MFI_DNAME_DEVICE_ID 0x0002 /* %u */
+#define MFI_DNAME_HONOR_OPTS 0x8000 /* Allow cmd line to override default */
+
extern int mfi_unit;
+extern u_int mfi_opts;
void mbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref);
void mbox_store_pdref(uint8_t *mbox, union mfi_pd_ref *ref);
@@ -143,5 +149,7 @@ int mfi_pd_get_info(int fd, uint16_t device_id, struct mfi_pd_info *info,
int mfi_pd_get_list(int fd, struct mfi_pd_list **listp, uint8_t *statusp);
int mfi_reconfig_supported(void);
const char *mfi_status(u_int status_code);
+const char *mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t device_id,
+ uint32_t def);
#endif /* !__MFIUTIL_H__ */
diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
index 65bf44f..01a27eb 100644
--- a/usr.sbin/mountd/mountd.c
+++ b/usr.sbin/mountd/mountd.c
@@ -158,6 +158,8 @@ struct fhreturn {
int *fhr_secflavors;
};
+#define GETPORT_MAXTRY 20 /* Max tries to get a port # */
+
/* Global defs */
char *add_expdir(struct dirlist **, char *, int);
void add_dlist(struct dirlist **, struct dirlist *,
@@ -167,7 +169,9 @@ int check_dirpath(char *);
int check_options(struct dirlist *);
int checkmask(struct sockaddr *sa);
int chk_host(struct dirlist *, struct sockaddr *, int *, int *);
-void create_service(struct netconfig *nconf);
+static int create_service(struct netconfig *nconf);
+static void complete_service(struct netconfig *nconf, char *port_str);
+static void clearout_service(void);
void del_mlist(char *hostp, char *dirp);
struct dirlist *dirp_search(struct dirlist *, char *);
int do_mount(struct exportlist *, struct grouplist *, int,
@@ -233,6 +237,10 @@ int got_sighup = 0;
int xcreated = 0;
char *svcport_str = NULL;
+static int mallocd_svcport = 0;
+static int *sock_fd;
+static int sock_fdcnt;
+static int sock_fdpos;
int opt_flags;
static int have_v6 = 1;
@@ -281,6 +289,8 @@ main(int argc, char **argv)
in_port_t svcport;
int c, k, s;
int maxrec = RPC_MAXDATASIZE;
+ int attempt_cnt, port_len, port_pos, ret;
+ char **port_list;
/* Check that another mountd isn't already running. */
pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
@@ -451,17 +461,97 @@ main(int argc, char **argv)
hosts[nhosts - 1] = "127.0.0.1";
}
+ attempt_cnt = 1;
+ sock_fdcnt = 0;
+ sock_fd = NULL;
+ port_list = NULL;
+ port_len = 0;
nc_handle = setnetconfig();
while ((nconf = getnetconfig(nc_handle))) {
if (nconf->nc_flag & NC_VISIBLE) {
if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
"inet6") == 0) {
/* DO NOTHING */
+ } else {
+ ret = create_service(nconf);
+ if (ret == 1)
+ /* Ignore this call */
+ continue;
+ if (ret < 0) {
+ /*
+ * Failed to bind port, so close off
+ * all sockets created and try again
+ * if the port# was dynamically
+ * assigned via bind(2).
+ */
+ clearout_service();
+ if (mallocd_svcport != 0 &&
+ attempt_cnt < GETPORT_MAXTRY) {
+ free(svcport_str);
+ svcport_str = NULL;
+ mallocd_svcport = 0;
+ } else {
+ errno = EADDRINUSE;
+ syslog(LOG_ERR,
+ "bindresvport_sa: %m");
+ exit(1);
+ }
+
+ /* Start over at the first service. */
+ free(sock_fd);
+ sock_fdcnt = 0;
+ sock_fd = NULL;
+ nc_handle = setnetconfig();
+ attempt_cnt++;
+ } else if (mallocd_svcport != 0 &&
+ attempt_cnt == GETPORT_MAXTRY) {
+ /*
+ * For the last attempt, allow
+ * different port #s for each nconf
+ * by saving the svcport_str and
+ * setting it back to NULL.
+ */
+ port_list = realloc(port_list,
+ (port_len + 1) * sizeof(char *));
+ if (port_list == NULL)
+ out_of_mem();
+ port_list[port_len++] = svcport_str;
+ svcport_str = NULL;
+ mallocd_svcport = 0;
+ }
+ }
+ }
+ }
+
+ /*
+ * Successfully bound the ports, so call complete_service() to
+ * do the rest of the setup on the service(s).
+ */
+ sock_fdpos = 0;
+ port_pos = 0;
+ nc_handle = setnetconfig();
+ while ((nconf = getnetconfig(nc_handle))) {
+ if (nconf->nc_flag & NC_VISIBLE) {
+ if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
+ "inet6") == 0) {
+ /* DO NOTHING */
+ } else if (port_list != NULL) {
+ if (port_pos >= port_len) {
+ syslog(LOG_ERR, "too many port#s");
+ exit(1);
+ }
+ complete_service(nconf, port_list[port_pos++]);
} else
- create_service(nconf);
+ complete_service(nconf, svcport_str);
}
}
endnetconfig(nc_handle);
+ free(sock_fd);
+ if (port_list != NULL) {
+ for (port_pos = 0; port_pos < port_len; port_pos++)
+ free(port_list[port_pos]);
+ free(port_list);
+ }
if (xcreated == 0) {
syslog(LOG_ERR, "could not create any services");
@@ -491,30 +581,31 @@ main(int argc, char **argv)
/*
* This routine creates and binds sockets on the appropriate
- * addresses. It gets called one time for each transport and
- * registrates the service with rpcbind on that trasport.
+ * addresses. It gets called one time for each transport.
+ * It returns 0 upon success, 1 for ingore the call and -1 to indicate
+ * bind failed with EADDRINUSE.
+ * Any file descriptors that have been created are stored in sock_fd and
+ * the total count of them is maintained in sock_fdcnt.
*/
-void
+static int
create_service(struct netconfig *nconf)
{
struct addrinfo hints, *res = NULL;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct __rpc_sockinfo si;
- struct netbuf servaddr;
- SVCXPRT *transp = NULL;
int aicode;
int fd;
int nhostsbak;
int one = 1;
int r;
- int registered = 0;
u_int32_t host_addr[4]; /* IPv4 or IPv6 */
+ int mallocd_res;
if ((nconf->nc_semantics != NC_TPI_CLTS) &&
(nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD))
- return; /* not my type */
+ return (1); /* not my type */
/*
* XXX - using RPC library internal functions.
@@ -522,7 +613,7 @@ create_service(struct netconfig *nconf)
if (!__rpc_nconf2sockinfo(nconf, &si)) {
syslog(LOG_ERR, "cannot get information for %s",
nconf->nc_netid);
- return;
+ return (1);
}
/* Get mountd's address on this transport */
@@ -538,6 +629,12 @@ create_service(struct netconfig *nconf)
nhostsbak = nhosts;
while (nhostsbak > 0) {
--nhostsbak;
+ sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
+ if (sock_fd == NULL)
+ out_of_mem();
+ sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */
+ mallocd_res = 0;
+
/*
* XXX - using RPC library internal functions.
*/
@@ -549,14 +646,16 @@ create_service(struct netconfig *nconf)
syslog(non_fatal ? LOG_DEBUG : LOG_ERR,
"cannot create socket for %s", nconf->nc_netid);
- return;
+ if (non_fatal != 0)
+ continue;
+ exit(1);
}
switch (hints.ai_family) {
case AF_INET:
if (inet_pton(AF_INET, hosts[nhostsbak],
host_addr) == 1) {
- hints.ai_flags &= AI_NUMERICHOST;
+ hints.ai_flags |= AI_NUMERICHOST;
} else {
/*
* Skip if we have an AF_INET6 address.
@@ -571,7 +670,7 @@ create_service(struct netconfig *nconf)
case AF_INET6:
if (inet_pton(AF_INET6, hosts[nhostsbak],
host_addr) == 1) {
- hints.ai_flags &= AI_NUMERICHOST;
+ hints.ai_flags |= AI_NUMERICHOST;
} else {
/*
* Skip if we have an AF_INET address.
@@ -607,6 +706,7 @@ create_service(struct netconfig *nconf)
res = malloc(sizeof(struct addrinfo));
if (res == NULL)
out_of_mem();
+ mallocd_res = 1;
res->ai_flags = hints.ai_flags;
res->ai_family = hints.ai_family;
res->ai_protocol = hints.ai_protocol;
@@ -620,7 +720,7 @@ create_service(struct netconfig *nconf)
sin->sin_addr.s_addr = htonl(INADDR_ANY);
res->ai_addr = (struct sockaddr*) sin;
res->ai_addrlen = (socklen_t)
- sizeof(res->ai_addr);
+ sizeof(struct sockaddr_in);
break;
case AF_INET6:
sin6 = malloc(sizeof(struct sockaddr_in6));
@@ -631,10 +731,12 @@ create_service(struct netconfig *nconf)
sin6->sin6_addr = in6addr_any;
res->ai_addr = (struct sockaddr*) sin6;
res->ai_addrlen = (socklen_t)
- sizeof(res->ai_addr);
- break;
- default:
+ sizeof(struct sockaddr_in6);
break;
+ default:
+ syslog(LOG_ERR, "bad addr fam %d",
+ res->ai_family);
+ exit(1);
}
} else {
if ((aicode = getaddrinfo(NULL, svcport_str,
@@ -643,6 +745,7 @@ create_service(struct netconfig *nconf)
"cannot get local address for %s: %s",
nconf->nc_netid,
gai_strerror(aicode));
+ close(fd);
continue;
}
}
@@ -652,16 +755,91 @@ create_service(struct netconfig *nconf)
syslog(LOG_ERR,
"cannot get local address for %s: %s",
nconf->nc_netid, gai_strerror(aicode));
+ close(fd);
continue;
}
}
+ /* Store the fd. */
+ sock_fd[sock_fdcnt - 1] = fd;
+
+ /* Now, attempt the bind. */
r = bindresvport_sa(fd, res->ai_addr);
if (r != 0) {
+ if (errno == EADDRINUSE && mallocd_svcport != 0) {
+ if (mallocd_res != 0) {
+ free(res->ai_addr);
+ free(res);
+ } else
+ freeaddrinfo(res);
+ return (-1);
+ }
syslog(LOG_ERR, "bindresvport_sa: %m");
exit(1);
}
+ if (svcport_str == NULL) {
+ svcport_str = malloc(NI_MAXSERV * sizeof(char));
+ if (svcport_str == NULL)
+ out_of_mem();
+ mallocd_svcport = 1;
+
+ if (getnameinfo(res->ai_addr,
+ res->ai_addr->sa_len, NULL, NI_MAXHOST,
+ svcport_str, NI_MAXSERV * sizeof(char),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ errx(1, "Cannot get port number");
+ }
+ if (mallocd_res != 0) {
+ free(res->ai_addr);
+ free(res);
+ } else
+ freeaddrinfo(res);
+ res = NULL;
+ }
+ return (0);
+}
+
+/*
+ * Called after all the create_service() calls have succeeded, to complete
+ * the setup and registration.
+ */
+static void
+complete_service(struct netconfig *nconf, char *port_str)
+{
+ struct addrinfo hints, *res = NULL;
+ struct __rpc_sockinfo si;
+ struct netbuf servaddr;
+ SVCXPRT *transp = NULL;
+ int aicode, fd, nhostsbak;
+ int registered = 0;
+
+ if ((nconf->nc_semantics != NC_TPI_CLTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS_ORD))
+ return; /* not my type */
+
+ /*
+ * XXX - using RPC library internal functions.
+ */
+ if (!__rpc_nconf2sockinfo(nconf, &si)) {
+ syslog(LOG_ERR, "cannot get information for %s",
+ nconf->nc_netid);
+ return;
+ }
+
+ nhostsbak = nhosts;
+ while (nhostsbak > 0) {
+ --nhostsbak;
+ if (sock_fdpos >= sock_fdcnt) {
+ /* Should never happen. */
+ syslog(LOG_ERR, "Ran out of socket fd's");
+ return;
+ }
+ fd = sock_fd[sock_fdpos++];
+ if (fd < 0)
+ continue;
+
if (nconf->nc_semantics != NC_TPI_CLTS)
listen(fd, SOMAXCONN);
@@ -696,19 +874,7 @@ create_service(struct netconfig *nconf)
hints.ai_socktype = si.si_socktype;
hints.ai_protocol = si.si_proto;
- if (svcport_str == NULL) {
- svcport_str = malloc(NI_MAXSERV * sizeof(char));
- if (svcport_str == NULL)
- out_of_mem();
-
- if (getnameinfo(res->ai_addr,
- res->ai_addr->sa_len, NULL, NI_MAXHOST,
- svcport_str, NI_MAXSERV * sizeof(char),
- NI_NUMERICHOST | NI_NUMERICSERV))
- errx(1, "Cannot get port number");
- }
-
- if((aicode = getaddrinfo(NULL, svcport_str, &hints,
+ if ((aicode = getaddrinfo(NULL, port_str, &hints,
&res)) != 0) {
syslog(LOG_ERR, "cannot get local address: %s",
gai_strerror(aicode));
@@ -728,6 +894,23 @@ create_service(struct netconfig *nconf)
} /* end while */
}
+/*
+ * Clear out sockets after a failure to bind one of them, so that the
+ * cycle of socket creation/binding can start anew.
+ */
+static void
+clearout_service(void)
+{
+ int i;
+
+ for (i = 0; i < sock_fdcnt; i++) {
+ if (sock_fd[i] >= 0) {
+ shutdown(sock_fd[i], SHUT_RDWR);
+ close(sock_fd[i]);
+ }
+ }
+}
+
static void
usage(void)
{
diff --git a/usr.sbin/pc-sysinstall/backend-query/enable-net.sh b/usr.sbin/pc-sysinstall/backend-query/enable-net.sh
index 3c73550..8cd72a1 100755
--- a/usr.sbin/pc-sysinstall/backend-query/enable-net.sh
+++ b/usr.sbin/pc-sysinstall/backend-query/enable-net.sh
@@ -1,6 +1,11 @@
#!/bin/sh
#-
# Copyright (c) 2010 iXsystems, Inc. All rights reserved.
+# Copyright (c) 2011 The FreeBSD Foundation
+# All rights reserved.
+#
+# Portions of this software were developed by Bjoern Zeeb
+# under sponsorship from the FreeBSD Foundation.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -40,23 +45,67 @@ NETMASK="$3"
DNS="$4"
GATEWAY="$5"
MIRRORFETCH="$6"
+IPV6="$7"
+IPV6GATE="$8"
+IPV6DNS="$9"
if [ -z "${NIC}" ]
then
- echo "ERROR: Usage enable-net <nic> <ip> <netmask> <dns> <gateway>"
+ echo "ERROR: Usage enable-net <nic> <ip> <netmask> <dns> <gateway> <ipv6> " \
+ "<ipv6gateway> <ipv6dns>"
exit 150
fi
if [ "$NIC" = "AUTO-DHCP" ]
then
enable_auto_dhcp
+elif [ "$NIC" = "IPv6-SLAAC" ]
+then
+ enable_auto_slaac
+ # In addition, if static values were defined, add them as well.
+ # We might not get DNS information from RAs, for example.
+ if [ -n "${IPV6}" ]; then
+ VAL=""
+ get_first_wired_nic
+ if [ -n "${VAL}" ]; then
+ ifconfig ${VAL} inet6 ${IPV6} alias
+ fi
+ fi
+ # Append only here.
+ if [ -n "${IPV6DNS}" ]; then
+ echo "nameserver ${IPV6DNS}" >>/etc/resolv.conf
+ fi
+ # Do not
+ if [ -n "${IPV6GATE}" ]; then
+ # Check if we have a default route already to not overwrite.
+ if ! route -n get -inet6 default > /dev/null 2>&1 ; then
+ route add -inet6 default ${IPV6GATE}
+ fi
+ fi
else
echo "Enabling NIC: $NIC"
- ifconfig ${NIC} ${IP} ${NETMASK}
+ if [ -n "${IP}" ]; then
+ ifconfig ${NIC} inet ${IP} ${NETMASK}
+ fi
+ if [ -n "${IPV6}" ]; then
+ ifconfig ${NIC} inet6 ${IPV6} alias
+ fi
- echo "nameserver ${DNS}" >/etc/resolv.conf
+ # Keep default from IPv4-only support times and clear the resolv.conf file.
+ : > /etc/resolv.conf
+ if [ -n "${DNS}" ]; then
+ echo "nameserver ${DNS}" >>/etc/resolv.conf
+ fi
+ if [ -n "${IPV6DNS}" ]; then
+ echo "nameserver ${IPV6DNS}" >>/etc/resolv.conf
+ fi
- route add default ${GATE}
+ if [ -n "${GATE}" ]; then
+ route add -inet default ${GATE}
+ fi
+ if [ -n "${IPV6GATE}" ]; then
+ route add -inet6 default ${IPV6GATE}
+ fi
fi
case ${MIRRORFETCH} in
diff --git a/usr.sbin/pc-sysinstall/backend-query/test-netup.sh b/usr.sbin/pc-sysinstall/backend-query/test-netup.sh
index 4c8304e..e0a3eba 100755
--- a/usr.sbin/pc-sysinstall/backend-query/test-netup.sh
+++ b/usr.sbin/pc-sysinstall/backend-query/test-netup.sh
@@ -1,6 +1,11 @@
#!/bin/sh
#-
# Copyright (c) 2010 iXsystems, Inc. All rights reserved.
+# Copyright (c) 2011 The FreeBSD Foundation
+# All rights reserved.
+#
+# Portions of this software were developed by Bjoern Zeeb
+# under sponsorship from the FreeBSD Foundation.#
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -26,8 +31,8 @@
# $FreeBSD$
-# Script which tests "fetch" when using a network connection, and saves
-# if we are using direct connect, or need FTP passive mode
+# Script which tries to ping "home" to see if Internet connectivity is
+# available.
#############################################################################
rm ${TMPDIR}/.testftp >/dev/null 2>/dev/null
@@ -39,12 +44,26 @@ then
exit 0
fi
+ping6 -c 2 www.pcbsd.org >/dev/null 2>/dev/null
+if [ "$?" = "0" ]
+then
+ echo "ftp: Up"
+ exit 0
+fi
+
ping -c 2 www.freebsd.org >/dev/null 2>/dev/null
if [ "$?" = "0" ]
then
echo "ftp: Up"
exit 0
fi
-
+
+ping6 -c 2 www.freebsd.org >/dev/null 2>/dev/null
+if [ "$?" = "0" ]
+then
+ echo "ftp: Up"
+ exit 0
+fi
+
echo "ftp: Down"
exit 1
diff --git a/usr.sbin/pc-sysinstall/backend/functions-cleanup.sh b/usr.sbin/pc-sysinstall/backend/functions-cleanup.sh
index 97386f8..d69135a 100755
--- a/usr.sbin/pc-sysinstall/backend/functions-cleanup.sh
+++ b/usr.sbin/pc-sysinstall/backend/functions-cleanup.sh
@@ -219,9 +219,9 @@ setup_fstab()
# Echo out the fstab entry now
if [ "${PARTFS}" = "SWAP" ]
then
- echo "/dev/${DEVICE} none swap ${MNTOPTS} 0 0" >> ${FSTAB}
+ echo "/dev/${DEVICE} none swap ${MNTOPTS} 0 0" >> ${FSTAB}
else
- echo "/dev/${DEVICE} ${PARTMNT} ufs ${MNTOPTS} 1 1" >> ${FSTAB}
+ echo "/dev/${DEVICE} ${PARTMNT} ufs ${MNTOPTS} 1 1" >> ${FSTAB}
fi
fi # End of ZFS Check
diff --git a/usr.sbin/pc-sysinstall/backend/functions-networking.sh b/usr.sbin/pc-sysinstall/backend/functions-networking.sh
index d12a9cc..bdd5a1a 100755
--- a/usr.sbin/pc-sysinstall/backend/functions-networking.sh
+++ b/usr.sbin/pc-sysinstall/backend/functions-networking.sh
@@ -1,6 +1,11 @@
#!/bin/sh
#-
# Copyright (c) 2010 iXsystems, Inc. All rights reserved.
+# Copyright (c) 2011 The FreeBSD Foundation
+# All rights reserved.
+#
+# Portions of this software were developed by Bjoern Zeeb
+# under sponsorship from the FreeBSD Foundation.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -119,6 +124,61 @@ save_auto_dhcp()
enable_dhcp_all
};
+# Function which simply enables iPv6 SLAAC on all detected nics
+enable_slaac_all()
+{
+ rm ${TMPDIR}/.niclist >/dev/null 2>/dev/null
+ # start by getting a list of nics on this system
+ ${QUERYDIR}/detect-nics.sh > ${TMPDIR}/.niclist
+ if [ -e "${TMPDIR}/.niclist" ]
+ then
+ echo "# Auto-Enabled NICs from pc-sysinstall" >>${FSMNT}/etc/rc.conf
+ WLANCOUNT="0"
+ while read line
+ do
+ NIC="`echo $line | cut -d ':' -f 1`"
+ DESC="`echo $line | cut -d ':' -f 2`"
+ echo_log "Setting $NIC to acceptign RAs on the system."
+ check_is_wifi ${NIC}
+ if [ $? -eq 0 ]
+ then
+ # We have a wifi device, setup a wlan* entry for it
+ # Given we cannot have DHCP and SLAAC the same time currently
+ # it's save to just duplicate.
+ WLAN="wlan${WLANCOUNT}"
+ echo "wlans_${NIC}=\"${WLAN}\"" >>${FSMNT}/etc/rc.conf
+ #echo "ifconfig_${NIC}=\"up\"" >>${FSMNT}/etc/rc.conf
+ echo "ifconfig_${WLAN}=\"inet6 accept_rtadv\"" >>${FSMNT}/etc/rc.conf
+ CNIC="${WLAN}"
+ WLANCOUNT=$((WLANCOUNT+1))
+ else
+ #echo "ifconfig_${NIC}=\"up\"" >>${FSMNT}/etc/rc.conf
+ echo "ifconfig_${NIC}_ipv6=\"inet6 accept_rtadv\"" >>${FSMNT}/etc/rc.conf
+ CNIC="${NIC}"
+ fi
+
+ done < ${TMPDIR}/.niclist
+ fi
+
+ # Given we cannot yet rely on RAs to provide DNS information as much
+ # as we can in the DHCP world, we should append a given nameserver.
+ : > ${FSMNT}/etc/resolv.conf
+ get_value_from_cfg netSaveIPv6NameServer
+ NAMESERVER="${VAL}"
+ if [ -n "${NAMESERVER}" ]
+ then
+ echo "nameserver ${NAMESERVER}" >>${FSMNT}/etc/resolv.conf
+ fi
+
+};
+
+
+# Function which detects available nics, and enables IPv6 SLAAC on them
+save_auto_slaac()
+{
+ enable_slaac_all
+};
+
# Function which saves a manual nic setup to the installed system
save_manual_nic()
@@ -137,21 +197,41 @@ save_manual_nic()
fi
# If we get here, we have a manual setup, lets do so now
+ IFARGS=""
+ IF6ARGS=""
# Set the manual IP
- IFARGS="inet ${NETIP}"
-
- # Check if we have a netmask to set
- get_value_from_cfg netSaveMask
- NETMASK="${VAL}"
- if [ -n "${NETMASK}" ]
+ if [ -n "${NETIP}" ]
then
- IFARGS="${IFARGS} netmask ${NETMASK}"
+ IFARGS="inet ${NETIP}"
+
+ # Check if we have a netmask to set
+ get_value_from_cfg netSaveMask
+ NETMASK="${VAL}"
+ if [ -n "${NETMASK}" ]
+ then
+ IFARGS="${IFARGS} netmask ${NETMASK}"
+ fi
fi
+ get_value_from_cfg netSaveIPv6
+ NETIP6="${VAL}"
+ if [ -n "${NETIP6}" ]
+ then
+ # Make sure we have one inet6 prefix.
+ IF6ARGS=`echo "${NETIP6}" | awk '{ if ("^inet6 ") { print $0; } else
+ { printf "inet6 %s", $0; } }'`
+ fi
echo "# Auto-Enabled NICs from pc-sysinstall" >>${FSMNT}/etc/rc.conf
- echo "ifconfig_${NIC}=\"${IFARGS}\"" >>${FSMNT}/etc/rc.conf
+ if [ -n "${IFARGS}" ]
+ then
+ echo "ifconfig_${NIC}=\"${IFARGS}\"" >>${FSMNT}/etc/rc.conf
+ fi
+ if [ -n "${IF6ARGS}" ]
+ then
+ echo "ifconfig_${NIC}_ipv6=\"${IF6ARGS}\"" >>${FSMNT}/etc/rc.conf
+ fi
# Check if we have a default router to set
get_value_from_cfg netSaveDefaultRouter
@@ -160,15 +240,28 @@ save_manual_nic()
then
echo "defaultrouter=\"${NETROUTE}\"" >>${FSMNT}/etc/rc.conf
fi
+ get_value_from_cfg netSaveIPv6DefaultRouter
+ NETROUTE="${VAL}"
+ if [ -n "${NETROUTE}" ]
+ then
+ echo "ipv6_defaultrouter=\"${NETROUTE}\"" >>${FSMNT}/etc/rc.conf
+ fi
# Check if we have a nameserver to enable
+ : > ${FSMNT}/etc/resolv.conf
get_value_from_cfg netSaveNameServer
NAMESERVER="${VAL}"
if [ -n "${NAMESERVER}" ]
then
- echo "nameserver ${NAMESERVER}" >${FSMNT}/etc/resolv.conf
+ echo "nameserver ${NAMESERVER}" >>${FSMNT}/etc/resolv.conf
fi
-
+ get_value_from_cfg netSaveIPv6NameServer
+ NAMESERVER="${VAL}"
+ if [ -n "${NAMESERVER}" ]
+ then
+ echo "nameserver ${NAMESERVER}" >>${FSMNT}/etc/resolv.conf
+ fi
+
};
# Function which determines if a nic is active / up
@@ -208,6 +301,31 @@ enable_auto_dhcp()
};
+# Function which detects available nics, and runs rtsol on them.
+enable_auto_slaac()
+{
+
+ # start by getting a list of nics on this system
+ ${QUERYDIR}/detect-nics.sh > ${TMPDIR}/.niclist
+ ALLNICS=""
+ while read line
+ do
+ NIC="`echo $line | cut -d ':' -f 1`"
+ DESC="`echo $line | cut -d ':' -f 2`"
+
+ is_nic_active "${NIC}"
+ if [ $? -eq 0 ] ; then
+ echo_log "Will try IPv6 SLAAC on $NIC $DESC"
+ ifconfig ${NIC} inet6 -ifdisabled accept_rtadv up
+ ALLNICS="${ALLNICS} ${NIC}"
+ fi
+ done < ${TMPDIR}/.niclist
+
+ # XXX once we support it in-tree call /sbin/resovconf here.
+ echo_log "Running rtsol on ${ALLNICS}"
+ rtsol -F ${ALLNICS} >/dev/null 2>/dev/null
+}
+
# Get the mac address of a target NIC
get_nic_mac()
{
@@ -236,15 +354,20 @@ enable_manual_nic()
# If we get here, we have a manual setup, lets do so now
- # Set the manual IP
- rc_halt "ifconfig ${NIC} ${NETIP}"
+ # IPv4:
- # Check if we have a netmask to set
- get_value_from_cfg netMask
- NETMASK="${VAL}"
- if [ -n "${NETMASK}" ]
+ # Set the manual IP
+ if [ -n "${NETIP}" ]
then
- rc_halt "ifconfig ${NIC} netmask ${NETMASK}"
+ # Check if we have a netmask to set
+ get_value_from_cfg netMask
+ NETMASK="${VAL}"
+ if [ -n "${NETMASK}" ]
+ then
+ rc_halt "ifconfig inet ${NIC} netmask ${NETMASK}"
+ else
+ rc_halt "ifconfig inet ${NIC} ${NETIP}"
+ fi
fi
# Check if we have a default router to set
@@ -252,18 +375,42 @@ enable_manual_nic()
NETROUTE="${VAL}"
if [ -n "${NETROUTE}" ]
then
- rc_halt "route add default ${NETROUTE}"
+ rc_halt "route add -inet default ${NETROUTE}"
+ fi
+
+ # IPv6:
+
+ # Set static IPv6 address
+ get_value_from_cfg netIPv6
+ NETIP="${VAL}"
+ if [ -n ${NETIP} ]
+ then
+ rc_halt "ifconfig inet6 ${NIC} ${NETIP} -ifdisabled up"
+ fi
+
+ # Default router
+ get_value_from_cfg netIPv6DefaultRouter
+ NETROUTE="${VAL}"
+ if [ -n "${NETROUTE}" ]
+ then
+ rc_halt "route add -inet6 default ${NETROUTE}"
fi
# Check if we have a nameserver to enable
+ : >/etc/resolv.conf
get_value_from_cfg netNameServer
NAMESERVER="${VAL}"
if [ -n "${NAMESERVER}" ]
then
- echo "nameserver ${NAMESERVER}" >/etc/resolv.conf
+ echo "nameserver ${NAMESERVER}" >>/etc/resolv.conf
fi
-
-
+ get_value_from_cfg netIPv6NameServer
+ NAMESERVER="${VAL}"
+ if [ -n "${NAMESERVER}" ]
+ then
+ echo "nameserver ${NAMESERVER}" >>/etc/resolv.conf
+ fi
+
};
@@ -281,6 +428,9 @@ start_networking()
if [ "$NETDEV" = "AUTO-DHCP" ]
then
enable_auto_dhcp
+ elif [ "$NETDEV" = "IPv6-SLAAC" ]
+ then
+ enable_auto_slaac
else
enable_manual_nic ${NETDEV}
fi
@@ -304,6 +454,9 @@ save_networking_install()
if [ "$NETDEV" = "AUTO-DHCP" ]
then
save_auto_dhcp
+ elif [ "$NETDEV" = "IPv6-SLAAC" ]
+ then
+ save_auto_slaac
else
save_manual_nic ${NETDEV}
fi
diff --git a/usr.sbin/pmccontrol/pmccontrol.c b/usr.sbin/pmccontrol/pmccontrol.c
index cce1e0e..80d4bd7 100644
--- a/usr.sbin/pmccontrol/pmccontrol.c
+++ b/usr.sbin/pmccontrol/pmccontrol.c
@@ -28,8 +28,9 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/queue.h>
+#include <sys/cpuset.h>
#include <sys/sysctl.h>
#include <assert.h>
@@ -133,26 +134,32 @@ pmcc_init_debug(void)
static int
pmcc_do_enable_disable(struct pmcc_op_list *op_list)
{
+ long cpusetsize;
int c, error, i, j, ncpu, npmc, t;
- cpumask_t haltedcpus, cpumask;
+ cpuset_t haltedcpus, cpumask;
struct pmcc_op *np;
unsigned char *map;
unsigned char op;
int cpu, pmc;
- size_t dummy;
+ size_t setsize;
if ((ncpu = pmc_ncpu()) < 0)
err(EX_OSERR, "Unable to determine the number of cpus");
/* Determine the set of active CPUs. */
- cpumask = (1 << ncpu) - 1;
- dummy = sizeof(int);
- haltedcpus = (cpumask_t) 0;
+ cpusetsize = sysconf(_SC_CPUSET_SIZE);
+ if (cpusetsize == -1 || (u_long)cpusetsize > sizeof(cpuset_t)) {
+ err(EX_OSERR, "ERROR: Cannot determine which CPUs are "
+ "halted");
+ }
+ CPU_ZERO(&haltedcpus);
+ setsize = (size_t)cpusetsize;
if (ncpu > 1 && sysctlbyname("machdep.hlt_cpus", &haltedcpus,
- &dummy, NULL, 0) < 0)
+ &setsize, NULL, 0) < 0)
err(EX_OSERR, "ERROR: Cannot determine which CPUs are "
"halted");
- cpumask &= ~haltedcpus;
+ CPU_FILL(&cpumask);
+ CPU_NAND(&cpumask, &haltedcpus);
/* Determine the maximum number of PMCs in any CPU. */
npmc = 0;
@@ -200,7 +207,7 @@ pmcc_do_enable_disable(struct pmcc_op_list *op_list)
if (cpu == PMCC_CPU_ALL)
for (i = 0; i < ncpu; i++) {
- if ((1 << i) & cpumask)
+ if (CPU_ISSET(i, &cpumask))
SET_PMCS(i, pmc, op);
}
else
diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c
index db33746..b93ca66 100644
--- a/usr.sbin/pw/pw_user.c
+++ b/usr.sbin/pw/pw_user.c
@@ -163,7 +163,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
* If we'll need to use it or we're updating it,
* then create the base home directory if necessary
*/
- if (arg != NULL || getarg(args, 'm') != NULL) {
+ if ((arg != NULL || getarg(args, 'm') != NULL) && (getarg(args, 'd') == NULL)) {
int l = strlen(cnf->home);
if (l > 1 && cnf->home[l-1] == '/') /* Shave off any trailing path delimiter */
diff --git a/usr.sbin/rpc.lockd/lockd.c b/usr.sbin/rpc.lockd/lockd.c
index fb9e536..b3402ff 100644
--- a/usr.sbin/rpc.lockd/lockd.c
+++ b/usr.sbin/rpc.lockd/lockd.c
@@ -74,6 +74,8 @@ __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $");
#include "lockd.h"
#include <rpcsvc/nlm_prot.h>
+#define GETPORT_MAXTRY 20 /* Max tries to get a port # */
+
int debug_level = 0; /* 0 = no debugging syslog() calls */
int _rpcsvcdirty = 0;
@@ -84,13 +86,19 @@ int kernel_lockd_client;
pid_t client_pid;
struct mon mon_host;
char **hosts, *svcport_str = NULL;
+static int mallocd_svcport = 0;
+static int *sock_fd;
+static int sock_fdcnt;
+static int sock_fdpos;
int nhosts = 0;
int xcreated = 0;
char **addrs; /* actually (netid, uaddr) pairs */
int naddrs; /* count of how many (netid, uaddr) pairs */
char localhost[] = "localhost";
-void create_service(struct netconfig *nconf);
+static int create_service(struct netconfig *nconf);
+static void complete_service(struct netconfig *nconf, char *port_str);
+static void clearout_service(void);
void lookup_addresses(struct netconfig *nconf);
void init_nsm(void);
void nlm_prog_0(struct svc_req *, SVCXPRT *);
@@ -119,6 +127,8 @@ main(int argc, char **argv)
int have_v6 = 1;
int maxrec = RPC_MAXDATASIZE;
in_port_t svcport = 0;
+ int attempt_cnt, port_len, port_pos, ret;
+ char **port_list;
while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) {
switch (ch) {
@@ -309,6 +319,11 @@ main(int argc, char **argv)
}
endnetconfig(nc_handle);
} else {
+ attempt_cnt = 1;
+ sock_fdcnt = 0;
+ sock_fd = NULL;
+ port_list = NULL;
+ port_len = 0;
nc_handle = setnetconfig();
while ((nconf = getnetconfig(nc_handle))) {
/* We want to listen only on udp6, tcp6, udp, tcp transports */
@@ -317,11 +332,96 @@ main(int argc, char **argv)
if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
/* DO NOTHING */
} else {
- create_service(nconf);
+ ret = create_service(nconf);
+ if (ret == 1)
+ /* Ignore this call */
+ continue;
+ if (ret < 0) {
+ /*
+ * Failed to bind port, so close
+ * off all sockets created and
+ * try again if the port# was
+ * dynamically assigned via
+ * bind(2).
+ */
+ clearout_service();
+ if (mallocd_svcport != 0 &&
+ attempt_cnt <
+ GETPORT_MAXTRY) {
+ free(svcport_str);
+ svcport_str = NULL;
+ mallocd_svcport = 0;
+ } else {
+ errno = EADDRINUSE;
+ syslog(LOG_ERR,
+ "bindresvport_sa: %m");
+ exit(1);
+ }
+
+ /*
+ * Start over at the first
+ * service.
+ */
+ free(sock_fd);
+ sock_fdcnt = 0;
+ sock_fd = NULL;
+ nc_handle = setnetconfig();
+ attempt_cnt++;
+ } else if (mallocd_svcport != 0 &&
+ attempt_cnt == GETPORT_MAXTRY) {
+ /*
+ * For the last attempt, allow
+ * different port #s for each
+ * nconf by saving the
+ * svcport_str and setting it
+ * back to NULL.
+ */
+ port_list = realloc(port_list,
+ (port_len + 1) *
+ sizeof(char *));
+ if (port_list == NULL)
+ out_of_mem();
+ port_list[port_len++] =
+ svcport_str;
+ svcport_str = NULL;
+ mallocd_svcport = 0;
+ }
}
}
}
+
+ /*
+ * Successfully bound the ports, so call complete_service() to
+ * do the rest of the setup on the service(s).
+ */
+ sock_fdpos = 0;
+ port_pos = 0;
+ nc_handle = setnetconfig();
+ while ((nconf = getnetconfig(nc_handle))) {
+ /* We want to listen only on udp6, tcp6, udp, tcp transports */
+ if (nconf->nc_flag & NC_VISIBLE) {
+ /* Skip if there's no IPv6 support */
+ if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
+ /* DO NOTHING */
+ } else if (port_list != NULL) {
+ if (port_pos >= port_len) {
+ syslog(LOG_ERR,
+ "too many port#s");
+ exit(1);
+ }
+ complete_service(nconf,
+ port_list[port_pos++]);
+ } else
+ complete_service(nconf, svcport_str);
+ }
+ }
endnetconfig(nc_handle);
+ free(sock_fd);
+ if (port_list != NULL) {
+ for (port_pos = 0; port_pos < port_len; port_pos++)
+ free(port_list[port_pos]);
+ free(port_list);
+ }
}
/*
@@ -386,29 +486,30 @@ main(int argc, char **argv)
/*
* This routine creates and binds sockets on the appropriate
- * addresses. It gets called one time for each transport and
- * registrates the service with rpcbind on that trasport.
+ * addresses. It gets called one time for each transport.
+ * It returns 0 upon success, 1 for ingore the call and -1 to indicate
+ * bind failed with EADDRINUSE.
+ * Any file descriptors that have been created are stored in sock_fd and
+ * the total count of them is maintained in sock_fdcnt.
*/
-void
+static int
create_service(struct netconfig *nconf)
{
struct addrinfo hints, *res = NULL;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct __rpc_sockinfo si;
- struct netbuf servaddr;
- SVCXPRT *transp = NULL;
int aicode;
int fd;
int nhostsbak;
int r;
- int registered = 0;
u_int32_t host_addr[4]; /* IPv4 or IPv6 */
+ int mallocd_res;
if ((nconf->nc_semantics != NC_TPI_CLTS) &&
(nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD))
- return; /* not my type */
+ return (1); /* not my type */
/*
* XXX - using RPC library internal functions.
@@ -416,7 +517,7 @@ create_service(struct netconfig *nconf)
if (!__rpc_nconf2sockinfo(nconf, &si)) {
syslog(LOG_ERR, "cannot get information for %s",
nconf->nc_netid);
- return;
+ return (1);
}
/* Get rpc.statd's address on this transport */
@@ -432,6 +533,11 @@ create_service(struct netconfig *nconf)
nhostsbak = nhosts;
while (nhostsbak > 0) {
--nhostsbak;
+ sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
+ if (sock_fd == NULL)
+ out_of_mem();
+ sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */
+ mallocd_res = 0;
/*
* XXX - using RPC library internal functions.
@@ -446,7 +552,7 @@ create_service(struct netconfig *nconf)
case AF_INET:
if (inet_pton(AF_INET, hosts[nhostsbak],
host_addr) == 1) {
- hints.ai_flags &= AI_NUMERICHOST;
+ hints.ai_flags |= AI_NUMERICHOST;
} else {
/*
* Skip if we have an AF_INET6 address.
@@ -461,7 +567,7 @@ create_service(struct netconfig *nconf)
case AF_INET6:
if (inet_pton(AF_INET6, hosts[nhostsbak],
host_addr) == 1) {
- hints.ai_flags &= AI_NUMERICHOST;
+ hints.ai_flags |= AI_NUMERICHOST;
} else {
/*
* Skip if we have an AF_INET address.
@@ -485,6 +591,7 @@ create_service(struct netconfig *nconf)
res = malloc(sizeof(struct addrinfo));
if (res == NULL)
out_of_mem();
+ mallocd_res = 1;
res->ai_flags = hints.ai_flags;
res->ai_family = hints.ai_family;
res->ai_protocol = hints.ai_protocol;
@@ -498,7 +605,7 @@ create_service(struct netconfig *nconf)
sin->sin_addr.s_addr = htonl(INADDR_ANY);
res->ai_addr = (struct sockaddr*) sin;
res->ai_addrlen = (socklen_t)
- sizeof(res->ai_addr);
+ sizeof(struct sockaddr_in);
break;
case AF_INET6:
sin6 = malloc(sizeof(struct sockaddr_in6));
@@ -508,10 +615,14 @@ create_service(struct netconfig *nconf)
sin6->sin6_port = htons(0);
sin6->sin6_addr = in6addr_any;
res->ai_addr = (struct sockaddr*) sin6;
- res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
+ res->ai_addrlen = (socklen_t)
+ sizeof(struct sockaddr_in6);
break;
default:
- break;
+ syslog(LOG_ERR,
+ "bad addr fam %d",
+ res->ai_family);
+ exit(1);
}
} else {
if ((aicode = getaddrinfo(NULL, svcport_str,
@@ -520,6 +631,7 @@ create_service(struct netconfig *nconf)
"cannot get local address for %s: %s",
nconf->nc_netid,
gai_strerror(aicode));
+ close(fd);
continue;
}
}
@@ -529,16 +641,92 @@ create_service(struct netconfig *nconf)
syslog(LOG_ERR,
"cannot get local address for %s: %s",
nconf->nc_netid, gai_strerror(aicode));
+ close(fd);
continue;
}
}
+
+ /* Store the fd. */
+ sock_fd[sock_fdcnt - 1] = fd;
+
+ /* Now, attempt the bind. */
r = bindresvport_sa(fd, res->ai_addr);
if (r != 0) {
+ if (errno == EADDRINUSE && mallocd_svcport != 0) {
+ if (mallocd_res != 0) {
+ free(res->ai_addr);
+ free(res);
+ } else
+ freeaddrinfo(res);
+ return (-1);
+ }
syslog(LOG_ERR, "bindresvport_sa: %m");
exit(1);
}
+ if (svcport_str == NULL) {
+ svcport_str = malloc(NI_MAXSERV * sizeof(char));
+ if (svcport_str == NULL)
+ out_of_mem();
+ mallocd_svcport = 1;
+
+ if (getnameinfo(res->ai_addr,
+ res->ai_addr->sa_len, NULL, NI_MAXHOST,
+ svcport_str, NI_MAXSERV * sizeof(char),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ errx(1, "Cannot get port number");
+ }
+ if (mallocd_res != 0) {
+ free(res->ai_addr);
+ free(res);
+ } else
+ freeaddrinfo(res);
+ res = NULL;
+ }
+ return (0);
+}
+
+/*
+ * Called after all the create_service() calls have succeeded, to complete
+ * the setup and registration.
+ */
+static void
+complete_service(struct netconfig *nconf, char *port_str)
+{
+ struct addrinfo hints, *res = NULL;
+ struct __rpc_sockinfo si;
+ struct netbuf servaddr;
+ SVCXPRT *transp = NULL;
+ int aicode, fd, nhostsbak;
+ int registered = 0;
+
+ if ((nconf->nc_semantics != NC_TPI_CLTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS_ORD))
+ return; /* not my type */
+
+ /*
+ * XXX - using RPC library internal functions.
+ */
+ if (!__rpc_nconf2sockinfo(nconf, &si)) {
+ syslog(LOG_ERR, "cannot get information for %s",
+ nconf->nc_netid);
+ return;
+ }
+
+ nhostsbak = nhosts;
+ while (nhostsbak > 0) {
+ --nhostsbak;
+ if (sock_fdpos >= sock_fdcnt) {
+ /* Should never happen. */
+ syslog(LOG_ERR, "Ran out of socket fd's");
+ return;
+ }
+ fd = sock_fd[sock_fdpos++];
+ if (fd < 0)
+ continue;
+
if (nconf->nc_semantics != NC_TPI_CLTS)
listen(fd, SOMAXCONN);
@@ -582,19 +770,7 @@ create_service(struct netconfig *nconf)
hints.ai_socktype = si.si_socktype;
hints.ai_protocol = si.si_proto;
- if (svcport_str == NULL) {
- svcport_str = malloc(NI_MAXSERV * sizeof(char));
- if (svcport_str == NULL)
- out_of_mem();
-
- if (getnameinfo(res->ai_addr,
- res->ai_addr->sa_len, NULL, NI_MAXHOST,
- svcport_str, NI_MAXSERV * sizeof(char),
- NI_NUMERICHOST | NI_NUMERICSERV))
- errx(1, "Cannot get port number");
- }
-
- if((aicode = getaddrinfo(NULL, svcport_str, &hints,
+ if ((aicode = getaddrinfo(NULL, port_str, &hints,
&res)) != 0) {
syslog(LOG_ERR, "cannot get local address: %s",
gai_strerror(aicode));
@@ -617,6 +793,23 @@ create_service(struct netconfig *nconf)
}
/*
+ * Clear out sockets after a failure to bind one of them, so that the
+ * cycle of socket creation/binding can start anew.
+ */
+static void
+clearout_service(void)
+{
+ int i;
+
+ for (i = 0; i < sock_fdcnt; i++) {
+ if (sock_fd[i] >= 0) {
+ shutdown(sock_fd[i], SHUT_RDWR);
+ close(sock_fd[i]);
+ }
+ }
+}
+
+/*
* Look up addresses for the kernel to create transports for.
*/
void
diff --git a/usr.sbin/rpc.statd/statd.c b/usr.sbin/rpc.statd/statd.c
index b8b4311..ff537f8 100644
--- a/usr.sbin/rpc.statd/statd.c
+++ b/usr.sbin/rpc.statd/statd.c
@@ -39,6 +39,7 @@
__FBSDID("$FreeBSD$");
#include <err.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <rpc/rpc.h>
@@ -55,13 +56,21 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include "statd.h"
+#define GETPORT_MAXTRY 20 /* Max tries to get a port # */
+
int debug = 0; /* Controls syslog() calls for debug messages */
char **hosts, *svcport_str = NULL;
int nhosts = 0;
int xcreated = 0;
-
-void create_service(struct netconfig *nconf);
+static int mallocd_svcport = 0;
+static int *sock_fd;
+static int sock_fdcnt;
+static int sock_fdpos;
+
+static int create_service(struct netconfig *nconf);
+static void complete_service(struct netconfig *nconf, char *port_str);
+static void clearout_service(void);
static void handle_sigchld(int sig);
void out_of_mem(void);
@@ -78,6 +87,8 @@ main(int argc, char **argv)
char *endptr, **hosts_bak;
int have_v6 = 1;
int maxrec = RPC_MAXDATASIZE;
+ int attempt_cnt, port_len, port_pos, ret;
+ char **port_list;
while ((ch = getopt(argc, argv, "dh:p:")) != -1)
switch (ch) {
@@ -176,6 +187,11 @@ main(int argc, char **argv)
hosts[nhosts - 1] = "127.0.0.1";
}
+ attempt_cnt = 1;
+ sock_fdcnt = 0;
+ sock_fd = NULL;
+ port_list = NULL;
+ port_len = 0;
nc_handle = setnetconfig();
while ((nconf = getnetconfig(nc_handle))) {
/* We want to listen only on udp6, tcp6, udp, tcp transports */
@@ -184,11 +200,87 @@ main(int argc, char **argv)
if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
/* DO NOTHING */
} else {
- create_service(nconf);
+ ret = create_service(nconf);
+ if (ret == 1)
+ /* Ignore this call */
+ continue;
+ if (ret < 0) {
+ /*
+ * Failed to bind port, so close off
+ * all sockets created and try again
+ * if the port# was dynamically
+ * assigned via bind(2).
+ */
+ clearout_service();
+ if (mallocd_svcport != 0 &&
+ attempt_cnt < GETPORT_MAXTRY) {
+ free(svcport_str);
+ svcport_str = NULL;
+ mallocd_svcport = 0;
+ } else {
+ errno = EADDRINUSE;
+ syslog(LOG_ERR,
+ "bindresvport_sa: %m");
+ exit(1);
+ }
+
+ /* Start over at the first service. */
+ free(sock_fd);
+ sock_fdcnt = 0;
+ sock_fd = NULL;
+ nc_handle = setnetconfig();
+ attempt_cnt++;
+ } else if (mallocd_svcport != 0 &&
+ attempt_cnt == GETPORT_MAXTRY) {
+ /*
+ * For the last attempt, allow
+ * different port #s for each nconf
+ * by saving the svcport_str and
+ * setting it back to NULL.
+ */
+ port_list = realloc(port_list,
+ (port_len + 1) * sizeof(char *));
+ if (port_list == NULL)
+ out_of_mem();
+ port_list[port_len++] = svcport_str;
+ svcport_str = NULL;
+ mallocd_svcport = 0;
+ }
}
}
}
+
+ /*
+ * Successfully bound the ports, so call complete_service() to
+ * do the rest of the setup on the service(s).
+ */
+ sock_fdpos = 0;
+ port_pos = 0;
+ nc_handle = setnetconfig();
+ while ((nconf = getnetconfig(nc_handle))) {
+ /* We want to listen only on udp6, tcp6, udp, tcp transports */
+ if (nconf->nc_flag & NC_VISIBLE) {
+ /* Skip if there's no IPv6 support */
+ if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
+ /* DO NOTHING */
+ } else if (port_list != NULL) {
+ if (port_pos >= port_len) {
+ syslog(LOG_ERR, "too many port#s");
+ exit(1);
+ }
+ complete_service(nconf, port_list[port_pos++]);
+ } else
+ complete_service(nconf, svcport_str);
+ }
+ }
endnetconfig(nc_handle);
+ free(sock_fd);
+ if (port_list != NULL) {
+ for (port_pos = 0; port_pos < port_len; port_pos++)
+ free(port_list[port_pos]);
+ free(port_list);
+ }
+
init_file("/var/db/statd.status");
/* Note that it is NOT sensible to run this program from inetd - the */
@@ -215,29 +307,30 @@ main(int argc, char **argv)
/*
* This routine creates and binds sockets on the appropriate
- * addresses. It gets called one time for each transport and
- * registrates the service with rpcbind on that trasport.
+ * addresses. It gets called one time for each transport.
+ * It returns 0 upon success, 1 for ingore the call and -1 to indicate
+ * bind failed with EADDRINUSE.
+ * Any file descriptors that have been created are stored in sock_fd and
+ * the total count of them is maintained in sock_fdcnt.
*/
-void
+static int
create_service(struct netconfig *nconf)
{
struct addrinfo hints, *res = NULL;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct __rpc_sockinfo si;
- struct netbuf servaddr;
- SVCXPRT *transp = NULL;
int aicode;
int fd;
int nhostsbak;
int r;
- int registered = 0;
u_int32_t host_addr[4]; /* IPv4 or IPv6 */
+ int mallocd_res;
if ((nconf->nc_semantics != NC_TPI_CLTS) &&
(nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD))
- return; /* not my type */
+ return (1); /* not my type */
/*
* XXX - using RPC library internal functions.
@@ -245,7 +338,7 @@ create_service(struct netconfig *nconf)
if (!__rpc_nconf2sockinfo(nconf, &si)) {
syslog(LOG_ERR, "cannot get information for %s",
nconf->nc_netid);
- return;
+ return (1);
}
/* Get rpc.statd's address on this transport */
@@ -261,6 +354,11 @@ create_service(struct netconfig *nconf)
nhostsbak = nhosts;
while (nhostsbak > 0) {
--nhostsbak;
+ sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
+ if (sock_fd == NULL)
+ out_of_mem();
+ sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */
+ mallocd_res = 0;
/*
* XXX - using RPC library internal functions.
@@ -274,7 +372,7 @@ create_service(struct netconfig *nconf)
case AF_INET:
if (inet_pton(AF_INET, hosts[nhostsbak],
host_addr) == 1) {
- hints.ai_flags &= AI_NUMERICHOST;
+ hints.ai_flags |= AI_NUMERICHOST;
} else {
/*
* Skip if we have an AF_INET6 address.
@@ -289,7 +387,7 @@ create_service(struct netconfig *nconf)
case AF_INET6:
if (inet_pton(AF_INET6, hosts[nhostsbak],
host_addr) == 1) {
- hints.ai_flags &= AI_NUMERICHOST;
+ hints.ai_flags |= AI_NUMERICHOST;
} else {
/*
* Skip if we have an AF_INET address.
@@ -313,6 +411,7 @@ create_service(struct netconfig *nconf)
res = malloc(sizeof(struct addrinfo));
if (res == NULL)
out_of_mem();
+ mallocd_res = 1;
res->ai_flags = hints.ai_flags;
res->ai_family = hints.ai_family;
res->ai_protocol = hints.ai_protocol;
@@ -326,7 +425,7 @@ create_service(struct netconfig *nconf)
sin->sin_addr.s_addr = htonl(INADDR_ANY);
res->ai_addr = (struct sockaddr*) sin;
res->ai_addrlen = (socklen_t)
- sizeof(res->ai_addr);
+ sizeof(struct sockaddr_in);
break;
case AF_INET6:
sin6 = malloc(sizeof(struct sockaddr_in6));
@@ -336,10 +435,13 @@ create_service(struct netconfig *nconf)
sin6->sin6_port = htons(0);
sin6->sin6_addr = in6addr_any;
res->ai_addr = (struct sockaddr*) sin6;
- res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
+ res->ai_addrlen = (socklen_t)
+ sizeof(struct sockaddr_in6);
break;
default:
- break;
+ syslog(LOG_ERR, "bad addr fam %d",
+ res->ai_family);
+ exit(1);
}
} else {
if ((aicode = getaddrinfo(NULL, svcport_str,
@@ -348,6 +450,7 @@ create_service(struct netconfig *nconf)
"cannot get local address for %s: %s",
nconf->nc_netid,
gai_strerror(aicode));
+ close(fd);
continue;
}
}
@@ -357,16 +460,91 @@ create_service(struct netconfig *nconf)
syslog(LOG_ERR,
"cannot get local address for %s: %s",
nconf->nc_netid, gai_strerror(aicode));
+ close(fd);
continue;
}
}
+ /* Store the fd. */
+ sock_fd[sock_fdcnt - 1] = fd;
+
+ /* Now, attempt the bind. */
r = bindresvport_sa(fd, res->ai_addr);
if (r != 0) {
+ if (errno == EADDRINUSE && mallocd_svcport != 0) {
+ if (mallocd_res != 0) {
+ free(res->ai_addr);
+ free(res);
+ } else
+ freeaddrinfo(res);
+ return (-1);
+ }
syslog(LOG_ERR, "bindresvport_sa: %m");
exit(1);
}
+ if (svcport_str == NULL) {
+ svcport_str = malloc(NI_MAXSERV * sizeof(char));
+ if (svcport_str == NULL)
+ out_of_mem();
+ mallocd_svcport = 1;
+
+ if (getnameinfo(res->ai_addr,
+ res->ai_addr->sa_len, NULL, NI_MAXHOST,
+ svcport_str, NI_MAXSERV * sizeof(char),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ errx(1, "Cannot get port number");
+ }
+ if (mallocd_res != 0) {
+ free(res->ai_addr);
+ free(res);
+ } else
+ freeaddrinfo(res);
+ res = NULL;
+ }
+ return (0);
+}
+
+/*
+ * Called after all the create_service() calls have succeeded, to complete
+ * the setup and registration.
+ */
+static void
+complete_service(struct netconfig *nconf, char *port_str)
+{
+ struct addrinfo hints, *res = NULL;
+ struct __rpc_sockinfo si;
+ struct netbuf servaddr;
+ SVCXPRT *transp = NULL;
+ int aicode, fd, nhostsbak;
+ int registered = 0;
+
+ if ((nconf->nc_semantics != NC_TPI_CLTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS_ORD))
+ return; /* not my type */
+
+ /*
+ * XXX - using RPC library internal functions.
+ */
+ if (!__rpc_nconf2sockinfo(nconf, &si)) {
+ syslog(LOG_ERR, "cannot get information for %s",
+ nconf->nc_netid);
+ return;
+ }
+
+ nhostsbak = nhosts;
+ while (nhostsbak > 0) {
+ --nhostsbak;
+ if (sock_fdpos >= sock_fdcnt) {
+ /* Should never happen. */
+ syslog(LOG_ERR, "Ran out of socket fd's");
+ return;
+ }
+ fd = sock_fd[sock_fdpos++];
+ if (fd < 0)
+ continue;
+
if (nconf->nc_semantics != NC_TPI_CLTS)
listen(fd, SOMAXCONN);
@@ -397,19 +575,8 @@ create_service(struct netconfig *nconf)
hints.ai_socktype = si.si_socktype;
hints.ai_protocol = si.si_proto;
- if (svcport_str == NULL) {
- svcport_str = malloc(NI_MAXSERV * sizeof(char));
- if (svcport_str == NULL)
- out_of_mem();
-
- if (getnameinfo(res->ai_addr,
- res->ai_addr->sa_len, NULL, NI_MAXHOST,
- svcport_str, NI_MAXSERV * sizeof(char),
- NI_NUMERICHOST | NI_NUMERICSERV))
- errx(1, "Cannot get port number");
- }
- if((aicode = getaddrinfo(NULL, svcport_str, &hints,
+ if ((aicode = getaddrinfo(NULL, port_str, &hints,
&res)) != 0) {
syslog(LOG_ERR, "cannot get local address: %s",
gai_strerror(aicode));
@@ -428,6 +595,23 @@ create_service(struct netconfig *nconf)
} /* end while */
}
+/*
+ * Clear out sockets after a failure to bind one of them, so that the
+ * cycle of socket creation/binding can start anew.
+ */
+static void
+clearout_service(void)
+{
+ int i;
+
+ for (i = 0; i < sock_fdcnt; i++) {
+ if (sock_fd[i] >= 0) {
+ shutdown(sock_fd[i], SHUT_RDWR);
+ close(sock_fd[i]);
+ }
+ }
+}
+
static void
usage()
{
diff --git a/usr.sbin/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c
index 792ea27..7280f40 100644
--- a/usr.sbin/rtadvd/advcap.c
+++ b/usr.sbin/rtadvd/advcap.c
@@ -64,8 +64,6 @@
#define V_TERM "HOST"
#endif
-char *RM;
-
/*
* termcap - routines for dealing with the terminal capability data base
*
@@ -83,12 +81,10 @@ char *RM;
static char *tbuf;
static int hopcount; /* detect infinite loops in termcap, init 0 */
-static char *remotefile;
-
-extern char *conffile;
+extern const char *conffile;
int tgetent(char *, char *);
-int getent(char *, char *, char *);
+int getent(char *, char *, const char *);
int tnchktc(void);
int tnamatch(char *);
static char *tskip(char *);
@@ -103,22 +99,18 @@ static char *tdecode(char *, char **);
* we just notice escaped newlines.
*/
int
-tgetent(bp, name)
- char *bp, *name;
+tgetent(char *bp, char *name)
{
- char *cp;
-
- remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF;
- return (getent(bp, name, cp));
+ return (getent(bp, name, conffile));
}
int
-getent(bp, name, cp)
- char *bp, *name, *cp;
+getent(char *bp, char *name, const char *cfile)
{
int c;
int i = 0, cnt = 0;
char ibuf[BUFSIZ];
+ char *cp;
int tf;
tbuf = bp;
@@ -130,9 +122,9 @@ getent(bp, name, cp)
* use so we don't have to read the file. In this case it
* has to already have the newlines crunched out.
*/
- if (cp && *cp) {
- tf = open(RM = cp, O_RDONLY);
- }
+ if (cfile && *cfile)
+ tf = open(cfile, O_RDONLY);
+
if (tf < 0) {
syslog(LOG_INFO,
"<%s> open: %s", __func__, strerror(errno));
@@ -184,7 +176,7 @@ getent(bp, name, cp)
* Note that this works because of the left to right scan.
*/
int
-tnchktc()
+tnchktc(void)
{
char *p, *q;
char tcname[16]; /* name of similar terminal */
@@ -211,7 +203,7 @@ tnchktc()
write(STDERR_FILENO, "Infinite tc= loop\n", 18);
return (0);
}
- if (getent(tcbuf, tcname, remotefile) != 1) {
+ if (getent(tcbuf, tcname, conffile) != 1) {
return (0);
}
for (q = tcbuf; *q++ != ':'; )
@@ -233,8 +225,7 @@ tnchktc()
* name (before the first field) stops us.
*/
int
-tnamatch(np)
- char *np;
+tnamatch(char *np)
{
char *Np, *Bp;
@@ -260,8 +251,7 @@ tnamatch(np)
* into the termcap file in octal.
*/
static char *
-tskip(bp)
- char *bp;
+tskip(char *bp)
{
int dquote;
@@ -305,8 +295,7 @@ breakbreak:
* Note that we handle octal numbers beginning with 0.
*/
int64_t
-tgetnum(id)
- char *id;
+tgetnum(char *id)
{
int64_t i;
int base;
@@ -341,8 +330,7 @@ tgetnum(id)
* not given.
*/
int
-tgetflag(id)
- char *id;
+tgetflag(char *id)
{
char *bp = tbuf;
@@ -369,8 +357,7 @@ tgetflag(id)
* No checking on area overflow.
*/
char *
-tgetstr(id, area)
- char *id, **area;
+tgetstr(char *id, char **area)
{
char *bp = tbuf;
@@ -395,13 +382,11 @@ tgetstr(id, area)
* string capability escapes.
*/
static char *
-tdecode(str, area)
- char *str;
- char **area;
+tdecode(char *str, char **area)
{
char *cp;
int c;
- char *dp;
+ const char *dp;
int i;
char term;
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index 5eadcc5..c0e442b 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -34,7 +34,6 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
-#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -53,6 +52,7 @@
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
+#include <netdb.h>
#include <string.h>
#include <search.h>
#include <stdlib.h>
@@ -65,29 +65,55 @@
#include "if.h"
#include "config.h"
+/* label of tcapcode + number + domain name + zero octet */
+static char entbuf[10 + 3 + NI_MAXHOST + 1];
+static char oentbuf[10 + 3 + NI_MAXHOST + 1];
+static char abuf[DNAME_LABELENC_MAXLEN];
+
static time_t prefix_timo = (60 * 120); /* 2 hours.
* XXX: should be configurable. */
-extern struct rainfo *ralist;
static struct rtadvd_timer *prefix_timeout(void *);
-static void makeentry(char *, size_t, int, char *);
-static int getinet6sysctl(int);
+static void makeentry(char *, size_t, int, const char *);
+static size_t dname_labelenc(char *, const char *);
-void
-getconfig(intface)
- char *intface;
+/* Encode domain name label encoding in RFC 1035 Section 3.1 */
+static size_t
+dname_labelenc(char *dst, const char *src)
{
- int stat, i;
- char tbuf[BUFSIZ];
- struct rainfo *tmp;
- long val;
- int64_t val64;
- char buf[BUFSIZ];
- char *bp = buf;
- char *addr, *flagstr;
- static int forwarding = -1;
+ char *dst_origin;
+ char *p;
+ size_t len;
+
+ dst_origin = dst;
+ len = strlen(src);
+
+ /* Length fields per 63 octets + '\0' (<= DNAME_LABELENC_MAXLEN) */
+ memset(dst, 0, len + len / 64 + 1 + 1);
+
+ syslog(LOG_DEBUG, "<%s> labelenc = %s", __func__, src);
+ while (src && (len = strlen(src)) != 0) {
+ /* Put a length field with 63 octet limitation first. */
+ p = strchr(src, '.');
+ if (p == NULL)
+ *dst++ = len = MIN(63, len);
+ else
+ *dst++ = len = MIN(63, p - src);
+ /* Copy 63 octets at most. */
+ memcpy(dst, src, len);
+ dst += len;
+ if (p == NULL) /* the last label */
+ break;
+ src = p + 1;
+ }
+ /* Always need a 0-length label at the tail. */
+ *dst++ = '\0';
+
+ syslog(LOG_DEBUG, "<%s> labellen = %td", __func__, dst - dst_origin);
+ return (dst - dst_origin);
+}
-#define MUSTHAVE(var, cap) \
+#define MUSTHAVE(var, cap) \
do { \
int64_t t; \
if ((t = agetnum(cap)) < 0) { \
@@ -97,60 +123,184 @@ getconfig(intface)
} \
var = t; \
} while (0)
-#define MAYHAVE(var, cap, def) \
+
+#define MAYHAVE(var, cap, def) \
do { \
if ((var = agetnum(cap)) < 0) \
var = def; \
} while (0)
+#define ELM_MALLOC(p,error_action) \
+ do { \
+ p = malloc(sizeof(*p)); \
+ if (p == NULL) { \
+ syslog(LOG_ERR, "<%s> malloc failed: %s", \
+ __func__, strerror(errno)); \
+ error_action; \
+ } \
+ memset(p, 0, sizeof(*p)); \
+ } while(0)
+
+int
+loadconfig(char *ifl_names[], const int ifl_len)
+{
+ int i;
+ int idx;
+ int error;
+
+ for (i = 0; i < ifl_len; i++) {
+ idx = if_nametoindex(ifl_names[i]);
+ if (idx == 0) {
+ syslog(LOG_ERR,
+ "<%s> interface %s not found. "
+ "Ignored at this moment.", __func__, ifl_names[i]);
+ continue;
+ }
+ syslog(LOG_INFO,
+ "<%s> loading config for %s.", __func__, ifl_names[i]);
+ error = getconfig(idx);
+ if (error)
+ syslog(LOG_ERR,
+ "<%s> invalid configuration for %s. "
+ "Ignored at this moment.", __func__, ifl_names[i]);
+ }
+
+ return (0);
+}
+
+int
+rmconfig(int idx)
+{
+ struct rainfo *rai;
+ struct prefix *pfx;
+ struct soliciter *sol;
+ struct rdnss *rdn;
+ struct rdnss_addr *rdna;
+ struct dnssl *dns;
+ struct rtinfo *rti;
+
+ rai = if_indextorainfo(idx);
+ if (rai == NULL) {
+ syslog(LOG_ERR, "<%s>: rainfo not found (idx=%d)",
+ __func__, idx);
+ return (-1);
+ }
+
+ TAILQ_REMOVE(&railist, rai, rai_next);
+ syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.",
+ __func__, idx);
+
+ /* Free all of allocated memories for this entry. */
+ rtadvd_remove_timer(rai->rai_timer);
+
+ if (rai->rai_ra_data != NULL)
+ free(rai->rai_ra_data);
+
+ if (rai->rai_sdl != NULL)
+ free(rai->rai_sdl);
+
+ while ((pfx = TAILQ_FIRST(&rai->rai_prefix)) != NULL) {
+ TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next);
+ free(pfx);
+ }
+ while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) {
+ TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next);
+ free(sol);
+ }
+ while ((rdn = TAILQ_FIRST(&rai->rai_rdnss)) != NULL) {
+ TAILQ_REMOVE(&rai->rai_rdnss, rdn, rd_next);
+ while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) {
+ TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next);
+ free(rdna);
+ }
+ free(rdn);
+ }
+ while ((dns = TAILQ_FIRST(&rai->rai_dnssl)) != NULL) {
+ TAILQ_REMOVE(&rai->rai_dnssl, dns, dn_next);
+ free(dns);
+ }
+ while ((rti = TAILQ_FIRST(&rai->rai_route)) != NULL) {
+ TAILQ_REMOVE(&rai->rai_route, rti, rti_next);
+ free(rti);
+ }
+ free(rai);
+
+ return (0);
+}
+
+int
+getconfig(int idx)
+{
+ int stat, i;
+ char tbuf[BUFSIZ];
+ struct rainfo *rai;
+ struct rainfo *rai_old;
+ long val;
+ int64_t val64;
+ char buf[BUFSIZ];
+ char *bp = buf;
+ char *addr, *flagstr;
+ char intface[IFNAMSIZ];
+
+ if (if_indextoname(idx, intface) == NULL) {
+ syslog(LOG_ERR, "<%s> invalid index number (%d)",
+ __func__, idx);
+ return (-1);
+ }
+
+ TAILQ_FOREACH(rai_old, &railist, rai_next)
+ if (idx == rai_old->rai_ifindex)
+ break;
+
if ((stat = agetent(tbuf, intface)) <= 0) {
memset(tbuf, 0, sizeof(tbuf));
syslog(LOG_INFO,
- "<%s> %s isn't defined in the configuration file"
- " or the configuration file doesn't exist."
- " Treat it as default",
- __func__, intface);
+ "<%s> %s isn't defined in the configuration file"
+ " or the configuration file doesn't exist."
+ " Treat it as default",
+ __func__, intface);
}
- tmp = (struct rainfo *)malloc(sizeof(*ralist));
- if (tmp == NULL) {
- syslog(LOG_INFO, "<%s> %s: can't allocate enough memory",
- __func__, intface);
- exit(1);
- }
- memset(tmp, 0, sizeof(*tmp));
- tmp->prefix.next = tmp->prefix.prev = &tmp->prefix;
+ ELM_MALLOC(rai, exit(1));
+ TAILQ_INIT(&rai->rai_prefix);
#ifdef ROUTEINFO
- tmp->route.next = tmp->route.prev = &tmp->route;
+ TAILQ_INIT(&rai->rai_route);
#endif
+ TAILQ_INIT(&rai->rai_rdnss);
+ TAILQ_INIT(&rai->rai_dnssl);
+ TAILQ_INIT(&rai->rai_soliciter);
- /* check if we are allowed to forward packets (if not determined) */
- if (forwarding < 0) {
- if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
- exit(1);
- }
+ /* gather on-link prefixes from the network interfaces. */
+ if (agetflag("noifprefix"))
+ rai->rai_advifprefix = 0;
+ else
+ rai->rai_advifprefix = 1;
/* get interface information */
if (agetflag("nolladdr"))
- tmp->advlinkopt = 0;
+ rai->rai_advlinkopt = 0;
else
- tmp->advlinkopt = 1;
- if (tmp->advlinkopt) {
- if ((tmp->sdl = if_nametosdl(intface)) == NULL) {
+ rai->rai_advlinkopt = 1;
+ if (rai->rai_advlinkopt) {
+ if ((rai->rai_sdl = if_nametosdl(intface)) == NULL) {
syslog(LOG_ERR,
- "<%s> can't get information of %s",
- __func__, intface);
- exit(1);
+ "<%s> can't get information of %s",
+ __func__, intface);
+ goto getconfig_free_rai;
}
- tmp->ifindex = tmp->sdl->sdl_index;
+ rai->rai_ifindex = rai->rai_sdl->sdl_index;
} else
- tmp->ifindex = if_nametoindex(intface);
- strncpy(tmp->ifname, intface, sizeof(tmp->ifname));
- if ((tmp->phymtu = if_getmtu(intface)) == 0) {
- tmp->phymtu = IPV6_MMTU;
+ rai->rai_ifindex = if_nametoindex(intface);
+ strncpy(rai->rai_ifname, intface, sizeof(rai->rai_ifname));
+ syslog(LOG_DEBUG,
+ "<%s> ifindex = %d on %s", __func__, rai->rai_ifindex,
+ rai->rai_ifname);
+
+ if ((rai->rai_phymtu = if_getmtu(intface)) == 0) {
+ rai->rai_phymtu = IPV6_MMTU;
syslog(LOG_WARNING,
- "<%s> can't get interface mtu of %s. Treat as %d",
- __func__, intface, IPV6_MMTU);
+ "<%s> can't get interface mtu of %s. Treat as %d",
+ __func__, intface, IPV6_MMTU);
}
/*
@@ -159,25 +309,27 @@ getconfig(intface)
MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
syslog(LOG_ERR,
- "<%s> maxinterval (%ld) on %s is invalid "
- "(must be between %u and %u)", __func__, val,
- intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
- exit(1);
+ "<%s> maxinterval (%ld) on %s is invalid "
+ "(must be between %u and %u)", __func__, val,
+ intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
+ goto getconfig_free_rai;
}
- tmp->maxinterval = (u_int)val;
- MAYHAVE(val, "mininterval", tmp->maxinterval/3);
- if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) {
+ rai->rai_maxinterval = (u_int)val;
+
+ MAYHAVE(val, "mininterval", rai->rai_maxinterval/3);
+ if ((u_int)val < MIN_MININTERVAL ||
+ (u_int)val > (rai->rai_maxinterval * 3) / 4) {
syslog(LOG_ERR,
- "<%s> mininterval (%ld) on %s is invalid "
- "(must be between %d and %d)",
- __func__, val, intface, MIN_MININTERVAL,
- (tmp->maxinterval * 3) / 4);
- exit(1);
+ "<%s> mininterval (%ld) on %s is invalid "
+ "(must be between %d and %d)",
+ __func__, val, intface, MIN_MININTERVAL,
+ (rai->rai_maxinterval * 3) / 4);
+ goto getconfig_free_rai;
}
- tmp->mininterval = (u_int)val;
+ rai->rai_mininterval = (u_int)val;
MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
- tmp->hoplimit = val & 0xff;
+ rai->rai_hoplimit = val & 0xff;
if ((flagstr = (char *)agetstr("raflags", &bp))) {
val = 0;
@@ -191,77 +343,61 @@ getconfig(intface)
if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
syslog(LOG_ERR, "<%s> the \'h\' and \'l\'"
" router flags are exclusive", __func__);
- exit(1);
+ goto getconfig_free_rai;
}
val |= ND_RA_FLAG_RTPREF_LOW;
}
- } else {
+ } else
MAYHAVE(val, "raflags", 0);
- }
- tmp->managedflg = val & ND_RA_FLAG_MANAGED;
- tmp->otherflg = val & ND_RA_FLAG_OTHER;
+
+ rai->rai_managedflg = val & ND_RA_FLAG_MANAGED;
+ rai->rai_otherflg = val & ND_RA_FLAG_OTHER;
#ifndef ND_RA_FLAG_RTPREF_MASK
#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
#endif
- tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
- if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) {
+ rai->rai_rtpref = val & ND_RA_FLAG_RTPREF_MASK;
+ if (rai->rai_rtpref == ND_RA_FLAG_RTPREF_RSV) {
syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s",
- __func__, tmp->rtpref, intface);
- exit(1);
+ __func__, rai->rai_rtpref, intface);
+ goto getconfig_free_rai;
}
- MAYHAVE(val, "rltime", tmp->maxinterval * 3);
- if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) {
+ MAYHAVE(val, "rltime", rai->rai_maxinterval * 3);
+ if ((u_int)val && ((u_int)val < rai->rai_maxinterval ||
+ (u_int)val > MAXROUTERLIFETIME)) {
syslog(LOG_ERR,
- "<%s> router lifetime (%ld) on %s is invalid "
- "(must be 0 or between %d and %d)",
- __func__, val, intface,
- tmp->maxinterval,
- MAXROUTERLIFETIME);
- exit(1);
+ "<%s> router lifetime (%ld) on %s is invalid "
+ "(must be 0 or between %d and %d)",
+ __func__, val, intface, rai->rai_maxinterval,
+ MAXROUTERLIFETIME);
+ goto getconfig_free_rai;
}
- /*
- * Basically, hosts MUST NOT send Router Advertisement messages at any
- * time (RFC 2461, Section 6.2.3). However, it would sometimes be
- * useful to allow hosts to advertise some parameters such as prefix
- * information and link MTU. Thus, we allow hosts to invoke rtadvd
- * only when router lifetime (on every advertising interface) is
- * explicitly set zero. (see also the above section)
- */
- if (val && forwarding == 0) {
- syslog(LOG_ERR,
- "<%s> non zero router lifetime is specified for %s, "
- "which must not be allowed for hosts. you must "
- "change router lifetime or enable IPv6 forwarding.",
- __func__, intface);
- exit(1);
- }
- tmp->lifetime = val & 0xffff;
+ rai->rai_lifetime = val & 0xffff;
MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
if (val < 0 || val > MAXREACHABLETIME) {
syslog(LOG_ERR,
- "<%s> reachable time (%ld) on %s is invalid "
- "(must be no greater than %d)",
- __func__, val, intface, MAXREACHABLETIME);
- exit(1);
+ "<%s> reachable time (%ld) on %s is invalid "
+ "(must be no greater than %d)",
+ __func__, val, intface, MAXREACHABLETIME);
+ goto getconfig_free_rai;
}
- tmp->reachabletime = (u_int32_t)val;
+ rai->rai_reachabletime = (u_int32_t)val;
MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
if (val64 < 0 || val64 > 0xffffffff) {
syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range",
- __func__, (long long)val64, intface);
- exit(1);
+ __func__, (long long)val64, intface);
+ goto getconfig_free_rai;
}
- tmp->retranstimer = (u_int32_t)val64;
+ rai->rai_retranstimer = (u_int32_t)val64;
if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
syslog(LOG_ERR,
- "<%s> mobile-ip6 configuration not supported",
- __func__);
- exit(1);
+ "<%s> mobile-ip6 configuration not supported",
+ __func__);
+ goto getconfig_free_rai;
}
/* prefix information */
@@ -271,12 +407,11 @@ getconfig(intface)
* checking consistency of advertised lifetimes.
*/
MAYHAVE(val, "clockskew", 0);
- tmp->clockskew = val;
+ rai->rai_clockskew = val;
- tmp->pfxs = 0;
+ rai->rai_pfxs = 0;
for (i = -1; i < MAXPREFIX; i++) {
struct prefix *pfx;
- char entbuf[256];
makeentry(entbuf, sizeof(entbuf), i, "addr");
addr = (char *)agetstr(entbuf, &bp);
@@ -284,49 +419,38 @@ getconfig(intface)
continue;
/* allocate memory to store prefix information */
- if ((pfx = malloc(sizeof(struct prefix))) == NULL) {
- syslog(LOG_ERR,
- "<%s> can't allocate enough memory",
- __func__);
- exit(1);
- }
- memset(pfx, 0, sizeof(*pfx));
+ ELM_MALLOC(pfx, exit(1));
+ pfx->pfx_rainfo = rai;
+ pfx->pfx_origin = PREFIX_FROM_CONFIG;
- /* link into chain */
- insque(pfx, &tmp->prefix);
- tmp->pfxs++;
- pfx->rainfo = tmp;
-
- pfx->origin = PREFIX_FROM_CONFIG;
-
- if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) {
+ if (inet_pton(AF_INET6, addr, &pfx->pfx_prefix) != 1) {
syslog(LOG_ERR,
- "<%s> inet_pton failed for %s",
- __func__, addr);
- exit(1);
+ "<%s> inet_pton failed for %s",
+ __func__, addr);
+ goto getconfig_free_pfx;
}
- if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
+ if (IN6_IS_ADDR_MULTICAST(&pfx->pfx_prefix)) {
syslog(LOG_ERR,
- "<%s> multicast prefix (%s) must "
- "not be advertised on %s",
- __func__, addr, intface);
- exit(1);
+ "<%s> multicast prefix (%s) must "
+ "not be advertised on %s",
+ __func__, addr, intface);
+ goto getconfig_free_pfx;
}
- if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
+ if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix))
syslog(LOG_NOTICE,
- "<%s> link-local prefix (%s) will be"
- " advertised on %s",
- __func__, addr, intface);
+ "<%s> link-local prefix (%s) will be"
+ " advertised on %s",
+ __func__, addr, intface);
makeentry(entbuf, sizeof(entbuf), i, "prefixlen");
MAYHAVE(val, entbuf, 64);
if (val < 0 || val > 128) {
syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s "
- "on %s out of range",
- __func__, val, addr, intface);
- exit(1);
+ "on %s out of range",
+ __func__, val, addr, intface);
+ goto getconfig_free_pfx;
}
- pfx->prefixlen = (int)val;
+ pfx->pfx_prefixlen = (int)val;
makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
if ((flagstr = (char *)agetstr(entbuf, &bp))) {
@@ -339,8 +463,8 @@ getconfig(intface)
MAYHAVE(val, entbuf,
(ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
}
- pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
- pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
+ pfx->pfx_onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
+ pfx->pfx_autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
makeentry(entbuf, sizeof(entbuf), i, "vltime");
MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
@@ -348,17 +472,17 @@ getconfig(intface)
syslog(LOG_ERR, "<%s> vltime (%lld) for "
"%s/%d on %s is out of range",
__func__, (long long)val64,
- addr, pfx->prefixlen, intface);
- exit(1);
+ addr, pfx->pfx_prefixlen, intface);
+ goto getconfig_free_pfx;
}
- pfx->validlifetime = (u_int32_t)val64;
+ pfx->pfx_validlifetime = (u_int32_t)val64;
makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
if (agetflag(entbuf)) {
struct timeval now;
gettimeofday(&now, 0);
- pfx->vltimeexpire =
- now.tv_sec + pfx->validlifetime;
+ pfx->pfx_vltimeexpire =
+ now.tv_sec + pfx->pfx_validlifetime;
}
makeentry(entbuf, sizeof(entbuf), i, "pltime");
@@ -368,44 +492,51 @@ getconfig(intface)
"<%s> pltime (%lld) for %s/%d on %s "
"is out of range",
__func__, (long long)val64,
- addr, pfx->prefixlen, intface);
- exit(1);
+ addr, pfx->pfx_prefixlen, intface);
+ goto getconfig_free_pfx;
}
- pfx->preflifetime = (u_int32_t)val64;
+ pfx->pfx_preflifetime = (u_int32_t)val64;
makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
if (agetflag(entbuf)) {
struct timeval now;
gettimeofday(&now, 0);
- pfx->pltimeexpire =
- now.tv_sec + pfx->preflifetime;
+ pfx->pfx_pltimeexpire =
+ now.tv_sec + pfx->pfx_preflifetime;
}
+ /* link into chain */
+ TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next);
+ rai->rai_pfxs++;
+ continue;
+getconfig_free_pfx:
+ free(pfx);
}
- if (tmp->pfxs == 0)
- get_prefix(tmp);
+ if (rai->rai_advifprefix && rai->rai_pfxs == 0)
+ get_prefix(rai);
MAYHAVE(val, "mtu", 0);
- if (val < 0 || val > 0xffffffff) {
+ if (val < 0 || (u_int)val > 0xffffffff) {
syslog(LOG_ERR,
- "<%s> mtu (%ld) on %s out of range",
- __func__, val, intface);
- exit(1);
+ "<%s> mtu (%ld) on %s out of range",
+ __func__, val, intface);
+ goto getconfig_free_rai;
}
- tmp->linkmtu = (u_int32_t)val;
- if (tmp->linkmtu == 0) {
+ rai->rai_linkmtu = (u_int32_t)val;
+ if (rai->rai_linkmtu == 0) {
char *mtustr;
if ((mtustr = (char *)agetstr("mtu", &bp)) &&
strcmp(mtustr, "auto") == 0)
- tmp->linkmtu = tmp->phymtu;
+ rai->rai_linkmtu = rai->rai_phymtu;
}
- else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) {
+ else if (rai->rai_linkmtu < IPV6_MMTU ||
+ rai->rai_linkmtu > rai->rai_phymtu) {
syslog(LOG_ERR,
- "<%s> advertised link mtu (%lu) on %s is invalid (must "
- "be between least MTU (%d) and physical link MTU (%d)",
- __func__, (unsigned long)tmp->linkmtu, intface,
- IPV6_MMTU, tmp->phymtu);
- exit(1);
+ "<%s> advertised link mtu (%lu) on %s is invalid (must "
+ "be between least MTU (%d) and physical link MTU (%d)",
+ __func__, (unsigned long)rai->rai_linkmtu, intface,
+ IPV6_MMTU, rai->rai_phymtu);
+ goto getconfig_free_rai;
}
#ifdef SIOCSIFINFO_IN6
@@ -415,65 +546,52 @@ getconfig(intface)
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__,
- strerror(errno));
+ strerror(errno));
exit(1);
}
memset(&ndi, 0, sizeof(ndi));
strncpy(ndi.ifname, intface, IFNAMSIZ);
- if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) {
+ if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0)
syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
- __func__, intface, strerror(errno));
- }
+ __func__, intface, strerror(errno));
/* reflect the RA info to the host variables in kernel */
- ndi.ndi.chlim = tmp->hoplimit;
- ndi.ndi.retrans = tmp->retranstimer;
- ndi.ndi.basereachable = tmp->reachabletime;
- if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) {
+ ndi.ndi.chlim = rai->rai_hoplimit;
+ ndi.ndi.retrans = rai->rai_retranstimer;
+ ndi.ndi.basereachable = rai->rai_reachabletime;
+ if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0)
syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s",
- __func__, intface, strerror(errno));
- }
+ __func__, intface, strerror(errno));
+
close(s);
}
#endif
/* route information */
#ifdef ROUTEINFO
- tmp->routes = 0;
+ rai->rai_routes = 0;
for (i = -1; i < MAXROUTE; i++) {
struct rtinfo *rti;
- char entbuf[256], oentbuf[256];
makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
addr = (char *)agetstr(entbuf, &bp);
if (addr == NULL) {
makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix");
addr = (char *)agetstr(oentbuf, &bp);
- if (addr) {
+ if (addr)
fprintf(stderr, "%s was obsoleted. Use %s.\n",
- oentbuf, entbuf);
- }
+ oentbuf, entbuf);
}
if (addr == NULL)
continue;
/* allocate memory to store prefix information */
- if ((rti = malloc(sizeof(struct rtinfo))) == NULL) {
- syslog(LOG_ERR,
- "<%s> can't allocate enough memory",
- __func__);
- exit(1);
- }
- memset(rti, 0, sizeof(*rti));
-
- /* link into chain */
- insque(rti, &tmp->route);
- tmp->routes++;
+ ELM_MALLOC(rti, exit(1));
- if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
+ if (inet_pton(AF_INET6, addr, &rti->rti_prefix) != 1) {
syslog(LOG_ERR, "<%s> inet_pton failed for %s",
- __func__, addr);
- exit(1);
+ __func__, addr);
+ goto getconfig_free_rti;
}
#if 0
/*
@@ -485,17 +603,17 @@ getconfig(intface)
MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) {
syslog(LOG_ERR,
- "<%s> multicast route (%s) must "
- "not be advertised on %s",
- __func__, addr, intface);
- exit(1);
+ "<%s> multicast route (%s) must "
+ "not be advertised on %s",
+ __func__, addr, intface);
+ goto getconfig_free_rti;
}
if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
syslog(LOG_NOTICE,
- "<%s> link-local route (%s) will "
- "be advertised on %s",
- __func__, addr, intface);
- exit(1);
+ "<%s> link-local route (%s) will "
+ "be advertised on %s",
+ __func__, addr, intface);
+ goto getconfig_free_rti;
}
#endif
@@ -505,19 +623,19 @@ getconfig(intface)
if (val == 256) {
makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen");
MAYHAVE(val, oentbuf, 256);
- if (val != 256) {
+ if (val != 256)
fprintf(stderr, "%s was obsoleted. Use %s.\n",
- oentbuf, entbuf);
- } else
+ oentbuf, entbuf);
+ else
val = 64;
}
if (val < 0 || val > 128) {
syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s "
- "out of range",
- __func__, val, addr, intface);
- exit(1);
+ "out of range",
+ __func__, val, addr, intface);
+ goto getconfig_free_rti;
}
- rti->prefixlen = (int)val;
+ rti->rti_prefixlen = (int)val;
makeentry(entbuf, sizeof(entbuf), i, "rtflags");
if ((flagstr = (char *)agetstr(entbuf, &bp))) {
@@ -530,7 +648,7 @@ getconfig(intface)
"<%s> the \'h\' and \'l\' route"
" preferences are exclusive",
__func__);
- exit(1);
+ goto getconfig_free_rti;
}
val |= ND_RA_FLAG_RTPREF_LOW;
}
@@ -541,17 +659,17 @@ getconfig(intface)
MAYHAVE(val, oentbuf, 256);
if (val != 256) {
fprintf(stderr, "%s was obsoleted. Use %s.\n",
- oentbuf, entbuf);
+ oentbuf, entbuf);
} else
val = 0;
}
- rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
- if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) {
+ rti->rti_rtpref = val & ND_RA_FLAG_RTPREF_MASK;
+ if (rti->rti_rtpref == ND_RA_FLAG_RTPREF_RSV) {
syslog(LOG_ERR, "<%s> invalid route preference (%02x) "
- "for %s/%d on %s",
- __func__, rti->rtpref, addr,
- rti->prefixlen, intface);
- exit(1);
+ "for %s/%d on %s",
+ __func__, rti->rti_rtpref, addr,
+ rti->rti_prefixlen, intface);
+ goto getconfig_free_rti;
}
/*
@@ -565,60 +683,191 @@ getconfig(intface)
if (val64 == -1) {
makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime");
MAYHAVE(val64, oentbuf, -1);
- if (val64 != -1) {
+ if (val64 != -1)
fprintf(stderr, "%s was obsoleted. Use %s.\n",
- oentbuf, entbuf);
- } else {
+ oentbuf, entbuf);
+ else {
fprintf(stderr, "%s should be specified "
- "for interface %s.\n",
- entbuf, intface);
- val64 = tmp->lifetime;
+ "for interface %s.\n", entbuf, intface);
+ val64 = rai->rai_lifetime;
}
}
if (val64 < 0 || val64 > 0xffffffff) {
syslog(LOG_ERR, "<%s> route lifetime (%lld) for "
"%s/%d on %s out of range", __func__,
- (long long)val64, addr, rti->prefixlen, intface);
- exit(1);
+ (long long)val64, addr, rti->rti_prefixlen, intface);
+ goto getconfig_free_rti;
}
- rti->ltime = (u_int32_t)val64;
+ rti->rti_ltime = (u_int32_t)val64;
+
+ /* link into chain */
+ TAILQ_INSERT_TAIL(&rai->rai_route, rti, rti_next);
+ rai->rai_routes++;
+ continue;
+getconfig_free_rti:
+ free(rti);
}
#endif
+ /* DNS server and DNS search list information */
+ for (i = -1; i < MAXRDNSSENT ; i++) {
+ struct rdnss *rdn;
+ struct rdnss_addr *rdna;
+ char *ap;
+ int c;
+
+ makeentry(entbuf, sizeof(entbuf), i, "rdnss");
+ addr = (char *)agetstr(entbuf, &bp);
+ if (addr == NULL)
+ break;
+ ELM_MALLOC(rdn, exit(1));
+
+ TAILQ_INIT(&rdn->rd_list);
+
+ for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) {
+ c = strcspn(ap, ",");
+ strncpy(abuf, ap, c);
+ abuf[c] = '\0';
+ ELM_MALLOC(rdna, goto getconfig_free_rdn);
+ if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) {
+ syslog(LOG_ERR, "<%s> inet_pton failed for %s",
+ __func__, abuf);
+ free(rdna);
+ goto getconfig_free_rdn;
+ }
+ TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next);
+ }
+
+ makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
+ MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2));
+ if ((u_int)val < rai->rai_maxinterval ||
+ (u_int)val > rai->rai_maxinterval * 2) {
+ syslog(LOG_ERR, "%s (%ld) on %s is invalid "
+ "(must be between %d and %d)",
+ entbuf, val, intface, rai->rai_maxinterval,
+ rai->rai_maxinterval * 2);
+ goto getconfig_free_rdn;
+ }
+ rdn->rd_ltime = val;
+
+ /* link into chain */
+ TAILQ_INSERT_TAIL(&rai->rai_rdnss, rdn, rd_next);
+ continue;
+getconfig_free_rdn:
+ while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) {
+ TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next);
+ free(rdna);
+ }
+ free(rdn);
+ }
+
+ for (i = -1; i < MAXDNSSLENT ; i++) {
+ struct dnssl *dns;
+ struct dnssl_addr *dnsa;
+ char *ap;
+ int c;
+
+ makeentry(entbuf, sizeof(entbuf), i, "dnssl");
+ addr = (char *)agetstr(entbuf, &bp);
+ if (addr == NULL)
+ break;
+
+ ELM_MALLOC(dns, exit(1));
+
+ TAILQ_INIT(&dns->dn_list);
+
+ for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) {
+ c = strcspn(ap, ",");
+ strncpy(abuf, ap, c);
+ abuf[c] = '\0';
+ ELM_MALLOC(dnsa, goto getconfig_free_dns);
+ dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf);
+ syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__,
+ dnsa->da_len);
+ TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next);
+ }
- /* okey */
- tmp->next = ralist;
- ralist = tmp;
+ makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
+ MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2));
+ if ((u_int)val < rai->rai_maxinterval ||
+ (u_int)val > rai->rai_maxinterval * 2) {
+ syslog(LOG_ERR, "%s (%ld) on %s is invalid "
+ "(must be between %d and %d)",
+ entbuf, val, intface, rai->rai_maxinterval,
+ rai->rai_maxinterval * 2);
+ goto getconfig_free_dns;
+ }
+ dns->dn_ltime = val;
+ /* link into chain */
+ TAILQ_INSERT_TAIL(&rai->rai_dnssl, dns, dn_next);
+ continue;
+getconfig_free_dns:
+ while ((dnsa = TAILQ_FIRST(&dns->dn_list)) != NULL) {
+ TAILQ_REMOVE(&dns->dn_list, dnsa, da_next);
+ free(dnsa);
+ }
+ free(dns);
+ }
/* construct the sending packet */
- make_packet(tmp);
+ make_packet(rai);
+
+ /*
+ * If an entry with the same ifindex exists, remove it first.
+ * Before the removal, RDNSS and DNSSL options with
+ * zero-lifetime will be sent.
+ */
+ if (rai_old != NULL) {
+ const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
+ struct rdnss *rdn;
+ struct dnssl *dns;
+
+ rai_old->rai_lifetime = 0;
+ TAILQ_FOREACH(rdn, &rai_old->rai_rdnss, rd_next)
+ rdn->rd_ltime = 0;
+ TAILQ_FOREACH(dns, &rai_old->rai_dnssl, dn_next)
+ dns->dn_ltime = 0;
+
+ make_packet(rai_old);
+ for (i = 0; i < retrans; i++) {
+ ra_output(rai_old);
+ sleep(MIN_DELAY_BETWEEN_RAS);
+ }
+ rmconfig(idx);
+ }
+ TAILQ_INSERT_TAIL(&railist, rai, rai_next);
/* set timer */
- tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
- tmp, tmp);
- ra_timer_update((void *)tmp, &tmp->timer->tm);
- rtadvd_set_timer(&tmp->timer->tm, tmp->timer);
+ rai->rai_timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
+ rai, rai);
+ ra_timer_update((void *)rai, &rai->rai_timer->rat_tm);
+ rtadvd_set_timer(&rai->rai_timer->rat_tm, rai->rai_timer);
+
+ return (0);
+getconfig_free_rai:
+ free(rai);
+ return (-1);
}
void
get_prefix(struct rainfo *rai)
{
struct ifaddrs *ifap, *ifa;
- struct prefix *pp;
+ struct prefix *pfx;
struct in6_addr *a;
u_char *p, *ep, *m, *lim;
u_char ntopbuf[INET6_ADDRSTRLEN];
if (getifaddrs(&ifap) < 0) {
syslog(LOG_ERR,
- "<%s> can't get interface addresses",
- __func__);
+ "<%s> can't get interface addresses",
+ __func__);
exit(1);
}
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
int plen;
- if (strcmp(ifa->ifa_name, rai->ifname) != 0)
+ if (strcmp(ifa->ifa_name, rai->rai_ifname) != 0)
continue;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -631,8 +880,8 @@ get_prefix(struct rainfo *rai)
plen = prefixlen(m, lim);
if (plen <= 0 || plen > 128) {
syslog(LOG_ERR, "<%s> failed to get prefixlen "
- "or prefix is invalid",
- __func__);
+ "or prefix is invalid",
+ __func__);
exit(1);
}
if (plen == 128) /* XXX */
@@ -643,56 +892,46 @@ get_prefix(struct rainfo *rai)
}
/* allocate memory to store prefix info. */
- if ((pp = malloc(sizeof(*pp))) == NULL) {
- syslog(LOG_ERR,
- "<%s> can't get allocate buffer for prefix",
- __func__);
- exit(1);
- }
- memset(pp, 0, sizeof(*pp));
+ ELM_MALLOC(pfx, exit(1));
/* set prefix, sweep bits outside of prefixlen */
- pp->prefixlen = plen;
- memcpy(&pp->prefix, a, sizeof(*a));
- p = (u_char *)&pp->prefix;
- ep = (u_char *)(&pp->prefix + 1);
+ pfx->pfx_prefixlen = plen;
+ memcpy(&pfx->pfx_prefix, a, sizeof(*a));
+ p = (u_char *)&pfx->pfx_prefix;
+ ep = (u_char *)(&pfx->pfx_prefix + 1);
while (m < lim && p < ep)
*p++ &= *m++;
while (p < ep)
*p++ = 0x00;
- if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf,
+ if (!inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf,
sizeof(ntopbuf))) {
syslog(LOG_ERR, "<%s> inet_ntop failed", __func__);
exit(1);
}
syslog(LOG_DEBUG,
- "<%s> add %s/%d to prefix list on %s",
- __func__, ntopbuf, pp->prefixlen, rai->ifname);
+ "<%s> add %s/%d to prefix list on %s",
+ __func__, ntopbuf, pfx->pfx_prefixlen, rai->rai_ifname);
/* set other fields with protocol defaults */
- pp->validlifetime = DEF_ADVVALIDLIFETIME;
- pp->preflifetime = DEF_ADVPREFERREDLIFETIME;
- pp->onlinkflg = 1;
- pp->autoconfflg = 1;
- pp->origin = PREFIX_FROM_KERNEL;
- pp->rainfo = rai;
+ pfx->pfx_validlifetime = DEF_ADVVALIDLIFETIME;
+ pfx->pfx_preflifetime = DEF_ADVPREFERREDLIFETIME;
+ pfx->pfx_onlinkflg = 1;
+ pfx->pfx_autoconfflg = 1;
+ pfx->pfx_origin = PREFIX_FROM_KERNEL;
+ pfx->pfx_rainfo = rai;
/* link into chain */
- insque(pp, &rai->prefix);
+ TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next);
/* counter increment */
- rai->pfxs++;
+ rai->rai_pfxs++;
}
freeifaddrs(ifap);
}
static void
-makeentry(buf, len, id, string)
- char *buf;
- size_t len;
- int id;
- char *string;
+makeentry(char *buf, size_t len, int id, const char *string)
{
if (id < 0)
@@ -711,37 +950,28 @@ makeentry(buf, len, id, string)
static void
add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
{
- struct prefix *prefix;
+ struct prefix *pfx;
u_char ntopbuf[INET6_ADDRSTRLEN];
- if ((prefix = malloc(sizeof(*prefix))) == NULL) {
- syslog(LOG_ERR, "<%s> memory allocation failed",
- __func__);
- return; /* XXX: error or exit? */
- }
- memset(prefix, 0, sizeof(*prefix));
- prefix->prefix = ipr->ipr_prefix.sin6_addr;
- prefix->prefixlen = ipr->ipr_plen;
- prefix->validlifetime = ipr->ipr_vltime;
- prefix->preflifetime = ipr->ipr_pltime;
- prefix->onlinkflg = ipr->ipr_raf_onlink;
- prefix->autoconfflg = ipr->ipr_raf_auto;
- prefix->origin = PREFIX_FROM_DYNAMIC;
-
- insque(prefix, &rai->prefix);
- prefix->rainfo = rai;
+ ELM_MALLOC(pfx, return);
+ pfx->pfx_prefix = ipr->ipr_prefix.sin6_addr;
+ pfx->pfx_prefixlen = ipr->ipr_plen;
+ pfx->pfx_validlifetime = ipr->ipr_vltime;
+ pfx->pfx_preflifetime = ipr->ipr_pltime;
+ pfx->pfx_onlinkflg = ipr->ipr_raf_onlink;
+ pfx->pfx_autoconfflg = ipr->ipr_raf_auto;
+ pfx->pfx_origin = PREFIX_FROM_DYNAMIC;
- syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
- __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- ipr->ipr_plen, rai->ifname);
+ TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next);
+ pfx->pfx_rainfo = rai;
- /* free the previous packet */
- free(rai->ra_data);
- rai->ra_data = NULL;
+ syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
+ __func__,
+ inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), ipr->ipr_plen, rai->rai_ifname);
/* reconstruct the packet */
- rai->pfxs++;
+ rai->rai_pfxs++;
make_packet(rai);
}
@@ -751,30 +981,33 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
* The prefix must be in the list.
*/
void
-delete_prefix(struct prefix *prefix)
+delete_prefix(struct prefix *pfx)
{
u_char ntopbuf[INET6_ADDRSTRLEN];
- struct rainfo *rai = prefix->rainfo;
+ struct rainfo *rai;
- remque(prefix);
+ rai = pfx->pfx_rainfo;
+ TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next);
syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
- __func__, inet_ntop(AF_INET6, &prefix->prefix,
- ntopbuf, INET6_ADDRSTRLEN),
- prefix->prefixlen, rai->ifname);
- if (prefix->timer)
- rtadvd_remove_timer(&prefix->timer);
- free(prefix);
- rai->pfxs--;
+ __func__,
+ inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf,
+ sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname);
+ if (pfx->pfx_timer)
+ rtadvd_remove_timer(pfx->pfx_timer);
+ free(pfx);
+ rai->rai_pfxs--;
+ make_packet(rai);
}
void
-invalidate_prefix(struct prefix *prefix)
+invalidate_prefix(struct prefix *pfx)
{
u_char ntopbuf[INET6_ADDRSTRLEN];
struct timeval timo;
- struct rainfo *rai = prefix->rainfo;
+ struct rainfo *rai;
- if (prefix->timer) { /* sanity check */
+ rai = pfx->pfx_rainfo;
+ if (pfx->pfx_timer) { /* sanity check */
syslog(LOG_ERR,
"<%s> assumption failure: timer already exists",
__func__);
@@ -783,38 +1016,38 @@ invalidate_prefix(struct prefix *prefix)
syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, "
"will expire in %ld seconds", __func__,
- inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN),
- prefix->prefixlen, rai->ifname, (long)prefix_timo);
+ inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, sizeof(ntopbuf)),
+ pfx->pfx_prefixlen, rai->rai_ifname, (long)prefix_timo);
/* set the expiration timer */
- prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL);
- if (prefix->timer == NULL) {
+ pfx->pfx_timer = rtadvd_add_timer(prefix_timeout, NULL, pfx, NULL);
+ if (pfx->pfx_timer == NULL) {
syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. "
"remove the prefix", __func__);
- delete_prefix(prefix);
+ delete_prefix(pfx);
}
timo.tv_sec = prefix_timo;
timo.tv_usec = 0;
- rtadvd_set_timer(&timo, prefix->timer);
+ rtadvd_set_timer(&timo, pfx->pfx_timer);
}
static struct rtadvd_timer *
prefix_timeout(void *arg)
{
- struct prefix *prefix = (struct prefix *)arg;
-
- delete_prefix(prefix);
- return(NULL);
+ delete_prefix((struct prefix *)arg);
+
+ return (NULL);
}
void
-update_prefix(struct prefix * prefix)
+update_prefix(struct prefix *pfx)
{
u_char ntopbuf[INET6_ADDRSTRLEN];
- struct rainfo *rai = prefix->rainfo;
+ struct rainfo *rai;
- if (prefix->timer == NULL) { /* sanity check */
+ rai = pfx->pfx_rainfo;
+ if (pfx->pfx_timer == NULL) { /* sanity check */
syslog(LOG_ERR,
"<%s> assumption failure: timer does not exist",
__func__);
@@ -822,11 +1055,12 @@ update_prefix(struct prefix * prefix)
}
syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s",
- __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf,
- INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname);
+ __func__, inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf,
+ sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname);
/* stop the expiration timer */
- rtadvd_remove_timer(&prefix->timer);
+ rtadvd_remove_timer(pfx->pfx_timer);
+ pfx->pfx_timer = NULL;
}
/*
@@ -842,13 +1076,13 @@ init_prefix(struct in6_prefixreq *ipr)
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__,
- strerror(errno));
+ strerror(errno));
exit(1);
}
if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__,
- strerror(errno));
+ strerror(errno));
ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
@@ -860,22 +1094,22 @@ init_prefix(struct in6_prefixreq *ipr)
u_char ntopbuf[INET6_ADDRSTRLEN];
syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is"
- "lower than PR_ORIG_RR(router renumbering)."
- "This should not happen if I am router", __func__,
- inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
- sizeof(ntopbuf)), ipr->ipr_origin);
+ "lower than PR_ORIG_RR(router renumbering)."
+ "This should not happen if I am router", __func__,
+ inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), ipr->ipr_origin);
close(s);
- return 1;
+ return (1);
}
close(s);
- return 0;
+ return (0);
#else
ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
ipr->ipr_raf_onlink = 1;
ipr->ipr_raf_auto = 1;
- return 0;
+ return (0);
#endif
}
@@ -887,8 +1121,8 @@ make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
memset(&ipr, 0, sizeof(ipr));
if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't"
- "exist. This should not happen! %s", __func__,
- ifindex, strerror(errno));
+ "exist. This should not happen! %s", __func__,
+ ifindex, strerror(errno));
exit(1);
}
ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
@@ -902,7 +1136,7 @@ make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
}
void
-make_packet(struct rainfo *rainfo)
+make_packet(struct rainfo *rai)
{
size_t packlen, lladdroptlen = 0;
char *buf;
@@ -913,45 +1147,68 @@ make_packet(struct rainfo *rainfo)
struct nd_opt_route_info *ndopt_rti;
struct rtinfo *rti;
#endif
+ struct nd_opt_rdnss *ndopt_rdnss;
+ struct rdnss *rdn;
+ struct nd_opt_dnssl *ndopt_dnssl;
+ struct dnssl *dns;
+ size_t len;
struct prefix *pfx;
/* calculate total length */
packlen = sizeof(struct nd_router_advert);
- if (rainfo->advlinkopt) {
- if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
+ if (rai->rai_advlinkopt) {
+ if ((lladdroptlen = lladdropt_length(rai->rai_sdl)) == 0) {
syslog(LOG_INFO,
- "<%s> link-layer address option has"
- " null length on %s. Treat as not included.",
- __func__, rainfo->ifname);
- rainfo->advlinkopt = 0;
+ "<%s> link-layer address option has"
+ " null length on %s. Treat as not included.",
+ __func__, rai->rai_ifname);
+ rai->rai_advlinkopt = 0;
}
packlen += lladdroptlen;
}
- if (rainfo->pfxs)
- packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
- if (rainfo->linkmtu)
+ if (rai->rai_pfxs)
+ packlen += sizeof(struct nd_opt_prefix_info) * rai->rai_pfxs;
+ if (rai->rai_linkmtu)
packlen += sizeof(struct nd_opt_mtu);
#ifdef ROUTEINFO
- for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next)
- packlen += sizeof(struct nd_opt_route_info) +
- ((rti->prefixlen + 0x3f) >> 6) * 8;
+ TAILQ_FOREACH(rti, &rai->rai_route, rti_next)
+ packlen += sizeof(struct nd_opt_route_info) +
+ ((rti->rti_prefixlen + 0x3f) >> 6) * 8;
#endif
+ TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
+ struct rdnss_addr *rdna;
+
+ packlen += sizeof(struct nd_opt_rdnss);
+ TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next)
+ packlen += sizeof(rdna->ra_dns);
+ }
+ TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
+ struct dnssl_addr *dnsa;
+
+ packlen += sizeof(struct nd_opt_dnssl);
+ len = 0;
+ TAILQ_FOREACH(dnsa, &dns->dn_list, da_next)
+ len += dnsa->da_len;
+ /* A zero octet and 8 octet boundary */
+ len++;
+ len += (len % 8) ? 8 - len % 8 : 0;
+
+ packlen += len;
+ }
/* allocate memory for the packet */
if ((buf = malloc(packlen)) == NULL) {
syslog(LOG_ERR,
- "<%s> can't get enough memory for an RA packet",
- __func__);
+ "<%s> can't get enough memory for an RA packet",
+ __func__);
exit(1);
}
- if (rainfo->ra_data) {
- /* free the previous packet */
- free(rainfo->ra_data);
- rainfo->ra_data = NULL;
- }
- rainfo->ra_data = buf;
+ memset(buf, 0, packlen);
+ if (rai->rai_ra_data) /* Free old data if any. */
+ free(rai->rai_ra_data);
+ rai->rai_ra_data = buf;
/* XXX: what if packlen > 576? */
- rainfo->ra_datalen = packlen;
+ rai->rai_ra_datalen = packlen;
/*
* construct the packet
@@ -960,71 +1217,70 @@ make_packet(struct rainfo *rainfo)
ra->nd_ra_type = ND_ROUTER_ADVERT;
ra->nd_ra_code = 0;
ra->nd_ra_cksum = 0;
- ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
+ ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rai->rai_hoplimit);
ra->nd_ra_flags_reserved = 0; /* just in case */
/*
* XXX: the router preference field, which is a 2-bit field, should be
* initialized before other fields.
*/
- ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref;
+ ra->nd_ra_flags_reserved = 0xff & rai->rai_rtpref;
ra->nd_ra_flags_reserved |=
- rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
+ rai->rai_managedflg ? ND_RA_FLAG_MANAGED : 0;
ra->nd_ra_flags_reserved |=
- rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
- ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
- ra->nd_ra_reachable = htonl(rainfo->reachabletime);
- ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
+ rai->rai_otherflg ? ND_RA_FLAG_OTHER : 0;
+ ra->nd_ra_router_lifetime = htons(rai->rai_lifetime);
+ ra->nd_ra_reachable = htonl(rai->rai_reachabletime);
+ ra->nd_ra_retransmit = htonl(rai->rai_retranstimer);
buf += sizeof(*ra);
- if (rainfo->advlinkopt) {
- lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
+ if (rai->rai_advlinkopt) {
+ lladdropt_fill(rai->rai_sdl, (struct nd_opt_hdr *)buf);
buf += lladdroptlen;
}
- if (rainfo->linkmtu) {
+ if (rai->rai_linkmtu) {
ndopt_mtu = (struct nd_opt_mtu *)buf;
ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
ndopt_mtu->nd_opt_mtu_len = 1;
ndopt_mtu->nd_opt_mtu_reserved = 0;
- ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu);
+ ndopt_mtu->nd_opt_mtu_mtu = htonl(rai->rai_linkmtu);
buf += sizeof(struct nd_opt_mtu);
}
- for (pfx = rainfo->prefix.next;
- pfx != &rainfo->prefix; pfx = pfx->next) {
+ TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
u_int32_t vltime, pltime;
struct timeval now;
ndopt_pi = (struct nd_opt_prefix_info *)buf;
ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
ndopt_pi->nd_opt_pi_len = 4;
- ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
+ ndopt_pi->nd_opt_pi_prefix_len = pfx->pfx_prefixlen;
ndopt_pi->nd_opt_pi_flags_reserved = 0;
- if (pfx->onlinkflg)
+ if (pfx->pfx_onlinkflg)
ndopt_pi->nd_opt_pi_flags_reserved |=
ND_OPT_PI_FLAG_ONLINK;
- if (pfx->autoconfflg)
+ if (pfx->pfx_autoconfflg)
ndopt_pi->nd_opt_pi_flags_reserved |=
ND_OPT_PI_FLAG_AUTO;
- if (pfx->timer)
+ if (pfx->pfx_timer)
vltime = 0;
else {
- if (pfx->vltimeexpire || pfx->pltimeexpire)
+ if (pfx->pfx_vltimeexpire || pfx->pfx_pltimeexpire)
gettimeofday(&now, NULL);
- if (pfx->vltimeexpire == 0)
- vltime = pfx->validlifetime;
+ if (pfx->pfx_vltimeexpire == 0)
+ vltime = pfx->pfx_validlifetime;
else
- vltime = (pfx->vltimeexpire > now.tv_sec) ?
- pfx->vltimeexpire - now.tv_sec : 0;
+ vltime = (pfx->pfx_vltimeexpire > now.tv_sec) ?
+ pfx->pfx_vltimeexpire - now.tv_sec : 0;
}
- if (pfx->timer)
+ if (pfx->pfx_timer)
pltime = 0;
else {
- if (pfx->pltimeexpire == 0)
- pltime = pfx->preflifetime;
+ if (pfx->pfx_pltimeexpire == 0)
+ pltime = pfx->pfx_preflifetime;
else
- pltime = (pfx->pltimeexpire > now.tv_sec) ?
- pfx->pltimeexpire - now.tv_sec : 0;
+ pltime = (pfx->pfx_pltimeexpire > now.tv_sec) ?
+ pfx->pfx_pltimeexpire - now.tv_sec : 0;
}
if (vltime < pltime) {
/*
@@ -1036,45 +1292,72 @@ make_packet(struct rainfo *rainfo)
ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
ndopt_pi->nd_opt_pi_reserved2 = 0;
- ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
+ ndopt_pi->nd_opt_pi_prefix = pfx->pfx_prefix;
buf += sizeof(struct nd_opt_prefix_info);
}
#ifdef ROUTEINFO
- for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) {
- u_int8_t psize = (rti->prefixlen + 0x3f) >> 6;
+ TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
+ u_int8_t psize = (rti->rti_prefixlen + 0x3f) >> 6;
ndopt_rti = (struct nd_opt_route_info *)buf;
ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
ndopt_rti->nd_opt_rti_len = 1 + psize;
- ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
- ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
- ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime);
- memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
+ ndopt_rti->nd_opt_rti_prefixlen = rti->rti_prefixlen;
+ ndopt_rti->nd_opt_rti_flags = 0xff & rti->rti_rtpref;
+ ndopt_rti->nd_opt_rti_lifetime = htonl(rti->rti_ltime);
+ memcpy(ndopt_rti + 1, &rti->rti_prefix, psize * 8);
buf += sizeof(struct nd_opt_route_info) + psize * 8;
}
#endif
+ TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
+ struct rdnss_addr *rdna;
+
+ ndopt_rdnss = (struct nd_opt_rdnss *)buf;
+ ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+ ndopt_rdnss->nd_opt_rdnss_len = 0;
+ ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+ ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdn->rd_ltime);
+ buf += sizeof(struct nd_opt_rdnss);
+
+ TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
+ memcpy(buf, &rdna->ra_dns, sizeof(rdna->ra_dns));
+ buf += sizeof(rdna->ra_dns);
+ }
+ /* Length field should be in 8 octets */
+ ndopt_rdnss->nd_opt_rdnss_len = (buf - (char *)ndopt_rdnss) / 8;
- return;
-}
+ syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__,
+ ndopt_rdnss->nd_opt_rdnss_len);
+ }
+ TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
+ struct dnssl_addr *dnsa;
+
+ ndopt_dnssl = (struct nd_opt_dnssl *)buf;
+ ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
+ ndopt_dnssl->nd_opt_dnssl_len = 0;
+ ndopt_dnssl->nd_opt_dnssl_reserved = 0;
+ ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dns->dn_ltime);
+ buf += sizeof(*ndopt_dnssl);
+
+ TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
+ memcpy(buf, dnsa->da_dom, dnsa->da_len);
+ buf += dnsa->da_len;
+ }
-static int
-getinet6sysctl(int code)
-{
- int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
- int value;
- size_t size;
-
- mib[3] = code;
- size = sizeof(value);
- if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
- < 0) {
- syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s",
- __func__, code,
- strerror(errno));
- return(-1);
+ /* A zero octet after encoded DNS server list. */
+ *buf++ = '\0';
+
+ /* Padding to next 8 octets boundary */
+ len = buf - (char *)ndopt_dnssl;
+ len += (len % 8) ? 8 - len % 8 : 0;
+
+ /* Length field must be in 8 octets */
+ ndopt_dnssl->nd_opt_dnssl_len = len / 8;
+
+ syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__,
+ ndopt_dnssl->nd_opt_dnssl_len);
}
- else
- return(value);
+ return;
}
diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h
index 2d02b8a..01886a6 100644
--- a/usr.sbin/rtadvd/config.h
+++ b/usr.sbin/rtadvd/config.h
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -30,7 +30,9 @@
* SUCH DAMAGE.
*/
-extern void getconfig(char *);
+extern int getconfig(int);
+extern int rmconfig(int);
+extern int loadconfig(char *[], const int);
extern void delete_prefix(struct prefix *);
extern void invalidate_prefix(struct prefix *);
extern void update_prefix(struct prefix *);
@@ -45,3 +47,5 @@ extern void get_prefix(struct rainfo *);
*/
#define MAXPREFIX 100
#define MAXROUTE 100
+#define MAXRDNSSENT 100
+#define MAXDNSSLENT 100
diff --git a/usr.sbin/rtadvd/dump.c b/usr.sbin/rtadvd/dump.c
index d37f5db..fac3fb2 100644
--- a/usr.sbin/rtadvd/dump.c
+++ b/usr.sbin/rtadvd/dump.c
@@ -4,7 +4,7 @@
/*
* Copyright (C) 2000 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -45,6 +45,7 @@
#include <arpa/inet.h>
+#include <netdb.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
@@ -63,8 +64,9 @@ extern struct rainfo *ralist;
static char *ether_str(struct sockaddr_dl *);
static void if_dump(void);
+static size_t dname_labeldec(char *, size_t, const char *);
-static char *rtpref_str[] = {
+static const char *rtpref_str[] = {
"medium", /* 00 */
"high", /* 01 */
"rsv", /* 10 */
@@ -72,8 +74,7 @@ static char *rtpref_str[] = {
};
static char *
-ether_str(sdl)
- struct sockaddr_dl *sdl;
+ether_str(struct sockaddr_dl *sdl)
{
static char hbuf[32];
u_char *cp;
@@ -85,84 +86,86 @@ ether_str(sdl)
} else
snprintf(hbuf, sizeof(hbuf), "NONE");
- return(hbuf);
+ return (hbuf);
}
static void
-if_dump()
+if_dump(void)
{
struct rainfo *rai;
struct prefix *pfx;
#ifdef ROUTEINFO
struct rtinfo *rti;
#endif
+ struct rdnss *rdn;
+ struct dnssl *dns;
char prefixbuf[INET6_ADDRSTRLEN];
- int first;
struct timeval now;
gettimeofday(&now, NULL); /* XXX: unused in most cases */
- for (rai = ralist; rai; rai = rai->next) {
- fprintf(fp, "%s:\n", rai->ifname);
+ TAILQ_FOREACH(rai, &railist, rai_next) {
+ fprintf(fp, "%s:\n", rai->rai_ifname);
fprintf(fp, " Status: %s\n",
- (iflist[rai->ifindex]->ifm_flags & IFF_UP) ? "UP" :
- "DOWN");
+ (iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) ? "UP" :
+ "DOWN");
/* control information */
- if (rai->lastsent.tv_sec) {
+ if (rai->rai_lastsent.tv_sec) {
/* note that ctime() appends CR by itself */
fprintf(fp, " Last RA sent: %s",
- ctime((time_t *)&rai->lastsent.tv_sec));
+ ctime((time_t *)&rai->rai_lastsent.tv_sec));
}
- if (rai->timer) {
+ if (rai->rai_timer)
fprintf(fp, " Next RA will be sent: %s",
- ctime((time_t *)&rai->timer->tm.tv_sec));
- }
+ ctime((time_t *)&rai->rai_timer->rat_tm.tv_sec));
else
fprintf(fp, " RA timer is stopped");
fprintf(fp, " waits: %d, initcount: %d\n",
- rai->waiting, rai->initcounter);
+ rai->rai_waiting, rai->rai_initcounter);
/* statistics */
fprintf(fp, " statistics: RA(out/in/inconsistent): "
"%llu/%llu/%llu, ",
- (unsigned long long)rai->raoutput,
- (unsigned long long)rai->rainput,
- (unsigned long long)rai->rainconsistent);
+ (unsigned long long)rai->rai_raoutput,
+ (unsigned long long)rai->rai_rainput,
+ (unsigned long long)rai->rai_rainconsistent);
fprintf(fp, "RS(input): %llu\n",
- (unsigned long long)rai->rsinput);
+ (unsigned long long)rai->rai_rsinput);
/* interface information */
- if (rai->advlinkopt)
+ if (rai->rai_advlinkopt)
fprintf(fp, " Link-layer address: %s\n",
- ether_str(rai->sdl));
- fprintf(fp, " MTU: %d\n", rai->phymtu);
+ ether_str(rai->rai_sdl));
+ fprintf(fp, " MTU: %d\n", rai->rai_phymtu);
/* Router configuration variables */
fprintf(fp, " DefaultLifetime: %d, MaxAdvInterval: %d, "
- "MinAdvInterval: %d\n", rai->lifetime, rai->maxinterval,
- rai->mininterval);
- fprintf(fp, " Flags: %s%s%s, ",
- rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", "");
+ "MinAdvInterval: %d\n", rai->rai_lifetime,
+ rai->rai_maxinterval, rai->rai_mininterval);
+ fprintf(fp, " Flags: ");
+ if (rai->rai_managedflg || rai->rai_otherflg) {
+ fprintf(fp, "%s", rai->rai_managedflg ? "M" : "");
+ fprintf(fp, "%s", rai->rai_otherflg ? "O" : "");
+ } else
+ fprintf(fp, "<none>");
+ fprintf(fp, ", ");
fprintf(fp, "Preference: %s, ",
- rtpref_str[(rai->rtpref >> 3) & 0xff]);
- fprintf(fp, "MTU: %d\n", rai->linkmtu);
+ rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
+ fprintf(fp, "MTU: %d\n", rai->rai_linkmtu);
fprintf(fp, " ReachableTime: %d, RetransTimer: %d, "
- "CurHopLimit: %d\n", rai->reachabletime,
- rai->retranstimer, rai->hoplimit);
- if (rai->clockskew)
+ "CurHopLimit: %d\n", rai->rai_reachabletime,
+ rai->rai_retranstimer, rai->rai_hoplimit);
+ if (rai->rai_clockskew)
fprintf(fp, " Clock skew: %ldsec\n",
- rai->clockskew);
- for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix;
- pfx = pfx->next) {
- if (first) {
+ rai->rai_clockskew);
+ TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
+ if (pfx == TAILQ_FIRST(&rai->rai_prefix))
fprintf(fp, " Prefixes:\n");
- first = 0;
- }
fprintf(fp, " %s/%d(",
- inet_ntop(AF_INET6, &pfx->prefix, prefixbuf,
- sizeof(prefixbuf)), pfx->prefixlen);
- switch (pfx->origin) {
+ inet_ntop(AF_INET6, &pfx->pfx_prefix, prefixbuf,
+ sizeof(prefixbuf)), pfx->pfx_prefixlen);
+ switch (pfx->pfx_origin) {
case PREFIX_FROM_KERNEL:
fprintf(fp, "KERNEL, ");
break;
@@ -173,36 +176,42 @@ if_dump()
fprintf(fp, "DYNAMIC, ");
break;
}
- if (pfx->validlifetime == ND6_INFINITE_LIFETIME)
+ if (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME)
fprintf(fp, "vltime: infinity");
else
fprintf(fp, "vltime: %ld",
- (long)pfx->validlifetime);
- if (pfx->vltimeexpire != 0)
- fprintf(fp, "(decr,expire %ld), ", (long)
- pfx->vltimeexpire > now.tv_sec ?
- pfx->vltimeexpire - now.tv_sec : 0);
+ (long)pfx->pfx_validlifetime);
+ if (pfx->pfx_vltimeexpire != 0)
+ fprintf(fp, "(decr,expire %ld), ",
+ (long)pfx->pfx_vltimeexpire > now.tv_sec ?
+ (long)pfx->pfx_vltimeexpire - now.tv_sec :
+ 0);
else
fprintf(fp, ", ");
- if (pfx->preflifetime == ND6_INFINITE_LIFETIME)
+ if (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME)
fprintf(fp, "pltime: infinity");
else
fprintf(fp, "pltime: %ld",
- (long)pfx->preflifetime);
- if (pfx->pltimeexpire != 0)
- fprintf(fp, "(decr,expire %ld), ", (long)
- pfx->pltimeexpire > now.tv_sec ?
- pfx->pltimeexpire - now.tv_sec : 0);
+ (long)pfx->pfx_preflifetime);
+ if (pfx->pfx_pltimeexpire != 0)
+ fprintf(fp, "(decr,expire %ld), ",
+ (long)pfx->pfx_pltimeexpire > now.tv_sec ?
+ (long)pfx->pfx_pltimeexpire - now.tv_sec :
+ 0);
else
fprintf(fp, ", ");
- fprintf(fp, "flags: %s%s%s",
- pfx->onlinkflg ? "L" : "",
- pfx->autoconfflg ? "A" : "",
- "");
- if (pfx->timer) {
+ fprintf(fp, "flags: ");
+ if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
+ fprintf(fp, "%s",
+ pfx->pfx_onlinkflg ? "L" : "");
+ fprintf(fp, "%s",
+ pfx->pfx_autoconfflg ? "A" : "");
+ } else
+ fprintf(fp, "<none>");
+ if (pfx->pfx_timer) {
struct timeval *rest;
- rest = rtadvd_timer_rest(pfx->timer);
+ rest = rtadvd_timer_rest(pfx->pfx_timer);
if (rest) { /* XXX: what if not? */
fprintf(fp, ", expire in: %ld",
(long)rest->tv_sec);
@@ -211,31 +220,64 @@ if_dump()
fprintf(fp, ")\n");
}
#ifdef ROUTEINFO
- for (first = 1, rti = rai->route.next; rti != &rai->route;
- rti = rti->next) {
- if (first) {
+ TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
+ if (rti == TAILQ_FIRST(&rai->rai_route))
fprintf(fp, " Route Information:\n");
- first = 0;
- }
fprintf(fp, " %s/%d (",
- inet_ntop(AF_INET6, &rti->prefix,
- prefixbuf, sizeof(prefixbuf)),
- rti->prefixlen);
+ inet_ntop(AF_INET6, &rti->rti_prefix,
+ prefixbuf, sizeof(prefixbuf)),
+ rti->rti_prefixlen);
fprintf(fp, "preference: %s, ",
- rtpref_str[0xff & (rti->rtpref >> 3)]);
- if (rti->ltime == ND6_INFINITE_LIFETIME)
+ rtpref_str[0xff & (rti->rti_rtpref >> 3)]);
+ if (rti->rti_ltime == ND6_INFINITE_LIFETIME)
fprintf(fp, "lifetime: infinity");
else
- fprintf(fp, "lifetime: %ld", (long)rti->ltime);
+ fprintf(fp, "lifetime: %ld",
+ (long)rti->rti_ltime);
fprintf(fp, ")\n");
}
#endif
+ TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
+ struct rdnss_addr *rdna;
+
+ if (rdn == TAILQ_FIRST(&rai->rai_rdnss))
+ fprintf(fp, " Recursive DNS servers:\n"
+ " Lifetime\tServers\n");
+
+ fprintf(fp, " %8u\t", rdn->rd_ltime);
+ TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
+ inet_ntop(AF_INET6, &rdna->ra_dns,
+ prefixbuf, sizeof(prefixbuf));
+
+ if (rdna != TAILQ_FIRST(&rdn->rd_list))
+ fprintf(fp, " \t");
+ fprintf(fp, "%s\n", prefixbuf);
+ }
+ fprintf(fp, "\n");
+ }
+
+ TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
+ struct dnssl_addr *dnsa;
+ char buf[NI_MAXHOST];
+
+ if (dns == TAILQ_FIRST(&rai->rai_dnssl))
+ fprintf(fp, " DNS search list:\n"
+ " Lifetime\tDomains\n");
+
+ fprintf(fp, " %8u\t", dns->dn_ltime);
+ TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
+ dname_labeldec(buf, sizeof(buf), dnsa->da_dom);
+ if (dnsa != TAILQ_FIRST(&dns->dn_list))
+ fprintf(fp, " \t");
+ fprintf(fp, "%s(%d)\n", buf, dnsa->da_len);
+ }
+ fprintf(fp, "\n");
+ }
}
}
void
-rtadvd_dump_file(dumpfile)
- char *dumpfile;
+rtadvd_dump_file(const char *dumpfile)
{
syslog(LOG_DEBUG, "<%s> dump current status to %s", __func__,
dumpfile);
@@ -250,3 +292,30 @@ rtadvd_dump_file(dumpfile)
fclose(fp);
}
+
+/* Decode domain name label encoding in RFC 1035 Section 3.1 */
+static size_t
+dname_labeldec(char *dst, size_t dlen, const char *src)
+{
+ size_t len;
+ const char *src_origin;
+ const char *src_last;
+ const char *dst_origin;
+
+ src_origin = src;
+ src_last = strchr(src, '\0');
+ dst_origin = dst;
+ memset(dst, '\0', dlen);
+ while (src && (len = (uint8_t)(*src++) & 0x3f) &&
+ (src + len) <= src_last) {
+ if (dst != dst_origin)
+ *dst++ = '.';
+ syslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
+ memcpy(dst, src, len);
+ src += len;
+ dst += len;
+ }
+ *dst = '\0';
+
+ return (src - src_origin);
+}
diff --git a/usr.sbin/rtadvd/dump.h b/usr.sbin/rtadvd/dump.h
index c8a6b22..8696e13 100644
--- a/usr.sbin/rtadvd/dump.h
+++ b/usr.sbin/rtadvd/dump.h
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -30,4 +30,4 @@
* SUCH DAMAGE.
*/
-extern void rtadvd_dump_file(char *);
+extern void rtadvd_dump_file(const char *);
diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c
index d8ed088..302c334 100644
--- a/usr.sbin/rtadvd/if.c
+++ b/usr.sbin/rtadvd/if.c
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -44,34 +44,35 @@
#include <netinet/icmp6.h>
#include <unistd.h>
#include <errno.h>
+#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "rtadvd.h"
#include "if.h"
-#define ROUNDUP(a, size) \
+#define ROUNDUP(a, size) \
(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
-#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
- ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
- sizeof(u_long)) :\
- sizeof(u_long)))
+#define NEXT_SA(ap) \
+ (ap) = (struct sockaddr *)((caddr_t)(ap) + \
+ ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \
+ sizeof(u_long)))
struct if_msghdr **iflist;
int iflist_init_ok;
size_t ifblock_size;
char *ifblock;
-static void get_iflist(char **buf, size_t *size);
-static void parse_iflist(struct if_msghdr ***ifmlist_p, char *buf,
- size_t bufsize);
+static void get_iflist(char **buf, size_t *size);
+static void parse_iflist(struct if_msghdr ***ifmlist_p,
+ char *buf, size_t bufsize);
static void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
int i;
-
+
for (i = 0; i < RTAX_MAX; i++) {
if (addrs & (1 << i)) {
rti_info[i] = sa;
@@ -93,12 +94,12 @@ if_nametosdl(char *name)
struct sockaddr_dl *sdl = NULL, *ret_sdl;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
- return(NULL);
+ return (NULL);
if ((buf = malloc(len)) == NULL)
- return(NULL);
+ return (NULL);
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
free(buf);
- return(NULL);
+ return (NULL);
}
lim = buf + len;
@@ -124,7 +125,7 @@ if_nametosdl(char *name)
if (next == lim) {
/* search failed */
free(buf);
- return(NULL);
+ return (NULL);
}
if ((ret_sdl = malloc(sdl->sdl_len)) == NULL)
@@ -133,7 +134,7 @@ if_nametosdl(char *name)
end:
free(buf);
- return(ret_sdl);
+ return (ret_sdl);
}
int
@@ -144,7 +145,7 @@ if_getmtu(char *name)
u_long mtu = 0;
if (getifaddrs(&ifap) < 0)
- return(0);
+ return (0);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifa->ifa_name, name) == 0) {
ifd = ifa->ifa_data;
@@ -161,14 +162,14 @@ if_getmtu(char *name)
int s;
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
- return(0);
+ return (0);
ifr.ifr_addr.sa_family = AF_INET6;
strncpy(ifr.ifr_name, name,
sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
close(s);
- return(0);
+ return (0);
}
close(s);
@@ -176,7 +177,7 @@ if_getmtu(char *name)
}
#endif
- return(mtu);
+ return (mtu);
}
/* give interface index and its old flags, then new flags returned */
@@ -188,14 +189,14 @@ if_getflags(int ifindex, int oifflags)
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__,
- strerror(errno));
+ strerror(errno));
return (oifflags & ~IFF_UP);
}
if_indextoname(ifindex, ifr.ifr_name);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s",
- __func__, ifr.ifr_name);
+ __func__, ifr.ifr_name);
close(s);
return (oifflags & ~IFF_UP);
}
@@ -209,9 +210,9 @@ lladdropt_length(struct sockaddr_dl *sdl)
{
switch (sdl->sdl_type) {
case IFT_ETHER:
- return(ROUNDUP8(ETHER_ADDR_LEN + 2));
+ return (ROUNDUP8(ETHER_ADDR_LEN + 2));
default:
- return(0);
+ return (0);
}
}
@@ -238,16 +239,15 @@ lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
}
int
-rtbuf_len()
+rtbuf_len(void)
{
size_t len;
-
int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
- return(-1);
+ return (-1);
- return(len);
+ return (len);
}
#define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
@@ -267,14 +267,21 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
/* just for safety */
if (!rtm->rtm_msglen) {
syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
- "(buf=%p lim=%p rtm=%p)", __func__,
- buf, lim, rtm);
+ "(buf=%p lim=%p rtm=%p)", __func__,
+ buf, lim, rtm);
break;
}
- if (FILTER_MATCH(rtm->rtm_type, filter) == 0) {
+ if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) {
+ syslog(LOG_WARNING,
+ "<%s> routing message version mismatch "
+ "(buf=%p lim=%p rtm=%p)", __func__,
+ buf, lim, rtm);
continue;
}
+ if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
+ continue;
+
switch (rtm->rtm_type) {
case RTM_GET:
case RTM_ADD:
@@ -328,6 +335,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
return (char *)rtm;
/* NOTREACHED */
case RTM_IFINFO:
+ case RTM_IFANNOUNCE:
/* found */
*lenp = rtm->rtm_msglen;
return (char *)rtm;
@@ -335,7 +343,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
}
}
- return (char *)rtm;
+ return ((char *)rtm);
}
#undef FILTER_MATCH
@@ -348,7 +356,7 @@ get_addr(char *buf)
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
- return(&SIN6(rti_info[RTAX_DST])->sin6_addr);
+ return (&SIN6(rti_info[RTAX_DST])->sin6_addr);
}
int
@@ -360,7 +368,7 @@ get_rtm_ifindex(char *buf)
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
- return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
+ return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
}
int
@@ -393,7 +401,7 @@ get_prefixlen(char *buf)
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
struct sockaddr *sa, *rti_info[RTAX_MAX];
u_char *p, *lim;
-
+
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
sa = rti_info[RTAX_NETMASK];
@@ -437,11 +445,11 @@ prefixlen(u_char *p, u_char *lim)
case 0x00:
break;
default:
- return(-1);
+ return (-1);
}
}
- return(masklen);
+ return (masklen);
}
int
@@ -449,7 +457,7 @@ rtmsg_type(char *buf)
{
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
- return(rtm->rtm_type);
+ return (rtm->rtm_type);
}
int
@@ -457,7 +465,7 @@ rtmsg_len(char *buf)
{
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
- return(rtm->rtm_msglen);
+ return (rtm->rtm_msglen);
}
int
@@ -465,7 +473,7 @@ ifmsg_len(char *buf)
{
struct if_msghdr *ifm = (struct if_msghdr *)buf;
- return(ifm->ifm_msglen);
+ return (ifm->ifm_msglen);
}
/*
@@ -486,7 +494,7 @@ get_iflist(char **buf, size_t *size)
if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) {
syslog(LOG_ERR, "<%s> sysctl: iflist size get failed",
- __func__);
+ __func__);
exit(1);
}
if ((*buf = malloc(*size)) == NULL) {
@@ -495,7 +503,7 @@ get_iflist(char **buf, size_t *size)
}
if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
syslog(LOG_ERR, "<%s> sysctl: iflist get failed",
- __func__);
+ __func__);
exit(1);
}
return;
@@ -529,8 +537,8 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
if (ifm->ifm_msglen == 0) {
syslog(LOG_WARNING, "<%s> ifm_msglen is 0 "
- "(buf=%p lim=%p ifm=%p)", __func__,
- buf, lim, ifm);
+ "(buf=%p lim=%p ifm=%p)", __func__,
+ buf, lim, ifm);
return;
}
@@ -538,10 +546,10 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
(*ifmlist_p)[ifm->ifm_index] = ifm;
} else {
syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n"
- "expected %d, got %d\n msglen = %d\n"
- "buf:%p, ifm:%p, lim:%p\n",
- RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
- buf, ifm, lim);
+ "expected %d, got %d\n msglen = %d\n"
+ "buf:%p, ifm:%p, lim:%p\n",
+ RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
+ buf, ifm, lim);
exit (1);
}
for (ifam = (struct ifa_msghdr *)
@@ -552,8 +560,8 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
/* just for safety */
if (!ifam->ifam_msglen) {
syslog(LOG_WARNING, "<%s> ifa_msglen is 0 "
- "(buf=%p lim=%p ifam=%p)", __func__,
- buf, lim, ifam);
+ "(buf=%p lim=%p ifam=%p)", __func__,
+ buf, lim, ifam);
return;
}
if (ifam->ifam_type != RTM_NEWADDR)
@@ -564,8 +572,11 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
}
void
-init_iflist()
+init_iflist(void)
{
+ syslog(LOG_DEBUG,
+ "<%s> generate iflist.", __func__);
+
if (ifblock) {
free(ifblock);
ifblock_size = 0;
diff --git a/usr.sbin/rtadvd/if.h b/usr.sbin/rtadvd/if.h
index 216eaa0..8728e19 100644
--- a/usr.sbin/rtadvd/if.h
+++ b/usr.sbin/rtadvd/if.h
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
diff --git a/usr.sbin/rtadvd/pathnames.h b/usr.sbin/rtadvd/pathnames.h
index 3afee55..13329da 100644
--- a/usr.sbin/rtadvd/pathnames.h
+++ b/usr.sbin/rtadvd/pathnames.h
@@ -1,4 +1,7 @@
/* $KAME: pathnames.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */
/* $FreeBSD$ */
-#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
+#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
+#define _PATH_RTADVDDUMP "/var/run/rtadvd.dump"
+#define _PATH_RTADVDPID "/var/run/rtadvd.pid"
+
diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c
index aafa0f9..660ed53 100644
--- a/usr.sbin/rtadvd/rrenum.c
+++ b/usr.sbin/rtadvd/rrenum.c
@@ -45,6 +45,7 @@
#include <arpa/inet.h>
#include <errno.h>
+#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
@@ -74,7 +75,7 @@ static int s = -1;
/*
* Check validity of a Prefix Control Operation(PCO).
- * Return 0 on success, 1 on failure.
+ * return 0 on success, 1 on failure.
*/
static int
rr_pco_check(int len, struct rr_pco_match *rpm)
@@ -86,8 +87,8 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */
(rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */
syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3",
- __func__, rpm->rpm_len);
- return 1;
+ __func__, rpm->rpm_len);
+ return (1);
}
/* rpm->rpm_code must be valid value */
switch (rpm->rpm_code) {
@@ -97,14 +98,14 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
break;
default:
syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __func__,
- rpm->rpm_code);
- return 1;
+ rpm->rpm_code);
+ return (1);
}
/* rpm->rpm_matchlen must be 0 to 128 inclusive */
if (rpm->rpm_matchlen > 128) {
syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128",
- __func__, rpm->rpm_matchlen);
- return 1;
+ __func__, rpm->rpm_matchlen);
+ return (1);
}
/*
@@ -126,23 +127,22 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
*/
if (checklen > 128) {
syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and"
- " rpu_keeplen %d is %d(over 128)",
- __func__, rpu->rpu_uselen,
- rpu->rpu_keeplen,
- rpu->rpu_uselen + rpu->rpu_keeplen);
- return 1;
+ " rpu_keeplen %d is %d(over 128)",
+ __func__, rpu->rpu_uselen, rpu->rpu_keeplen,
+ rpu->rpu_uselen + rpu->rpu_keeplen);
+ return (1);
}
}
- return 0;
+ return (0);
}
static void
do_use_prefix(int len, struct rr_pco_match *rpm,
- struct in6_rrenumreq *irr, int ifindex)
+ struct in6_rrenumreq *irr, int ifindex)
{
struct rr_pco_use *rpu, *rpulim;
struct rainfo *rai;
- struct prefix *pp;
+ struct prefix *pfx;
rpu = (struct rr_pco_use *)(rpm + 1);
rpulim = (struct rr_pco_use *)((char *)rpm + len);
@@ -164,7 +164,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
errno != EADDRNOTAVAIL)
syslog(LOG_ERR, "<%s> ioctl: %s", __func__,
- strerror(errno));
+ strerror(errno));
return;
}
@@ -176,19 +176,23 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
irr->irr_u_uselen = rpu->rpu_uselen;
irr->irr_u_keeplen = rpu->rpu_keeplen;
irr->irr_raf_mask_onlink =
- !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
+ !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
irr->irr_raf_mask_auto =
- !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
+ !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
irr->irr_vltime = ntohl(rpu->rpu_vltime);
irr->irr_pltime = ntohl(rpu->rpu_pltime);
irr->irr_raf_onlink =
- (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 0 : 1;
+ (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ?
+ 0 : 1;
irr->irr_raf_auto =
- (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 0 : 1;
+ (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ?
+ 0 : 1;
irr->irr_rrf_decrvalid =
- (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 0 : 1;
+ (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ?
+ 0 : 1;
irr->irr_rrf_decrprefd =
- (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 0 : 1;
+ (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ?
+ 0 : 1;
irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix);
irr->irr_useprefix.sin6_family = AF_INET6;
irr->irr_useprefix.sin6_addr = rpu->rpu_prefix;
@@ -196,7 +200,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
errno != EADDRNOTAVAIL)
syslog(LOG_ERR, "<%s> ioctl: %s", __func__,
- strerror(errno));
+ strerror(errno));
/* very adhoc: should be rewritten */
if (rpm->rpm_code == RPM_PCO_CHANGE &&
@@ -206,28 +210,31 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if ((rai = if_indextorainfo(ifindex)) == NULL)
continue; /* non-advertising IF */
- for (pp = rai->prefix.next; pp != &rai->prefix;
- pp = pp->next) {
+ TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
struct timeval now;
- if (prefix_match(&pp->prefix, pp->prefixlen,
- &rpm->rpm_prefix,
- rpm->rpm_matchlen)) {
+ if (prefix_match(&pfx->pfx_prefix,
+ pfx->pfx_prefixlen, &rpm->rpm_prefix,
+ rpm->rpm_matchlen)) {
/* change parameters */
- pp->validlifetime = ntohl(rpu->rpu_vltime);
- pp->preflifetime = ntohl(rpu->rpu_pltime);
+ pfx->pfx_validlifetime =
+ ntohl(rpu->rpu_vltime);
+ pfx->pfx_preflifetime =
+ ntohl(rpu->rpu_pltime);
if (irr->irr_rrf_decrvalid) {
gettimeofday(&now, 0);
- pp->vltimeexpire =
- now.tv_sec + pp->validlifetime;
+ pfx->pfx_vltimeexpire =
+ now.tv_sec +
+ pfx->pfx_validlifetime;
} else
- pp->vltimeexpire = 0;
+ pfx->pfx_vltimeexpire = 0;
if (irr->irr_rrf_decrprefd) {
gettimeofday(&now, 0);
- pp->pltimeexpire =
- now.tv_sec + pp->preflifetime;
+ pfx->pfx_pltimeexpire =
+ now.tv_sec +
+ pfx->pfx_preflifetime;
} else
- pp->pltimeexpire = 0;
+ pfx->pfx_pltimeexpire = 0;
}
}
}
@@ -245,11 +252,11 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
struct in6_rrenumreq irr;
if ((rr_pco_check(len, rpm) != 0))
- return 1;
+ return (1);
if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__,
- strerror(errno));
+ strerror(errno));
exit(1);
}
@@ -264,8 +271,8 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
while (if_indextoname(++ifindex, irr.irr_name)) {
/*
- * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off,
- * the interface is not applied
+ * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and
+ * IFF_UP is off, the interface is not applied
*/
if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
(iflist[ifindex]->ifm_flags & IFF_UP) == 0)
@@ -274,13 +281,13 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
do_use_prefix(len, rpm, &irr, ifindex);
}
if (errno == ENXIO)
- return 0;
+ return (0);
else if (errno) {
syslog(LOG_ERR, "<%s> if_indextoname: %s", __func__,
- strerror(errno));
- return 1;
+ strerror(errno));
+ return (1);
}
- return 0;
+ return (0);
}
/*
@@ -305,11 +312,11 @@ do_rr(int len, struct icmp6_router_renum *rr)
int rpmlen;
rpm = (struct rr_pco_match *)cp;
- if (len < sizeof(struct rr_pco_match)) {
+ if ((size_t)len < sizeof(struct rr_pco_match)) {
tooshort:
syslog(LOG_ERR, "<%s> pkt too short. left len = %d. "
- "gabage at end of pkt?", __func__, len);
- return 1;
+ "gabage at end of pkt?", __func__, len);
+ return (1);
}
rpmlen = rpm->rpm_len << 3;
if (len < rpmlen)
@@ -325,7 +332,7 @@ do_rr(int len, struct icmp6_router_renum *rr)
len -= rpmlen;
}
- return 0;
+ return (0);
}
/*
@@ -334,46 +341,45 @@ do_rr(int len, struct icmp6_router_renum *rr)
*/
static int
rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
- struct in6_addr *dst)
+ struct in6_addr *dst)
{
u_char ntopbuf[INET6_ADDRSTRLEN];
/* omit rr minimal length check. hope kernel have done it. */
/* rr_command length check */
- if (len < (sizeof(struct icmp6_router_renum) +
- sizeof(struct rr_pco_match))) {
+ if ((size_t)len < (sizeof(struct icmp6_router_renum) +
+ sizeof(struct rr_pco_match))) {
syslog(LOG_ERR, "<%s> rr_command len %d is too short",
- __func__, len);
- return 1;
+ __func__, len);
+ return (1);
}
/* destination check. only for multicast. omit unicast check. */
if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) &&
!IN6_IS_ADDR_MC_SITELOCAL(dst)) {
syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal",
- __func__,
- inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN));
- return 1;
+ __func__,
+ inet_ntop(AF_INET6, dst, ntopbuf, sizeof(ntopbuf)));
+ return (1);
}
/* seqnum and segnum check */
if (rro.rro_seqnum > rr->rr_seqnum) {
syslog(LOG_WARNING,
- "<%s> rcvd old seqnum %d from %s",
- __func__, (u_int32_t)ntohl(rr->rr_seqnum),
- inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN));
- return 1;
+ "<%s> rcvd old seqnum %d from %s",
+ __func__, (u_int32_t)ntohl(rr->rr_seqnum),
+ inet_ntop(AF_INET6, from, ntopbuf, sizeof(ntopbuf)));
+ return (1);
}
if (rro.rro_seqnum == rr->rr_seqnum &&
(rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 &&
RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) {
if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0)
syslog(LOG_WARNING,
- "<%s> rcvd duped segnum %d from %s",
- __func__, rr->rr_segnum,
- inet_ntop(AF_INET6, from, ntopbuf,
- INET6_ADDRSTRLEN));
- return 0;
+ "<%s> rcvd duped segnum %d from %s",
+ __func__, rr->rr_segnum, inet_ntop(AF_INET6, from,
+ ntopbuf, sizeof(ntopbuf)));
+ return (0);
}
/* update seqnum */
@@ -382,16 +388,16 @@ rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
/* init rro_segnum_bits */
memset(rro.rro_segnum_bits, 0,
- sizeof(rro.rro_segnum_bits));
+ sizeof(rro.rro_segnum_bits));
}
rro.rro_seqnum = rr->rr_seqnum;
- return 0;
+ return (0);
}
static void
rr_command_input(int len, struct icmp6_router_renum *rr,
- struct in6_addr *from, struct in6_addr *dst)
+ struct in6_addr *from, struct in6_addr *dst)
{
/* rr_command validity check */
if (rr_command_check(len, rr, from, dst))
@@ -401,9 +407,8 @@ rr_command_input(int len, struct icmp6_router_renum *rr,
return;
/* do router renumbering */
- if (do_rr(len, rr)) {
+ if (do_rr(len, rr))
goto failed;
- }
/* update segnum */
RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum);
@@ -417,27 +422,26 @@ rr_command_input(int len, struct icmp6_router_renum *rr,
void
rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
- struct sockaddr_in6 *from, struct in6_addr *dst)
+ struct sockaddr_in6 *from, struct in6_addr *dst)
{
u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
syslog(LOG_DEBUG,
- "<%s> RR received from %s to %s on %s",
- __func__,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf[0], INET6_ADDRSTRLEN),
- inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s> RR received from %s to %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0] ,sizeof(ntopbuf[0])),
+ inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
/* packet validation based on Section 4.1 of RFC2894 */
- if (len < sizeof(struct icmp6_router_renum)) {
+ if ((size_t)len < sizeof(struct icmp6_router_renum)) {
syslog(LOG_NOTICE,
- "<%s>: RR short message (size %d) from %s to %s on %s",
- __func__, len,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf[0], INET6_ADDRSTRLEN),
- inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s>: RR short message (size %d) from %s to %s on %s",
+ __func__, len,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0],
+ sizeof(ntopbuf[0])),
+ inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
@@ -449,16 +453,16 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
* We rely on the kernel input routine for unicast addresses, and thus
* check multicast destinations only.
*/
- if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) &&
- !IN6_ARE_ADDR_EQUAL(&in6a_site_allrouters, &pi->ipi6_addr)) {
+ if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && !IN6_ARE_ADDR_EQUAL(
+ &sin6_sitelocal_allrouters.sin6_addr, &pi->ipi6_addr)) {
syslog(LOG_NOTICE,
- "<%s>: RR message with invalid destination (%s) "
- "from %s on %s",
- __func__,
- inet_ntop(AF_INET6, &dst, ntopbuf[0], INET6_ADDRSTRLEN),
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf[1], INET6_ADDRSTRLEN),
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s>: RR message with invalid destination (%s) "
+ "from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &dst, ntopbuf[0], sizeof(ntopbuf[0])),
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[1],
+ sizeof(ntopbuf[1])),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
@@ -477,7 +481,7 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
break;
default:
syslog(LOG_ERR, "<%s> received unknown code %d",
- __func__, rr->rr_code);
+ __func__, rr->rr_code);
break;
}
diff --git a/usr.sbin/rtadvd/rrenum.h b/usr.sbin/rtadvd/rrenum.h
index c358a2b..2b20d59 100644
--- a/usr.sbin/rtadvd/rrenum.h
+++ b/usr.sbin/rtadvd/rrenum.h
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
diff --git a/usr.sbin/rtadvd/rtadvd.8 b/usr.sbin/rtadvd/rtadvd.8
index 7bc3064..b41f7c06 100644
--- a/usr.sbin/rtadvd/rtadvd.8
+++ b/usr.sbin/rtadvd/rtadvd.8
@@ -37,9 +37,10 @@
.Nd router advertisement daemon
.Sh SYNOPSIS
.Nm
-.Op Fl dDfMRs
+.Op Fl dDfRs
.Op Fl c Ar configfile
.Op Fl F Ar dumpfile
+.Op Fl M Ar ifname
.Op Fl p Ar pidfile
.Ar interface ...
.Sh DESCRIPTION
@@ -103,7 +104,7 @@ will not watch the routing table and the whole functionality described
above will be suppressed.
.Pp
Basically, hosts MUST NOT send Router Advertisement messages at any
-time (RFC 2461, Section 6.2.3).
+time (RFC 4861, Section 6.2.3).
However, it would sometimes be useful to allow hosts to advertise some
parameters such as prefix information and link MTU.
Thus,
@@ -168,6 +169,18 @@ or the file specified with option
.Fl F .
.Pp
Use
+.Dv SIGHUP
+to reload the configuration file
+.Pa /etc/rtadvd.conf .
+If an invalid parameter is found in the configuration file upon the reload,
+the entry will be ignored and the old configuration will be used.
+When parameters in an existing entry are updated,
+.Nm
+will send Router Advertisement messages with the old configuration but
+zero router lifetime to the interface first, and then start to send a new
+message.
+.Pp
+Use
.Dv SIGTERM
to kill
.Nm
@@ -176,7 +189,7 @@ In this case,
.Nm
will transmit router advertisement with router lifetime 0
to all the interfaces
-.Pq in accordance with RFC2461 6.2.5 .
+.Pq in accordance with RFC 4861 6.2.5 .
.Sh FILES
.Bl -tag -width Pa -compact
.It Pa /etc/rtadvd.conf
@@ -193,6 +206,34 @@ dumps its internal state.
.Sh SEE ALSO
.Xr rtadvd.conf 5 ,
.Xr rtsol 8
+.Rs
+.%A Thomas Narten
+.%A Erik Nordmark
+.%A W. A. Simpson
+.%A Hesham Soliman
+.%T Neighbor Discovery for IP version 6 (IPv6)
+.%R RFC 4861
+.Re
+.Rs
+.%A Thomas Narten
+.%A Erik Nordmark
+.%A W. A. Simpson
+.%T Neighbor Discovery for IP version 6 (IPv6)
+.%R RFC 2461 (obsoleted by RFC 4861)
+.Re
+.Rs
+.%A Richard Draves
+.%T Default Router Preferences and More-Specific Routes
+.%R draft-ietf-ipngwg-router-selection-xx.txt
+.Re
+.Rs
+.%A J. Jeong
+.%A S. Park
+.%A L. Beloeil
+.%A S. Madanapalli
+.%T IPv6 Router Advertisement Options for DNS Configuration
+.%R RFC 6106
+.Re
.Sh HISTORY
The
.Nm
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c
index 02e3dc7..e9b212c 100644
--- a/usr.sbin/rtadvd/rtadvd.c
+++ b/usr.sbin/rtadvd/rtadvd.c
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -31,12 +31,15 @@
*/
#include <sys/param.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/queue.h>
+#include <sys/sysctl.h>
#include <net/if.h>
+#include <net/if_media.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet/in.h>
@@ -46,12 +49,17 @@
#include <arpa/inet.h>
+#include <net/if_var.h>
+#include <netinet/in_var.h>
+#include <netinet6/nd6.h>
+
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <err.h>
#include <errno.h>
#include <libutil.h>
+#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
@@ -66,6 +74,7 @@
#include "if.h"
#include "config.h"
#include "dump.h"
+#include "pathnames.h"
struct msghdr rcvmhdr;
static u_char *rcvcmsgbuf;
@@ -74,30 +83,32 @@ static u_char *sndcmsgbuf = NULL;
static size_t sndcmsgbuflen;
volatile sig_atomic_t do_dump;
volatile sig_atomic_t do_die;
+volatile sig_atomic_t do_reload;
struct msghdr sndmhdr;
struct iovec rcviov[2];
struct iovec sndiov[2];
struct sockaddr_in6 rcvfrom;
-struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6};
-struct in6_addr in6a_site_allrouters;
-static char *dumpfilename = "/var/run/rtadvd.dump";
-static char *pidfilename = "/var/run/rtadvd.pid";
+static const char *dumpfilename = _PATH_RTADVDDUMP;
+static const char *pidfilename = _PATH_RTADVDPID;
+const char *conffile = _PATH_RTADVDCONF;
static struct pidfh *pfh;
static char *mcastif;
int sock;
int rtsock = -1;
int accept_rr = 0;
int dflag = 0, sflag = 0;
+static int ifl_len;
+static char **ifl_names;
-u_char *conffile = NULL;
+struct railist_head_t railist =
+ TAILQ_HEAD_INITIALIZER(railist);
-struct rainfo *ralist = NULL;
struct nd_optlist {
- struct nd_optlist *next;
- struct nd_opt_hdr *opt;
+ TAILQ_ENTRY(nd_optlist) nol_next;
+ struct nd_opt_hdr *nol_opt;
};
-union nd_opts {
- struct nd_opt_hdr *nd_opt_array[9];
+union nd_opt {
+ struct nd_opt_hdr *opt_array[9];
struct {
struct nd_opt_hdr *zero;
struct nd_opt_hdr *src_lladdr;
@@ -105,51 +116,76 @@ union nd_opts {
struct nd_opt_prefix_info *pi;
struct nd_opt_rd_hdr *rh;
struct nd_opt_mtu *mtu;
- struct nd_optlist *list;
+ TAILQ_HEAD(, nd_optlist) opt_list;
} nd_opt_each;
};
-#define nd_opts_src_lladdr nd_opt_each.src_lladdr
-#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr
-#define nd_opts_pi nd_opt_each.pi
-#define nd_opts_rh nd_opt_each.rh
-#define nd_opts_mtu nd_opt_each.mtu
-#define nd_opts_list nd_opt_each.list
-
-#define NDOPT_FLAG_SRCLINKADDR 0x1
-#define NDOPT_FLAG_TGTLINKADDR 0x2
-#define NDOPT_FLAG_PREFIXINFO 0x4
-#define NDOPT_FLAG_RDHDR 0x8
-#define NDOPT_FLAG_MTU 0x10
+#define opt_src_lladdr nd_opt_each.src_lladdr
+#define opt_tgt_lladdr nd_opt_each.tgt_lladdr
+#define opt_pi nd_opt_each.pi
+#define opt_rh nd_opt_each.rh
+#define opt_mtu nd_opt_each.mtu
+#define opt_list nd_opt_each.opt_list
+
+#define NDOPT_FLAG_SRCLINKADDR (1 << 0)
+#define NDOPT_FLAG_TGTLINKADDR (1 << 1)
+#define NDOPT_FLAG_PREFIXINFO (1 << 2)
+#define NDOPT_FLAG_RDHDR (1 << 3)
+#define NDOPT_FLAG_MTU (1 << 4)
+#define NDOPT_FLAG_RDNSS (1 << 5)
+#define NDOPT_FLAG_DNSSL (1 << 6)
u_int32_t ndopt_flags[] = {
- 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
- NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU,
+ [ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR,
+ [ND_OPT_TARGET_LINKADDR] = NDOPT_FLAG_TGTLINKADDR,
+ [ND_OPT_PREFIX_INFORMATION] = NDOPT_FLAG_PREFIXINFO,
+ [ND_OPT_REDIRECTED_HEADER] = NDOPT_FLAG_RDHDR,
+ [ND_OPT_MTU] = NDOPT_FLAG_MTU,
+ [ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS,
+ [ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL,
+};
+
+struct sockaddr_in6 sin6_linklocal_allnodes = {
+ .sin6_len = sizeof(sin6_linklocal_allnodes),
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
+};
+
+struct sockaddr_in6 sin6_linklocal_allrouters = {
+ .sin6_len = sizeof(sin6_linklocal_allrouters),
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
+};
+
+struct sockaddr_in6 sin6_sitelocal_allrouters = {
+ .sin6_len = sizeof(sin6_sitelocal_allrouters),
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT,
};
-int main(int, char *[]);
-static void set_die(int);
-static void die(void);
-static void sock_open(void);
-static void rtsock_open(void);
-static void rtadvd_input(void);
-static void rs_input(int, struct nd_router_solicit *,
- struct in6_pktinfo *, struct sockaddr_in6 *);
-static void ra_input(int, struct nd_router_advert *,
- struct in6_pktinfo *, struct sockaddr_in6 *);
-static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
- struct sockaddr_in6 *);
-static int nd6_options(struct nd_opt_hdr *, int,
- union nd_opts *, u_int32_t);
-static void free_ndopts(union nd_opts *);
-static void ra_output(struct rainfo *);
-static void rtmsg_input(void);
-static void rtadvd_set_dump_file(int);
-static void set_short_delay(struct rainfo *);
+static void set_reload(int);
+static void set_die(int);
+static void die(void);
+static void sock_open(void);
+static void rtsock_open(void);
+static void rtadvd_input(void);
+static void rs_input(int, struct nd_router_solicit *,
+ struct in6_pktinfo *, struct sockaddr_in6 *);
+static void ra_input(int, struct nd_router_advert *,
+ struct in6_pktinfo *, struct sockaddr_in6 *);
+static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
+ struct sockaddr_in6 *);
+static int nd6_options(struct nd_opt_hdr *, int,
+ union nd_opt *, u_int32_t);
+static void free_ndopts(union nd_opt *);
+static void rtmsg_input(void);
+static void rtadvd_set_dump_file(int);
+static void set_short_delay(struct rainfo *);
+static int ifl_lookup(char *, char **, int);
+static int check_accept_rtadv(int);
+static int getinet6sysctl(int);
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char *argv[])
{
#ifdef HAVE_POLL_H
struct pollfd set[2];
@@ -164,16 +200,16 @@ main(argc, argv)
pid_t pid, otherpid;
/* get command line options and arguments */
- while ((ch = getopt(argc, argv, "c:dDF:fMp:Rs")) != -1) {
+ while ((ch = getopt(argc, argv, "c:dDfF:M:p:Rs")) != -1) {
switch (ch) {
case 'c':
conffile = optarg;
break;
case 'd':
- dflag = 1;
+ dflag++;
break;
case 'D':
- dflag = 2;
+ dflag += 2;
break;
case 'f':
fflag = 1;
@@ -202,8 +238,9 @@ main(argc, argv)
argv += optind;
if (argc == 0) {
fprintf(stderr,
- "usage: rtadvd [-dDfMRs] [-c conffile] "
- "[-F dumpfile] [-p pidfile] interfaces...\n");
+ "usage: rtadvd [-dDfRs] [-c conffile] "
+ "[-F dumpfile] [-M ifname] "
+ "[-p pidfile] interfaces...\n");
exit(1);
}
@@ -213,10 +250,12 @@ main(argc, argv)
openlog("rtadvd", logopt, LOG_DAEMON);
/* set log level */
- if (dflag == 0)
- (void)setlogmask(LOG_UPTO(LOG_ERR));
- if (dflag == 1)
+ if (dflag > 1)
+ (void)setlogmask(LOG_UPTO(LOG_DEBUG));
+ else if (dflag > 0)
(void)setlogmask(LOG_UPTO(LOG_INFO));
+ else
+ (void)setlogmask(LOG_UPTO(LOG_ERR));
/* timer initialization */
rtadvd_timer_init();
@@ -229,17 +268,12 @@ main(argc, argv)
srandom((u_long)time(NULL));
#endif
#endif
-
/* get iflist block from kernel */
init_iflist();
+ ifl_names = argv;
+ ifl_len = argc;
- while (argc--)
- getconfig(*argv++);
-
- if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) {
- fprintf(stderr, "fatal: inet_pton failed\n");
- exit(1);
- }
+ loadconfig(argv, argc);
pfh = pidfile_open(pidfilename, 0600, &otherpid);
if (pfh == NULL) {
@@ -292,15 +326,14 @@ main(argc, argv)
if (rtsock >= 0)
FD_SET(rtsock, fdsetp);
#endif
-
signal(SIGTERM, set_die);
signal(SIGUSR1, rtadvd_set_dump_file);
+ signal(SIGHUP, set_reload);
while (1) {
#ifndef HAVE_POLL_H
memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */
#endif
-
if (do_dump) { /* SIGUSR1 */
do_dump = 0;
rtadvd_dump_file(dumpfilename);
@@ -311,6 +344,11 @@ main(argc, argv)
/*NOTREACHED*/
}
+ if (do_reload) {
+ loadconfig(argv, argc);
+ do_reload = 0;
+ }
+
/* timer expiration check and reset the timer */
timeout = rtadvd_check_timer();
@@ -325,7 +363,6 @@ main(argc, argv)
"<%s> there's no timer. waiting for inputs",
__func__);
}
-
#ifdef HAVE_POLL_H
if ((i = poll(set, 2, timeout ? (timeout->tv_sec * 1000 +
timeout->tv_usec / 1000) : INFTIM)) < 0)
@@ -358,75 +395,95 @@ main(argc, argv)
exit(0); /* NOTREACHED */
}
+static int
+ifl_lookup(char *ifn, char **names, int len)
+{
+ while (len--)
+ if (strncmp(names[len], ifn, IFNAMSIZ) == 0)
+ return (0);
+ return (-1);
+}
+
static void
-rtadvd_set_dump_file(sig)
- int sig;
+rtadvd_set_dump_file(int sig __unused)
{
+
do_dump = 1;
}
static void
-set_die(sig)
- int sig;
+set_reload(int sig __unused)
{
+
+ do_reload = 1;
+}
+
+static void
+set_die(int sig __unused)
+{
+
do_die = 1;
}
static void
-die()
+die(void)
{
- struct rainfo *ra;
+ struct rainfo *rai;
+ struct rdnss *rdn;
+ struct dnssl *dns;
int i;
const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
- if (dflag > 1) {
- syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n",
- __func__);
- }
+ syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n",
+ __func__);
- for (ra = ralist; ra; ra = ra->next) {
- ra->lifetime = 0;
- make_packet(ra);
+ TAILQ_FOREACH(rai, &railist, rai_next) {
+ rai->rai_lifetime = 0;
+ TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next)
+ rdn->rd_ltime = 0;
+ TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next)
+ dns->dn_ltime = 0;
+ make_packet(rai);
}
for (i = 0; i < retrans; i++) {
- for (ra = ralist; ra; ra = ra->next)
- ra_output(ra);
+ TAILQ_FOREACH(rai, &railist, rai_next)
+ ra_output(rai);
sleep(MIN_DELAY_BETWEEN_RAS);
}
pidfile_remove(pfh);
+
exit(0);
- /*NOTREACHED*/
}
static void
-rtmsg_input()
+rtmsg_input(void)
{
int n, type, ifindex = 0, plen;
size_t len;
char msg[2048], *next, *lim;
- u_char ifname[IF_NAMESIZE];
- struct prefix *prefix;
+ u_char ifname[IFNAMSIZ];
+ struct if_announcemsghdr *ifan;
+ struct prefix *pfx;
struct rainfo *rai;
struct in6_addr *addr;
char addrbuf[INET6_ADDRSTRLEN];
int prefixchange = 0;
+ int error;
n = read(rtsock, msg, sizeof(msg));
- if (dflag > 1) {
- syslog(LOG_DEBUG, "<%s> received a routing message "
- "(type = %d, len = %d)", __func__, rtmsg_type(msg), n);
- }
+ syslog(LOG_DEBUG, "<%s> received a routing message "
+ "(type = %d, len = %d)", __func__, rtmsg_type(msg), n);
+
if (n > rtmsg_len(msg)) {
/*
- * This usually won't happen for messages received on
+ * This usually won't happen for messages received on
* a routing socket.
*/
- if (dflag > 1)
- syslog(LOG_DEBUG,
- "<%s> received data length is larger than "
- "1st routing message len. multiple messages? "
- "read %d bytes, but 1st msg len = %d",
- __func__, n, rtmsg_len(msg));
+ syslog(LOG_DEBUG,
+ "<%s> received data length is larger than "
+ "1st routing message len. multiple messages? "
+ "read %d bytes, but 1st msg len = %d",
+ __func__, n, rtmsg_len(msg));
#if 0
/* adjust length */
n = rtmsg_len(msg);
@@ -438,11 +495,12 @@ rtmsg_input()
int oldifflags;
next = get_next_msg(next, lim, 0, &len,
- RTADV_TYPE2BITMASK(RTM_ADD) |
- RTADV_TYPE2BITMASK(RTM_DELETE) |
- RTADV_TYPE2BITMASK(RTM_NEWADDR) |
- RTADV_TYPE2BITMASK(RTM_DELADDR) |
- RTADV_TYPE2BITMASK(RTM_IFINFO));
+ RTADV_TYPE2BITMASK(RTM_ADD) |
+ RTADV_TYPE2BITMASK(RTM_DELETE) |
+ RTADV_TYPE2BITMASK(RTM_NEWADDR) |
+ RTADV_TYPE2BITMASK(RTM_DELADDR) |
+ RTADV_TYPE2BITMASK(RTM_IFINFO) |
+ RTADV_TYPE2BITMASK(RTM_IFANNOUNCE));
if (len == 0)
break;
type = rtmsg_type(next);
@@ -458,25 +516,65 @@ rtmsg_input()
case RTM_IFINFO:
ifindex = get_ifm_ifindex(next);
break;
- default:
- /* should not reach here */
- if (dflag > 1) {
+ case RTM_IFANNOUNCE:
+ ifan = (struct if_announcemsghdr *)next;
+ switch (ifan->ifan_what) {
+ case IFAN_ARRIVAL:
+ case IFAN_DEPARTURE:
+ break;
+ default:
syslog(LOG_DEBUG,
- "<%s:%d> unknown rtmsg %d on %s",
- __func__, __LINE__, type,
- if_indextoname(ifindex, ifname));
+ "<%s:%d> unknown ifan msg (ifan_what=%d)",
+ __func__, __LINE__, ifan->ifan_what);
+ continue;
+ }
+
+ syslog(LOG_INFO, "<%s>: if_announcemsg (idx=%d:%d)",
+ __func__, ifan->ifan_index, ifan->ifan_what);
+ init_iflist();
+ error = ifl_lookup(ifan->ifan_name,
+ ifl_names, ifl_len);
+ if (error) {
+ syslog(LOG_INFO, "<%s>: not a target "
+ "interface (idx=%d)", __func__,
+ ifan->ifan_index);
+ continue;
+ }
+
+ switch (ifan->ifan_what) {
+ case IFAN_ARRIVAL:
+ error = getconfig(ifan->ifan_index);
+ if (error)
+ syslog(LOG_ERR,
+ "<%s>: getconfig failed (idx=%d)"
+ " Ignored.", __func__,
+ ifan->ifan_index);
+ break;
+ case IFAN_DEPARTURE:
+ error = rmconfig(ifan->ifan_index);
+ if (error)
+ syslog(LOG_ERR,
+ "<%s>: rmconfig failed (idx=%d)"
+ " Ignored.", __func__,
+ ifan->ifan_index);
+ break;
}
continue;
+ default:
+ /* should not reach here */
+ syslog(LOG_DEBUG,
+ "<%s:%d> unknown rtmsg %d on %s",
+ __func__, __LINE__, type,
+ if_indextoname(ifindex, ifname));
+ continue;
}
if ((rai = if_indextorainfo(ifindex)) == NULL) {
- if (dflag > 1) {
- syslog(LOG_DEBUG,
- "<%s> route changed on "
- "non advertising interface(%s)",
- __func__,
- if_indextoname(ifindex, ifname));
- }
+ syslog(LOG_DEBUG,
+ "<%s> route changed on "
+ "non advertising interface(%s)",
+ __func__,
+ if_indextoname(ifindex, ifname));
continue;
}
oldifflags = iflist[ifindex]->ifm_flags;
@@ -500,25 +598,25 @@ rtmsg_input()
__func__, plen);
break;
}
- prefix = find_prefix(rai, addr, plen);
- if (prefix) {
- if (prefix->timer) {
+ pfx = find_prefix(rai, addr, plen);
+ if (pfx) {
+ if (pfx->pfx_timer) {
/*
* If the prefix has been invalidated,
* make it available again.
*/
- update_prefix(prefix);
+ update_prefix(pfx);
prefixchange = 1;
- } else if (dflag > 1) {
+ } else
syslog(LOG_DEBUG,
"<%s> new prefix(%s/%d) "
"added on %s, "
"but it was already in list",
__func__,
inet_ntop(AF_INET6, addr,
- (char *)addrbuf, INET6_ADDRSTRLEN),
- plen, rai->ifname);
- }
+ (char *)addrbuf,
+ sizeof(addrbuf)),
+ plen, rai->rai_ifname);
break;
}
make_prefix(rai, ifindex, addr, plen);
@@ -543,21 +641,17 @@ rtmsg_input()
__func__, plen);
break;
}
- prefix = find_prefix(rai, addr, plen);
- if (prefix == NULL) {
- if (dflag > 1) {
- syslog(LOG_DEBUG,
- "<%s> prefix(%s/%d) was "
- "deleted on %s, "
- "but it was not in list",
- __func__,
- inet_ntop(AF_INET6, addr,
- (char *)addrbuf, INET6_ADDRSTRLEN),
- plen, rai->ifname);
- }
+ pfx = find_prefix(rai, addr, plen);
+ if (pfx == NULL) {
+ syslog(LOG_DEBUG,
+ "<%s> prefix(%s/%d) was deleted on %s, "
+ "but it was not in list",
+ __func__, inet_ntop(AF_INET6, addr,
+ (char *)addrbuf, sizeof(addrbuf)),
+ plen, rai->rai_ifname);
break;
}
- invalidate_prefix(prefix);
+ invalidate_prefix(pfx);
prefixchange = 1;
break;
case RTM_NEWADDR:
@@ -571,12 +665,10 @@ rtmsg_input()
break;
default:
/* should not reach here */
- if (dflag > 1) {
- syslog(LOG_DEBUG,
- "<%s:%d> unknown rtmsg %d on %s",
- __func__, __LINE__, type,
- if_indextoname(ifindex, ifname));
- }
+ syslog(LOG_DEBUG,
+ "<%s:%d> unknown rtmsg %d on %s",
+ __func__, __LINE__, type,
+ if_indextoname(ifindex, ifname));
return;
}
@@ -585,27 +677,29 @@ rtmsg_input()
!(iflist[ifindex]->ifm_flags & IFF_UP)) {
syslog(LOG_INFO,
"<%s> interface %s becomes down. stop timer.",
- __func__, rai->ifname);
- rtadvd_remove_timer(&rai->timer);
+ __func__, rai->rai_ifname);
+ rtadvd_remove_timer(rai->rai_timer);
+ rai->rai_timer = NULL;
} else if (!(oldifflags & IFF_UP) && /* DOWN to UP */
- (iflist[ifindex]->ifm_flags & IFF_UP)) {
+ (iflist[ifindex]->ifm_flags & IFF_UP)) {
syslog(LOG_INFO,
"<%s> interface %s becomes up. restart timer.",
- __func__, rai->ifname);
+ __func__, rai->rai_ifname);
- rai->initcounter = 0; /* reset the counter */
- rai->waiting = 0; /* XXX */
- rai->timer = rtadvd_add_timer(ra_timeout,
+ rai->rai_initcounter = 0; /* reset the counter */
+ rai->rai_waiting = 0; /* XXX */
+ rai->rai_timer = rtadvd_add_timer(ra_timeout,
ra_timer_update, rai, rai);
- ra_timer_update((void *)rai, &rai->timer->tm);
- rtadvd_set_timer(&rai->timer->tm, rai->timer);
+ ra_timer_update(rai, &rai->rai_timer->rat_tm);
+ rtadvd_set_timer(&rai->rai_timer->rat_tm,
+ rai->rai_timer);
} else if (prefixchange &&
(iflist[ifindex]->ifm_flags & IFF_UP)) {
/*
* An advertised prefix has been added or invalidated.
* Will notice the change in a short delay.
*/
- rai->initcounter = 0;
+ rai->rai_initcounter = 0;
set_short_delay(rai);
}
}
@@ -614,13 +708,13 @@ rtmsg_input()
}
void
-rtadvd_input()
+rtadvd_input(void)
{
- int i;
+ ssize_t i;
int *hlimp = NULL;
#ifdef OLDRAWSOCKET
struct ip6_hdr *ip;
-#endif
+#endif
struct icmp6_hdr *icp;
int ifindex = 0;
struct cmsghdr *cm;
@@ -655,14 +749,14 @@ rtadvd_input()
}
if (ifindex == 0) {
syslog(LOG_ERR,
- "<%s> failed to get receiving interface",
- __func__);
+ "<%s> failed to get receiving interface",
+ __func__);
return;
}
if (hlimp == NULL) {
syslog(LOG_ERR,
- "<%s> failed to get receiving hop limit",
- __func__);
+ "<%s> failed to get receiving hop limit",
+ __func__);
return;
}
@@ -673,28 +767,28 @@ rtadvd_input()
if (iflist[pi->ipi6_ifindex] == NULL ||
(iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) {
syslog(LOG_INFO,
- "<%s> received data on a disabled interface (%s)",
- __func__,
- (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" :
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s> received data on a disabled interface (%s)",
+ __func__,
+ (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" :
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
#ifdef OLDRAWSOCKET
- if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) {
+ if ((size_t)i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) {
syslog(LOG_ERR,
- "<%s> packet size(%d) is too short",
- __func__, i);
+ "<%s> packet size(%d) is too short",
+ __func__, i);
return;
}
ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base;
icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */
#else
- if (i < sizeof(struct icmp6_hdr)) {
+ if ((size_t)i < sizeof(struct icmp6_hdr)) {
syslog(LOG_ERR,
- "<%s> packet size(%d) is too short",
- __func__, i);
+ "<%s> packet size(%zd) is too short",
+ __func__, i);
return;
}
@@ -704,7 +798,7 @@ rtadvd_input()
switch (icp->icmp6_type) {
case ND_ROUTER_SOLICIT:
/*
- * Message verification - RFC-2461 6.1.1
+ * Message verification - RFC 4861 6.1.1
* XXX: these checks must be done in the kernel as well,
* but we can't completely rely on them.
*/
@@ -714,7 +808,7 @@ rtadvd_input()
"received from %s on %s",
__func__, *hlimp,
inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
- INET6_ADDRSTRLEN),
+ sizeof(ntopbuf)),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
@@ -724,17 +818,17 @@ rtadvd_input()
"received from %s on %s",
__func__, icp->icmp6_code,
inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
- INET6_ADDRSTRLEN),
+ sizeof(ntopbuf)),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
- if (i < sizeof(struct nd_router_solicit)) {
+ if ((size_t)i < sizeof(struct nd_router_solicit)) {
syslog(LOG_NOTICE,
"<%s> RS from %s on %s does not have enough "
- "length (len = %d)",
+ "length (len = %zd)",
__func__,
inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
- INET6_ADDRSTRLEN),
+ sizeof(ntopbuf)),
if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
return;
}
@@ -742,16 +836,25 @@ rtadvd_input()
break;
case ND_ROUTER_ADVERT:
/*
- * Message verification - RFC-2461 6.1.2
- * XXX: there's a same dilemma as above...
+ * Message verification - RFC 4861 6.1.2
+ * XXX: there's the same dilemma as above...
*/
+ if (!IN6_IS_ADDR_LINKLOCAL(&rcvfrom.sin6_addr)) {
+ syslog(LOG_NOTICE,
+ "<%s> RA witn non-linklocal source address "
+ "received from %s on %s",
+ __func__, inet_ntop(AF_INET6, &rcvfrom.sin6_addr,
+ ntopbuf, sizeof(ntopbuf)),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
if (*hlimp != 255) {
syslog(LOG_NOTICE,
"<%s> RA with invalid hop limit(%d) "
"received from %s on %s",
__func__, *hlimp,
inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
- INET6_ADDRSTRLEN),
+ sizeof(ntopbuf)),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
@@ -761,17 +864,17 @@ rtadvd_input()
"received from %s on %s",
__func__, icp->icmp6_code,
inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
- INET6_ADDRSTRLEN),
+ sizeof(ntopbuf)),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
- if (i < sizeof(struct nd_router_advert)) {
+ if ((size_t)i < sizeof(struct nd_router_advert)) {
syslog(LOG_NOTICE,
"<%s> RA from %s on %s does not have enough "
- "length (len = %d)",
+ "length (len = %zd)",
__func__,
inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
- INET6_ADDRSTRLEN),
+ sizeof(ntopbuf)),
if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
return;
}
@@ -785,7 +888,7 @@ rtadvd_input()
break;
}
rr_input(i, (struct icmp6_router_renum *)icp, pi, &rcvfrom,
- &dst);
+ &dst);
break;
default:
/*
@@ -806,17 +909,17 @@ static void
rs_input(int len, struct nd_router_solicit *rs,
struct in6_pktinfo *pi, struct sockaddr_in6 *from)
{
- u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
- union nd_opts ndopts;
- struct rainfo *ra;
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+ u_char ifnamebuf[IFNAMSIZ];
+ union nd_opt ndopts;
+ struct rainfo *rai;
struct soliciter *sol;
syslog(LOG_DEBUG,
- "<%s> RS received from %s on %s",
- __func__,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s> RS received from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
/* ND option check */
memset(&ndopts, 0, sizeof(ndopts));
@@ -824,36 +927,33 @@ rs_input(int len, struct nd_router_solicit *rs,
len - sizeof(struct nd_router_solicit),
&ndopts, NDOPT_FLAG_SRCLINKADDR)) {
syslog(LOG_INFO,
- "<%s> ND option check failed for an RS from %s on %s",
- __func__,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s> ND option check failed for an RS from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
/*
* If the IP source address is the unspecified address, there
* must be no source link-layer address option in the message.
- * (RFC-2461 6.1.1)
+ * (RFC 4861 6.1.1)
*/
if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
- ndopts.nd_opts_src_lladdr) {
+ ndopts.opt_src_lladdr) {
syslog(LOG_INFO,
- "<%s> RS from unspecified src on %s has a link-layer"
- " address option",
- __func__,
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s> RS from unspecified src on %s has a link-layer"
+ " address option",
+ __func__, if_indextoname(pi->ipi6_ifindex, ifnamebuf));
goto done;
}
- ra = ralist;
- while (ra != NULL) {
- if (pi->ipi6_ifindex == ra->ifindex)
+ TAILQ_FOREACH(rai, &railist, rai_next)
+ if (pi->ipi6_ifindex == (unsigned int)rai->rai_ifindex)
break;
- ra = ra->next;
- }
- if (ra == NULL) {
+
+ if (rai == NULL) {
syslog(LOG_INFO,
"<%s> RS received on non advertising interface(%s)",
__func__,
@@ -861,7 +961,7 @@ rs_input(int len, struct nd_router_solicit *rs,
goto done;
}
- ra->rsinput++; /* increment statistics */
+ rai->rai_rsinput++; /* increment statistics */
/*
* Decide whether to send RA according to the rate-limit
@@ -871,21 +971,20 @@ rs_input(int len, struct nd_router_solicit *rs,
/* record sockaddr waiting for RA, if possible */
sol = (struct soliciter *)malloc(sizeof(*sol));
if (sol) {
- sol->addr = *from;
- /* XXX RFC2553 need clarification on flowinfo */
- sol->addr.sin6_flowinfo = 0;
- sol->next = ra->soliciter;
- ra->soliciter = sol;
+ sol->sol_addr = *from;
+ /* XXX RFC 2553 need clarification on flowinfo */
+ sol->sol_addr.sin6_flowinfo = 0;
+ TAILQ_INSERT_TAIL(&rai->rai_soliciter, sol, sol_next);
}
/*
* If there is already a waiting RS packet, don't
* update the timer.
*/
- if (ra->waiting++)
+ if (rai->rai_waiting++)
goto done;
- set_short_delay(ra);
+ set_short_delay(rai);
done:
free_ndopts(&ndopts);
@@ -893,8 +992,7 @@ rs_input(int len, struct nd_router_solicit *rs,
}
static void
-set_short_delay(rai)
- struct rainfo *rai;
+set_short_delay(struct rainfo *rai)
{
long delay; /* must not be greater than 1000000 */
struct timeval interval, now, min_delay, tm_tmp, *rest;
@@ -904,7 +1002,7 @@ set_short_delay(rai)
* corresponds to a time later than the time the next
* multicast RA is scheduled to be sent, ignore the random
* delay and send the advertisement at the
- * already-scheduled time. RFC-2461 6.2.6
+ * already-scheduled time. RFC 4861 6.2.6
*/
#ifdef HAVE_ARC4RANDOM
delay = arc4random_uniform(MAX_RA_DELAY_TIME);
@@ -913,8 +1011,8 @@ set_short_delay(rai)
#endif
interval.tv_sec = 0;
interval.tv_usec = delay;
- rest = rtadvd_timer_rest(rai->timer);
- if (TIMEVAL_LT(*rest, interval)) {
+ rest = rtadvd_timer_rest(rai->rai_timer);
+ if (TIMEVAL_LT(rest, &interval)) {
syslog(LOG_DEBUG, "<%s> random delay is larger than "
"the rest of the current timer", __func__);
interval = *rest;
@@ -928,170 +1026,217 @@ set_short_delay(rai)
* previous advertisement was sent.
*/
gettimeofday(&now, NULL);
- TIMEVAL_SUB(&now, &rai->lastsent, &tm_tmp);
+ TIMEVAL_SUB(&now, &rai->rai_lastsent, &tm_tmp);
min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
min_delay.tv_usec = 0;
- if (TIMEVAL_LT(tm_tmp, min_delay)) {
+ if (TIMEVAL_LT(&tm_tmp, &min_delay)) {
TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay);
TIMEVAL_ADD(&min_delay, &interval, &interval);
}
- rtadvd_set_timer(&interval, rai->timer);
+ rtadvd_set_timer(&interval, rai->rai_timer);
+}
+
+static int
+check_accept_rtadv(int idx)
+{
+ struct in6_ndireq nd;
+ u_char ifname[IFNAMSIZ];
+ int s6;
+ int error;
+
+ if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR,
+ "<%s> open socket failed for idx=%d.",
+ __func__, idx);
+ return (0);
+ }
+ if ((if_indextoname(idx, ifname)) == NULL) {
+ syslog(LOG_ERR,
+ "<%s> ifindex->ifname failed (idx=%d).",
+ __func__, idx);
+ close(s6);
+ return (0);
+ }
+ memset(&nd, 0, sizeof(nd));
+ strncpy(nd.ifname, ifname, sizeof(nd.ifname));
+ error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
+ if (error) {
+ syslog(LOG_ERR,
+ "<%s> ioctl(SIOCGIFINFO_IN6) failed for idx=%d.",
+ __func__, idx);
+ nd.ndi.flags = 0;
+ }
+ close(s6);
+
+ return (nd.ndi.flags & ND6_IFF_ACCEPT_RTADV);
+}
+
+static int
+getinet6sysctl(int code)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
+ int value;
+ size_t size;
+
+ mib[3] = code;
+ size = sizeof(value);
+ if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
+ < 0) {
+ syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s",
+ __func__, code,
+ strerror(errno));
+ return (-1);
+ }
+ else
+ return (value);
}
static void
-ra_input(int len, struct nd_router_advert *ra,
+ra_input(int len, struct nd_router_advert *nra,
struct in6_pktinfo *pi, struct sockaddr_in6 *from)
{
struct rainfo *rai;
- u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
- union nd_opts ndopts;
- char *on_off[] = {"OFF", "ON"};
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+ u_char ifnamebuf[IFNAMSIZ];
+ union nd_opt ndopts;
+ const char *on_off[] = {"OFF", "ON"};
u_int32_t reachabletime, retranstimer, mtu;
int inconsistent = 0;
+ int error;
+
+ syslog(LOG_DEBUG, "<%s> RA received from %s on %s", __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ if (!check_accept_rtadv(pi->ipi6_ifindex)) {
+ syslog(LOG_INFO,
+ "<%s> An RA from %s on %s ignored (no ACCEPT_RTADV flag).",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex,
+ ifnamebuf));
+ return;
+ }
- syslog(LOG_DEBUG,
- "<%s> RA received from %s on %s",
- __func__,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
-
/* ND option check */
memset(&ndopts, 0, sizeof(ndopts));
- if (nd6_options((struct nd_opt_hdr *)(ra + 1),
- len - sizeof(struct nd_router_advert),
- &ndopts, NDOPT_FLAG_SRCLINKADDR |
- NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
+ error = nd6_options((struct nd_opt_hdr *)(nra + 1),
+ len - sizeof(struct nd_router_advert), &ndopts,
+ NDOPT_FLAG_SRCLINKADDR | NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU |
+ NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL);
+ if (error) {
syslog(LOG_INFO,
- "<%s> ND option check failed for an RA from %s on %s",
- __func__,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s> ND option check failed for an RA from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex,
+ ifnamebuf));
return;
}
/*
- * RA consistency check according to RFC-2461 6.2.7
+ * RA consistency check according to RFC 4861 6.2.7
*/
- if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
+ rai = if_indextorainfo(pi->ipi6_ifindex);
+ if (rai == NULL) {
syslog(LOG_INFO,
- "<%s> received RA from %s on non-advertising"
- " interface(%s)",
- __func__,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ "<%s> received RA from %s on non-advertising"
+ " interface(%s)",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex,
+ ifnamebuf));
goto done;
}
- rai->rainput++; /* increment statistics */
-
+ rai->rai_rainput++; /* increment statistics */
+
/* Cur Hop Limit value */
- if (ra->nd_ra_curhoplimit && rai->hoplimit &&
- ra->nd_ra_curhoplimit != rai->hoplimit) {
+ if (nra->nd_ra_curhoplimit && rai->rai_hoplimit &&
+ nra->nd_ra_curhoplimit != rai->rai_hoplimit) {
syslog(LOG_INFO,
- "<%s> CurHopLimit inconsistent on %s:"
- " %d from %s, %d from us",
- __func__,
- rai->ifname,
- ra->nd_ra_curhoplimit,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- rai->hoplimit);
+ "<%s> CurHopLimit inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__, rai->rai_ifname, nra->nd_ra_curhoplimit,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), rai->rai_hoplimit);
inconsistent++;
}
/* M flag */
- if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
- rai->managedflg) {
+ if ((nra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
+ rai->rai_managedflg) {
syslog(LOG_INFO,
- "<%s> M flag inconsistent on %s:"
- " %s from %s, %s from us",
- __func__,
- rai->ifname,
- on_off[!rai->managedflg],
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- on_off[rai->managedflg]);
+ "<%s> M flag inconsistent on %s:"
+ " %s from %s, %s from us",
+ __func__, rai->rai_ifname, on_off[!rai->rai_managedflg],
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), on_off[rai->rai_managedflg]);
inconsistent++;
}
/* O flag */
- if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
- rai->otherflg) {
+ if ((nra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
+ rai->rai_otherflg) {
syslog(LOG_INFO,
- "<%s> O flag inconsistent on %s:"
- " %s from %s, %s from us",
- __func__,
- rai->ifname,
- on_off[!rai->otherflg],
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- on_off[rai->otherflg]);
+ "<%s> O flag inconsistent on %s:"
+ " %s from %s, %s from us",
+ __func__, rai->rai_ifname, on_off[!rai->rai_otherflg],
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), on_off[rai->rai_otherflg]);
inconsistent++;
}
/* Reachable Time */
- reachabletime = ntohl(ra->nd_ra_reachable);
- if (reachabletime && rai->reachabletime &&
- reachabletime != rai->reachabletime) {
+ reachabletime = ntohl(nra->nd_ra_reachable);
+ if (reachabletime && rai->rai_reachabletime &&
+ reachabletime != rai->rai_reachabletime) {
syslog(LOG_INFO,
- "<%s> ReachableTime inconsistent on %s:"
- " %d from %s, %d from us",
- __func__,
- rai->ifname,
- reachabletime,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- rai->reachabletime);
+ "<%s> ReachableTime inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__, rai->rai_ifname, reachabletime,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), rai->rai_reachabletime);
inconsistent++;
}
/* Retrans Timer */
- retranstimer = ntohl(ra->nd_ra_retransmit);
- if (retranstimer && rai->retranstimer &&
- retranstimer != rai->retranstimer) {
+ retranstimer = ntohl(nra->nd_ra_retransmit);
+ if (retranstimer && rai->rai_retranstimer &&
+ retranstimer != rai->rai_retranstimer) {
syslog(LOG_INFO,
- "<%s> RetranceTimer inconsistent on %s:"
- " %d from %s, %d from us",
- __func__,
- rai->ifname,
- retranstimer,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- rai->retranstimer);
+ "<%s> RetranceTimer inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__, rai->rai_ifname, retranstimer,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), rai->rai_retranstimer);
inconsistent++;
}
/* Values in the MTU options */
- if (ndopts.nd_opts_mtu) {
- mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
- if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
+ if (ndopts.opt_mtu) {
+ mtu = ntohl(ndopts.opt_mtu->nd_opt_mtu_mtu);
+ if (mtu && rai->rai_linkmtu && mtu != rai->rai_linkmtu) {
syslog(LOG_INFO,
- "<%s> MTU option value inconsistent on %s:"
- " %d from %s, %d from us",
- __func__,
- rai->ifname, mtu,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- rai->linkmtu);
+ "<%s> MTU option value inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__, rai->rai_ifname, mtu,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), rai->rai_linkmtu);
inconsistent++;
}
}
/* Preferred and Valid Lifetimes for prefixes */
{
- struct nd_optlist *optp = ndopts.nd_opts_list;
+ struct nd_optlist *nol;
- if (ndopts.nd_opts_pi) {
- if (prefix_check(ndopts.nd_opts_pi, rai, from))
+ if (ndopts.opt_pi)
+ if (prefix_check(ndopts.opt_pi, rai, from))
inconsistent++;
- }
- while (optp) {
- if (prefix_check((struct nd_opt_prefix_info *)optp->opt,
- rai, from))
+
+ TAILQ_FOREACH(nol, &ndopts.opt_list, nol_next)
+ if (prefix_check((struct nd_opt_prefix_info *)nol->nol_opt,
+ rai, from))
inconsistent++;
- optp = optp->next;
- }
}
if (inconsistent)
- rai->rainconsistent++;
-
+ rai->rai_rainconsistent++;
+
done:
free_ndopts(&ndopts);
return;
@@ -1100,51 +1245,49 @@ ra_input(int len, struct nd_router_advert *ra,
/* return a non-zero value if the received prefix is inconsitent with ours */
static int
prefix_check(struct nd_opt_prefix_info *pinfo,
- struct rainfo *rai, struct sockaddr_in6 *from)
+ struct rainfo *rai, struct sockaddr_in6 *from)
{
u_int32_t preferred_time, valid_time;
- struct prefix *pp;
+ struct prefix *pfx;
int inconsistent = 0;
- u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+ u_char prefixbuf[INET6_ADDRSTRLEN];
struct timeval now;
#if 0 /* impossible */
if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
- return(0);
+ return (0);
#endif
/*
* log if the adveritsed prefix has link-local scope(sanity check?)
*/
- if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) {
+ if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix))
syslog(LOG_INFO,
- "<%s> link-local prefix %s/%d is advertised "
- "from %s on %s",
- __func__,
- inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
- prefixbuf, INET6_ADDRSTRLEN),
- pinfo->nd_opt_pi_prefix_len,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- rai->ifname);
- }
-
- if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
- pinfo->nd_opt_pi_prefix_len)) == NULL) {
+ "<%s> link-local prefix %s/%d is advertised "
+ "from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
+ sizeof(prefixbuf)),
+ pinfo->nd_opt_pi_prefix_len,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), rai->rai_ifname);
+
+ if ((pfx = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
+ pinfo->nd_opt_pi_prefix_len)) == NULL) {
syslog(LOG_INFO,
- "<%s> prefix %s/%d from %s on %s is not in our list",
- __func__,
- inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
- prefixbuf, INET6_ADDRSTRLEN),
- pinfo->nd_opt_pi_prefix_len,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- rai->ifname);
- return(0);
+ "<%s> prefix %s/%d from %s on %s is not in our list",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
+ sizeof(prefixbuf)),
+ pinfo->nd_opt_pi_prefix_len,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), rai->rai_ifname);
+ return (0);
}
preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
- if (pp->pltimeexpire) {
+ if (pfx->pfx_pltimeexpire) {
/*
* The lifetime is decremented in real time, so we should
* compare the expiration time.
@@ -1155,134 +1298,135 @@ prefix_check(struct nd_opt_prefix_info *pinfo,
gettimeofday(&now, NULL);
preferred_time += now.tv_sec;
- if (!pp->timer && rai->clockskew &&
- abs(preferred_time - pp->pltimeexpire) > rai->clockskew) {
+ if (!pfx->pfx_timer && rai->rai_clockskew &&
+ abs(preferred_time - pfx->pfx_pltimeexpire) > rai->rai_clockskew) {
syslog(LOG_INFO,
- "<%s> preferred lifetime for %s/%d"
- " (decr. in real time) inconsistent on %s:"
- " %d from %s, %ld from us",
- __func__,
- inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
- prefixbuf, INET6_ADDRSTRLEN),
- pinfo->nd_opt_pi_prefix_len,
- rai->ifname, preferred_time,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- pp->pltimeexpire);
+ "<%s> preferred lifetime for %s/%d"
+ " (decr. in real time) inconsistent on %s:"
+ " %d from %s, %ld from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
+ sizeof(prefixbuf)),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->rai_ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), pfx->pfx_pltimeexpire);
inconsistent++;
}
- } else if (!pp->timer && preferred_time != pp->preflifetime) {
+ } else if (!pfx->pfx_timer && preferred_time != pfx->pfx_preflifetime)
syslog(LOG_INFO,
- "<%s> preferred lifetime for %s/%d"
- " inconsistent on %s:"
- " %d from %s, %d from us",
- __func__,
- inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
- prefixbuf, INET6_ADDRSTRLEN),
- pinfo->nd_opt_pi_prefix_len,
- rai->ifname, preferred_time,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- pp->preflifetime);
- }
+ "<%s> preferred lifetime for %s/%d"
+ " inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
+ sizeof(prefixbuf)),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->rai_ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), pfx->pfx_preflifetime);
valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
- if (pp->vltimeexpire) {
+ if (pfx->pfx_vltimeexpire) {
gettimeofday(&now, NULL);
valid_time += now.tv_sec;
- if (!pp->timer && rai->clockskew &&
- abs(valid_time - pp->vltimeexpire) > rai->clockskew) {
+ if (!pfx->pfx_timer && rai->rai_clockskew &&
+ abs(valid_time - pfx->pfx_vltimeexpire) > rai->rai_clockskew) {
syslog(LOG_INFO,
- "<%s> valid lifetime for %s/%d"
- " (decr. in real time) inconsistent on %s:"
- " %d from %s, %ld from us",
- __func__,
- inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
- prefixbuf, INET6_ADDRSTRLEN),
- pinfo->nd_opt_pi_prefix_len,
- rai->ifname, preferred_time,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- pp->vltimeexpire);
+ "<%s> valid lifetime for %s/%d"
+ " (decr. in real time) inconsistent on %s:"
+ " %d from %s, %ld from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
+ sizeof(prefixbuf)),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->rai_ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), pfx->pfx_vltimeexpire);
inconsistent++;
}
- } else if (!pp->timer && valid_time != pp->validlifetime) {
+ } else if (!pfx->pfx_timer && valid_time != pfx->pfx_validlifetime) {
syslog(LOG_INFO,
- "<%s> valid lifetime for %s/%d"
- " inconsistent on %s:"
- " %d from %s, %d from us",
- __func__,
- inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
- prefixbuf, INET6_ADDRSTRLEN),
- pinfo->nd_opt_pi_prefix_len,
- rai->ifname, valid_time,
- inet_ntop(AF_INET6, &from->sin6_addr,
- ntopbuf, INET6_ADDRSTRLEN),
- pp->validlifetime);
+ "<%s> valid lifetime for %s/%d"
+ " inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
+ sizeof(prefixbuf)),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->rai_ifname, valid_time,
+ inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), pfx->pfx_validlifetime);
inconsistent++;
}
- return(inconsistent);
+ return (inconsistent);
}
struct prefix *
find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
{
- struct prefix *pp;
+ struct prefix *pfx;
int bytelen, bitlen;
u_char bitmask;
- for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) {
- if (plen != pp->prefixlen)
+ TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
+ if (plen != pfx->pfx_prefixlen)
continue;
+
bytelen = plen / 8;
bitlen = plen % 8;
bitmask = 0xff << (8 - bitlen);
- if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen))
+
+ if (memcmp((void *)prefix, (void *)&pfx->pfx_prefix, bytelen))
continue;
+
if (bitlen == 0 ||
- ((prefix->s6_addr[bytelen] & bitmask) ==
- (pp->prefix.s6_addr[bytelen] & bitmask))) {
- return(pp);
+ ((prefix->s6_addr[bytelen] & bitmask) ==
+ (pfx->pfx_prefix.s6_addr[bytelen] & bitmask))) {
+ return (pfx);
}
}
- return(NULL);
+ return (NULL);
}
/* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */
int
prefix_match(struct in6_addr *p0, int plen0,
- struct in6_addr *p1, int plen1)
+ struct in6_addr *p1, int plen1)
{
int bytelen, bitlen;
u_char bitmask;
if (plen0 < plen1)
- return(0);
+ return (0);
+
bytelen = plen1 / 8;
bitlen = plen1 % 8;
bitmask = 0xff << (8 - bitlen);
+
if (memcmp((void *)p0, (void *)p1, bytelen))
- return(0);
+ return (0);
+
if (bitlen == 0 ||
((p0->s6_addr[bytelen] & bitmask) ==
(p1->s6_addr[bytelen] & bitmask))) {
- return(1);
+ return (1);
}
- return(0);
+ return (0);
}
static int
nd6_options(struct nd_opt_hdr *hdr, int limit,
- union nd_opts *ndopts, u_int32_t optflags)
+ union nd_opt *ndopts, u_int32_t optflags)
{
int optlen = 0;
for (; limit > 0; limit -= optlen) {
- if (limit < sizeof(struct nd_opt_hdr)) {
+ if ((size_t)limit < sizeof(struct nd_opt_hdr)) {
syslog(LOG_INFO, "<%s> short option header", __func__);
goto bad;
}
@@ -1300,7 +1444,9 @@ nd6_options(struct nd_opt_hdr *hdr, int limit,
goto bad;
}
- if (hdr->nd_opt_type > ND_OPT_MTU) {
+ if (hdr->nd_opt_type > ND_OPT_MTU &&
+ hdr->nd_opt_type != ND_OPT_RDNSS &&
+ hdr->nd_opt_type != ND_OPT_DNSSL) {
syslog(LOG_INFO, "<%s> unknown ND option(type %d)",
__func__, hdr->nd_opt_type);
continue;
@@ -1316,10 +1462,25 @@ nd6_options(struct nd_opt_hdr *hdr, int limit,
* Option length check. Do it here for all fixed-length
* options.
*/
- if ((hdr->nd_opt_type == ND_OPT_MTU &&
- (optlen != sizeof(struct nd_opt_mtu))) ||
- ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
- optlen != sizeof(struct nd_opt_prefix_info)))) {
+ switch (hdr->nd_opt_type) {
+ case ND_OPT_MTU:
+ if (optlen == sizeof(struct nd_opt_mtu))
+ break;
+ goto skip;
+ case ND_OPT_RDNSS:
+ if (optlen >= 24 &&
+ (optlen - sizeof(struct nd_opt_rdnss)) % 16 == 0)
+ break;
+ goto skip;
+ case ND_OPT_DNSSL:
+ if (optlen >= 16 &&
+ (optlen - sizeof(struct nd_opt_dnssl)) % 8 == 0)
+ break;
+ goto skip;
+ case ND_OPT_PREFIX_INFORMATION:
+ if (optlen == sizeof(struct nd_opt_prefix_info))
+ break;
+skip:
syslog(LOG_INFO, "<%s> invalid option length",
__func__);
continue;
@@ -1328,33 +1489,35 @@ nd6_options(struct nd_opt_hdr *hdr, int limit,
switch (hdr->nd_opt_type) {
case ND_OPT_TARGET_LINKADDR:
case ND_OPT_REDIRECTED_HEADER:
+ case ND_OPT_RDNSS:
+ case ND_OPT_DNSSL:
break; /* we don't care about these options */
case ND_OPT_SOURCE_LINKADDR:
case ND_OPT_MTU:
- if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
+ if (ndopts->opt_array[hdr->nd_opt_type]) {
syslog(LOG_INFO,
"<%s> duplicated ND option (type = %d)",
__func__, hdr->nd_opt_type);
}
- ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
+ ndopts->opt_array[hdr->nd_opt_type] = hdr;
break;
case ND_OPT_PREFIX_INFORMATION:
{
- struct nd_optlist *pfxlist;
+ struct nd_optlist *nol;
- if (ndopts->nd_opts_pi == 0) {
- ndopts->nd_opts_pi =
+ if (ndopts->opt_pi == 0) {
+ ndopts->opt_pi =
(struct nd_opt_prefix_info *)hdr;
continue;
}
- if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
+ nol = malloc(sizeof(*nol));
+ if (nol == NULL) {
syslog(LOG_ERR, "<%s> can't allocate memory",
__func__);
goto bad;
}
- pfxlist->next = ndopts->nd_opts_list;
- pfxlist->opt = hdr;
- ndopts->nd_opts_list = pfxlist;
+ nol->nol_opt = hdr;
+ TAILQ_INSERT_TAIL(&(ndopts->opt_list), nol, nol_next);
break;
}
@@ -1363,46 +1526,45 @@ nd6_options(struct nd_opt_hdr *hdr, int limit,
}
}
- return(0);
+ return (0);
bad:
free_ndopts(ndopts);
- return(-1);
+ return (-1);
}
static void
-free_ndopts(union nd_opts *ndopts)
+free_ndopts(union nd_opt *ndopts)
{
- struct nd_optlist *opt = ndopts->nd_opts_list, *next;
+ struct nd_optlist *nol;
- while (opt) {
- next = opt->next;
- free(opt);
- opt = next;
+ while ((nol = TAILQ_FIRST(&ndopts->opt_list)) != NULL) {
+ TAILQ_REMOVE(&ndopts->opt_list, nol, nol_next);
+ free(nol);
}
}
void
-sock_open()
+sock_open(void)
{
struct icmp6_filter filt;
struct ipv6_mreq mreq;
- struct rainfo *ra = ralist;
+ struct rainfo *rai;
int on;
/* XXX: should be max MTU attached to the node */
static u_char answer[1500];
rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
- CMSG_SPACE(sizeof(int));
+ CMSG_SPACE(sizeof(int));
rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen);
if (rcvcmsgbuf == NULL) {
syslog(LOG_ERR, "<%s> not enough core", __func__);
exit(1);
}
- sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
- CMSG_SPACE(sizeof(int));
+ sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen);
if (sndcmsgbuf == NULL) {
syslog(LOG_ERR, "<%s> not enough core", __func__);
@@ -1410,113 +1572,84 @@ sock_open()
}
if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
- syslog(LOG_ERR, "<%s> socket: %s", __func__,
- strerror(errno));
+ syslog(LOG_ERR, "<%s> socket: %s", __func__, strerror(errno));
exit(1);
}
-
/* specify to tell receiving interface */
on = 1;
-#ifdef IPV6_RECVPKTINFO
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
- sizeof(on)) < 0) {
- syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s",
- __func__, strerror(errno));
- exit(1);
- }
-#else /* old adv. API */
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
- sizeof(on)) < 0) {
- syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s",
- __func__, strerror(errno));
+ sizeof(on)) < 0) {
+ syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", __func__,
+ strerror(errno));
exit(1);
}
-#endif
-
on = 1;
/* specify to tell value of hoplimit field of received IP6 hdr */
-#ifdef IPV6_RECVHOPLIMIT
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
- sizeof(on)) < 0) {
- syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s",
- __func__, strerror(errno));
- exit(1);
- }
-#else /* old adv. API */
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
- sizeof(on)) < 0) {
- syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s",
- __func__, strerror(errno));
+ sizeof(on)) < 0) {
+ syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", __func__,
+ strerror(errno));
exit(1);
}
-#endif
-
ICMP6_FILTER_SETBLOCKALL(&filt);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
if (accept_rr)
ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
+
if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
- sizeof(filt)) < 0) {
+ sizeof(filt)) < 0) {
syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s",
- __func__, strerror(errno));
+ __func__, strerror(errno));
exit(1);
}
/*
* join all routers multicast address on each advertising interface.
*/
- if (inet_pton(AF_INET6, ALLROUTERS_LINK,
- &mreq.ipv6mr_multiaddr.s6_addr)
- != 1) {
- syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)",
- __func__);
- exit(1);
- }
- while (ra) {
- mreq.ipv6mr_interface = ra->ifindex;
+ memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
+ &sin6_linklocal_allrouters.sin6_addr,
+ sizeof(mreq.ipv6mr_multiaddr.s6_addr));
+ TAILQ_FOREACH(rai, &railist, rai_next) {
+ mreq.ipv6mr_interface = rai->rai_ifindex;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
- sizeof(mreq)) < 0) {
+ sizeof(mreq)) < 0) {
syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %s",
- __func__, ra->ifname, strerror(errno));
+ __func__, rai->rai_ifname, strerror(errno));
exit(1);
}
- ra = ra->next;
}
/*
* When attending router renumbering, join all-routers site-local
- * multicast group.
+ * multicast group.
*/
if (accept_rr) {
- if (inet_pton(AF_INET6, ALLROUTERS_SITE,
- &in6a_site_allrouters) != 1) {
- syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)",
- __func__);
- exit(1);
- }
- mreq.ipv6mr_multiaddr = in6a_site_allrouters;
+ memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
+ &sin6_sitelocal_allrouters.sin6_addr,
+ sizeof(mreq.ipv6mr_multiaddr.s6_addr));
if (mcastif) {
if ((mreq.ipv6mr_interface = if_nametoindex(mcastif))
== 0) {
syslog(LOG_ERR,
- "<%s> invalid interface: %s",
- __func__, mcastif);
+ "<%s> invalid interface: %s",
+ __func__, mcastif);
exit(1);
}
} else
- mreq.ipv6mr_interface = ralist->ifindex;
+ mreq.ipv6mr_interface =
+ TAILQ_FIRST(&railist)->rai_ifindex;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
- &mreq, sizeof(mreq)) < 0) {
+ &mreq, sizeof(mreq)) < 0) {
syslog(LOG_ERR,
- "<%s> IPV6_JOIN_GROUP(site) on %s: %s",
- __func__,
- mcastif ? mcastif : ralist->ifname,
- strerror(errno));
+ "<%s> IPV6_JOIN_GROUP(site) on %s: %s", __func__,
+ mcastif ? mcastif :
+ TAILQ_FIRST(&railist)->rai_ifname,
+ strerror(errno));
exit(1);
}
}
-
+
/* initialize msghdr for receiving packets */
rcviov[0].iov_base = (caddr_t)answer;
rcviov[0].iov_len = sizeof(answer);
@@ -1533,17 +1666,17 @@ sock_open()
sndmhdr.msg_iovlen = 1;
sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
sndmhdr.msg_controllen = sndcmsgbuflen;
-
+
return;
}
/* open a routing socket to watch the routing table */
static void
-rtsock_open()
+rtsock_open(void)
{
if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
syslog(LOG_ERR,
- "<%s> socket: %s", __func__, strerror(errno));
+ "<%s> socket: %s", __func__, strerror(errno));
exit(1);
}
}
@@ -1551,36 +1684,72 @@ rtsock_open()
struct rainfo *
if_indextorainfo(int idx)
{
- struct rainfo *rai = ralist;
+ struct rainfo *rai;
- for (rai = ralist; rai; rai = rai->next) {
- if (rai->ifindex == idx)
- return(rai);
+ TAILQ_FOREACH(rai, &railist, rai_next) {
+ syslog(LOG_DEBUG, "<%s> rai->rai_ifindex %d == idx %d?",
+ __func__, rai->rai_ifindex, idx);
+ if (rai->rai_ifindex == idx)
+ return (rai);
}
- return(NULL); /* search failed */
+ return (NULL); /* search failed */
}
-static void
-ra_output(rainfo)
-struct rainfo *rainfo;
+void
+ra_output(struct rainfo *rai)
{
int i;
struct cmsghdr *cm;
struct in6_pktinfo *pi;
- struct soliciter *sol, *nextsol;
+ struct soliciter *sol;
- if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) {
+ if ((iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) == 0) {
syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA",
- __func__, rainfo->ifname);
+ __func__, rai->rai_ifname);
return;
}
- make_packet(rainfo); /* XXX: inefficient */
+ /*
+ * Check lifetime, ACCEPT_RTADV flag, and ip6.forwarding.
+ *
+ * (lifetime == 0) = output
+ * (lifetime != 0 && (ACCEPT_RTADV || !ip6.forwarding) = no output
+ *
+ * Basically, hosts MUST NOT send Router Advertisement
+ * messages at any time (RFC 4861, Section 6.2.3). However, it
+ * would sometimes be useful to allow hosts to advertise some
+ * parameters such as prefix information and link MTU. Thus,
+ * we allow hosts to invoke rtadvd only when router lifetime
+ * (on every advertising interface) is explicitly set
+ * zero. (see also the above section)
+ */
+ syslog(LOG_DEBUG,
+ "<%s> check lifetime=%d, ACCEPT_RTADV=%d, ip6.forwarding=%d on %s",
+ __func__, rai->rai_lifetime, check_accept_rtadv(rai->rai_ifindex),
+ getinet6sysctl(IPV6CTL_FORWARDING), rai->rai_ifname);
+ if (rai->rai_lifetime != 0) {
+ if (check_accept_rtadv(rai->rai_ifindex)) {
+ syslog(LOG_INFO,
+ "<%s> non-zero lifetime RA "
+ "on RA receiving interface %s."
+ " Ignored.", __func__, rai->rai_ifname);
+ return;
+ }
+ if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) {
+ syslog(LOG_INFO,
+ "<%s> non-zero lifetime RA "
+ "but net.inet6.ip6.forwarding=0. "
+ "Ignored.", __func__);
+ return;
+ }
+ }
+
+ make_packet(rai); /* XXX: inefficient */
- sndmhdr.msg_name = (caddr_t)&sin6_allnodes;
- sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data;
- sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen;
+ sndmhdr.msg_name = (caddr_t)&sin6_linklocal_allnodes;
+ sndmhdr.msg_iov[0].iov_base = (caddr_t)rai->rai_ra_data;
+ sndmhdr.msg_iov[0].iov_len = rai->rai_ra_datalen;
cm = CMSG_FIRSTHDR(&sndmhdr);
/* specify the outgoing interface */
@@ -1589,7 +1758,7 @@ struct rainfo *rainfo;
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
pi = (struct in6_pktinfo *)CMSG_DATA(cm);
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
- pi->ipi6_ifindex = rainfo->ifindex;
+ pi->ipi6_ifindex = rai->rai_ifindex;
/* specify the hop limit of the packet */
{
@@ -1603,80 +1772,79 @@ struct rainfo *rainfo;
}
syslog(LOG_DEBUG,
- "<%s> send RA on %s, # of waitings = %d",
- __func__, rainfo->ifname, rainfo->waiting);
+ "<%s> send RA on %s, # of waitings = %d",
+ __func__, rai->rai_ifname, rai->rai_waiting);
i = sendmsg(sock, &sndmhdr, 0);
- if (i < 0 || i != rainfo->ra_datalen) {
+ if (i < 0 || (size_t)i != rai->rai_ra_datalen) {
if (i < 0) {
syslog(LOG_ERR, "<%s> sendmsg on %s: %s",
- __func__, rainfo->ifname,
- strerror(errno));
+ __func__, rai->rai_ifname,
+ strerror(errno));
}
}
/* update counter */
- if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
- rainfo->initcounter++;
- rainfo->raoutput++;
+ if (rai->rai_initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
+ rai->rai_initcounter++;
+ rai->rai_raoutput++;
/*
* unicast advertisements
* XXX commented out. reason: though spec does not forbit it, unicast
* advert does not really help
*/
- for (sol = rainfo->soliciter; sol; sol = nextsol) {
- nextsol = sol->next;
-
- sol->next = NULL;
+ while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) {
+ TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next);
free(sol);
}
- rainfo->soliciter = NULL;
/* update timestamp */
- gettimeofday(&rainfo->lastsent, NULL);
+ gettimeofday(&rai->rai_lastsent, NULL);
/* reset waiting conter */
- rainfo->waiting = 0;
+ rai->rai_waiting = 0;
}
/* process RA timer */
struct rtadvd_timer *
-ra_timeout(void *data)
+ra_timeout(void *arg)
{
- struct rainfo *rai = (struct rainfo *)data;
+ struct rainfo *rai;
#ifdef notyet
/* if necessary, reconstruct the packet. */
#endif
-
- syslog(LOG_DEBUG,
- "<%s> RA timer on %s is expired",
- __func__, rai->ifname);
+ rai = (struct rainfo *)arg;
+ syslog(LOG_DEBUG, "<%s> RA timer on %s is expired",
+ __func__, rai->rai_ifname);
ra_output(rai);
- return(rai->timer);
+ return (rai->rai_timer);
}
/* update RA timer */
void
-ra_timer_update(void *data, struct timeval *tm)
+ra_timer_update(void *arg, struct timeval *tm)
{
- struct rainfo *rai = (struct rainfo *)data;
long interval;
+ struct rainfo *rai;
+ rai = (struct rainfo *)arg;
/*
* Whenever a multicast advertisement is sent from an interface,
* the timer is reset to a uniformly-distributed random value
* between the interface's configured MinRtrAdvInterval and
* MaxRtrAdvInterval (RFC2461 6.2.4).
*/
- interval = rai->mininterval;
+ interval = rai->rai_mininterval;
#ifdef HAVE_ARC4RANDOM
- interval += arc4random_uniform(rai->maxinterval - rai->mininterval);
+ interval += arc4random_uniform(rai->rai_maxinterval -
+ rai->rai_mininterval);
#else
- interval += random() % (rai->maxinterval - rai->mininterval);
+ interval += random() % (rai->rai_maxinterval -
+ rai->rai_mininterval);
#endif
/*
@@ -1684,9 +1852,9 @@ ra_timer_update(void *data, struct timeval *tm)
* MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval
* is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer
* SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead.
- * (RFC-2461 6.2.4)
+ * (RFC 4861 6.2.4)
*/
- if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
+ if (rai->rai_initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
@@ -1694,9 +1862,9 @@ ra_timer_update(void *data, struct timeval *tm)
tm->tv_usec = 0;
syslog(LOG_DEBUG,
- "<%s> RA timer on %s is set to %ld:%ld",
- __func__, rai->ifname,
- (long int)tm->tv_sec, (long int)tm->tv_usec);
+ "<%s> RA timer on %s is set to %ld:%ld",
+ __func__, rai->rai_ifname,
+ (long int)tm->tv_sec, (long int)tm->tv_usec);
return;
}
diff --git a/usr.sbin/rtadvd/rtadvd.conf b/usr.sbin/rtadvd/rtadvd.conf
index 33ab7f3..1e42c75 100644
--- a/usr.sbin/rtadvd/rtadvd.conf
+++ b/usr.sbin/rtadvd/rtadvd.conf
@@ -18,4 +18,5 @@
# this part by hand, and then invoke rtadvd with the -s option.
#ef0:\
-# :addr="3ffe:501:ffff:1000::":prefixlen#64:
+# :addr="2001:db8:ffff:1000::":prefixlen#64:\
+# :rdnss="2001:db8:ffff:1000::1":dnssl="example.com":
diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5
index 81ffa70..ba2f490 100644
--- a/usr.sbin/rtadvd/rtadvd.conf.5
+++ b/usr.sbin/rtadvd/rtadvd.conf.5
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 17, 1998
+.Dd June 4, 2011
.Dt RTADVD.CONF 5
.Os
.Sh NAME
@@ -179,10 +179,25 @@ will automatically get appropriate prefixes from the kernel's routing table,
and advertise the prefixes with the default parameters.
Keywords other than
.Cm clockskew
+and
+.Cm noifprefix
can be augmented with a number, like
.Dq Li prefix2 ,
to specify multiple prefixes.
.Bl -tag -width indent
+.It Cm \&noifprefix
+(bool) Specifies no prefix on the network interfaces will be advertised.
+By default
+.Nm rtadvd
+automatically gathers on-link prefixes from all of the network interfaces
+and advertise them.
+The
+.Cm noifprefix
+disables that behavior.
+If this is specified and no
+.Cm addr
+keyword is specified, no prefix information option will be included in the
+message.
.It Cm \&clockskew
(num) Time skew to adjust link propagation delays and clock skews
between routers on the link
@@ -355,6 +370,66 @@ However, keywords that start with
.Dq Li rtr
have basically been obsoleted, and should not be used any more.
.Pp
+The following items are for ICMPv6 Recursive DNS Server Option and
+DNS Search List Option
+.Pq RFC 6106 ,
+which will be attached to router advertisement header.
+These items are optional.
+.Bl -tag -width indent
+.It Cm \&rdnss
+(str) The IPv6 address of one or more recursive DNS servers.
+The argument must be inside double quotes.
+Multiple DNS servers can be specified in a comma-separated string.
+If different lifetimes are needed for different servers,
+separate entries can be given by using
+.Cm rdnss ,
+.Cm rdnss0 ,
+.Cm rdnss1 ,
+.Cm rdnss2 ...
+options with corresponding
+.Cm rdnssltime ,
+.Cm rdnssltime0 ,
+.Cm rdnssltime1 ,
+.Cm rdnssltime2 ...
+entries.
+Note that the maximum number of servers depends on the receiver side.
+See also
+.Xr resolver 5
+manual page for resolver implementation in
+.Fx .
+.It Cm \&rdnssltime
+The lifetime of the
+.Cm rdnss
+DNS server entries.
+The default value is 3/2 of the interval time.
+.It Cm \&dnssl
+(str) One or more domain names in a comma-separated string.
+These domain names will be used when making DNS queries on a
+non-fully-qualified domain name.
+If different lifetimes are needed for different domains, separate entries
+can be given by using
+.Cm dnssl ,
+.Cm dnssl0 ,
+.Cm dnssl1 ,
+.Cm dnssl2 ...
+options with corresponding
+.Cm dnsslltime ,
+.Cm dnsslltime0 ,
+.Cm dnsslltime1 ,
+.Cm dnsslltime2 ...
+entries.
+Note that the maximum number of names depends on the receiver side.
+See also
+.Xr resolver 5
+manual page for resolver implementation in
+.Fx .
+.It Cm \&dnsslltime
+The lifetime of the
+.Cm dnssl
+DNS search list entries.
+The default value is 3/2 of the interval time.
+.El
+.Pp
You can also refer one line from another by using
.Cm tc
capability.
@@ -388,7 +463,18 @@ option to
.Xr rtadvd 8 .
.Bd -literal -offset
ef0:\\
- :addr="3ffe:501:ffff:1000::":prefixlen#64:
+ :addr="2001:db8:ffff:1000::":prefixlen#64:
+.Ed
+.Pp
+The following example configures the
+.Li wlan0
+interface and adds two DNS servers and a DNS domain search options
+using the default option lifetime values.
+.Bd -literal -offset
+wlan0:\\
+ :addr="2001:db8:ffff:1000::":prefixlen#64:\\
+ :rdnss="2001:db8:ffff::10,2001:db8:ffff::2:43":\\
+ :dnssl="example.com":
.Ed
.Pp
The following example presents the default values in an explicit manner.
@@ -399,24 +485,41 @@ default:\\
:chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\
:pinfoflags="la":vltime#2592000:pltime#604800:mtu#0:
ef0:\\
- :addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default:
+ :addr="2001:db8:ffff:1000::":prefixlen#64:tc=default:
.Ed
.Sh SEE ALSO
.Xr termcap 5 ,
+.Xr resolver 5 ,
.Xr rtadvd 8 ,
.Xr rtsol 8
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
+.%A Hesham Soliman
.%T Neighbor Discovery for IP version 6 (IPv6)
-.%R RFC 2461
+.%R RFC 4861
+.Re
+.Rs
+.%A Thomas Narten
+.%A Erik Nordmark
+.%A W. A. Simpson
+.%T Neighbor Discovery for IP version 6 (IPv6)
+.%R RFC 2461 (obsoleted by RFC 4861)
.Re
.Rs
.%A Richard Draves
.%T Default Router Preferences and More-Specific Routes
.%R draft-ietf-ipngwg-router-selection-xx.txt
.Re
+.Rs
+.%A J. Jeong
+.%A S. Park
+.%A L. Beloeil
+.%A S. Madanapalli
+.%T IPv6 Router Advertisement Options for DNS Configuration
+.%R RFC 6106
+.Re
.Sh HISTORY
The
.Xr rtadvd 8
diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h
index 828fec6..190bb0d 100644
--- a/usr.sbin/rtadvd/rtadvd.h
+++ b/usr.sbin/rtadvd/rtadvd.h
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -30,11 +30,41 @@
* SUCH DAMAGE.
*/
-#define ALLNODES "ff02::1"
-#define ALLROUTERS_LINK "ff02::2"
-#define ALLROUTERS_SITE "ff05::2"
-#define ANY "::"
-#define RTSOLLEN 8
+#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
+ {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
+
+#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
+ {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
+
+#define IN6ADDR_SITELOCAL_ALLROUTERS_INIT \
+ {{{ 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
+
+extern struct sockaddr_in6 sin6_linklocal_allnodes;
+extern struct sockaddr_in6 sin6_linklocal_allrouters;
+extern struct sockaddr_in6 sin6_sitelocal_allrouters;
+
+/*
+ * RFC 3542 API deprecates IPV6_PKTINFO in favor of
+ * IPV6_RECVPKTINFO
+ */
+#ifndef IPV6_RECVPKTINFO
+#ifdef IPV6_PKTINFO
+#define IPV6_RECVPKTINFO IPV6_PKTINFO
+#endif
+#endif
+
+/*
+ * RFC 3542 API deprecates IPV6_HOPLIMIT in favor of
+ * IPV6_RECVHOPLIMIT
+ */
+#ifndef IPV6_RECVHOPLIMIT
+#ifdef IPV6_HOPLIMIT
+#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
+#endif
+#endif
/* protocol constants and default values */
#define DEF_MAXRTRADVINTERVAL 600
@@ -62,100 +92,151 @@
#define PREFIX_FROM_DYNAMIC 3
struct prefix {
- struct prefix *next; /* forward link */
- struct prefix *prev; /* previous link */
-
- struct rainfo *rainfo; /* back pointer to the interface */
-
- struct rtadvd_timer *timer; /* expiration timer. used when a prefix
- * derived from the kernel is deleted.
- */
-
- u_int32_t validlifetime; /* AdvValidLifetime */
- long vltimeexpire; /* expiration of vltime; decrement case only */
- u_int32_t preflifetime; /* AdvPreferredLifetime */
- long pltimeexpire; /* expiration of pltime; decrement case only */
- u_int onlinkflg; /* bool: AdvOnLinkFlag */
- u_int autoconfflg; /* bool: AdvAutonomousFlag */
- int prefixlen;
- int origin; /* from kernel or config */
- struct in6_addr prefix;
+ TAILQ_ENTRY(prefix) pfx_next;
+
+ struct rainfo *pfx_rainfo; /* back pointer to the interface */
+ /*
+ * Expiration timer. This is used when a prefix derived from
+ * the kernel is deleted.
+ */
+ struct rtadvd_timer *pfx_timer;
+
+ u_int32_t pfx_validlifetime; /* AdvValidLifetime */
+ long pfx_vltimeexpire; /* Expiration of vltime */
+ u_int32_t pfx_preflifetime; /* AdvPreferredLifetime */
+ long pfx_pltimeexpire; /* Expiration of pltime */
+ u_int pfx_onlinkflg; /* bool: AdvOnLinkFlag */
+ u_int pfx_autoconfflg; /* bool: AdvAutonomousFlag */
+ int pfx_prefixlen;
+ int pfx_origin; /* From kernel or config */
+
+ struct in6_addr pfx_prefix;
};
#ifdef ROUTEINFO
struct rtinfo {
- struct rtinfo *prev; /* previous link */
- struct rtinfo *next; /* forward link */
+ TAILQ_ENTRY(rtinfo) rti_next;
- u_int32_t ltime; /* route lifetime */
- u_int rtpref; /* route preference */
- int prefixlen;
- struct in6_addr prefix;
+ u_int32_t rti_ltime; /* route lifetime */
+ u_int rti_rtpref; /* route preference */
+ int rti_prefixlen;
+ struct in6_addr rti_prefix;
};
#endif
+struct rdnss_addr {
+ TAILQ_ENTRY(rdnss_addr) ra_next;
+
+ struct in6_addr ra_dns; /* DNS server entry */
+};
+
+struct rdnss {
+ TAILQ_ENTRY(rdnss) rd_next;
+
+ TAILQ_HEAD(, rdnss_addr) rd_list; /* list of DNS servers */
+ int rd_cnt; /* number of DNS servers */
+ u_int32_t rd_ltime; /* number of seconds valid */
+};
+
+/*
+ * The maximum length of a domain name in a DNS search list is calculated
+ * by a domain name + length fields per 63 octets + a zero octet at
+ * the tail and adding 8 octet boundary padding.
+ */
+#define _DNAME_LABELENC_MAXLEN \
+ (NI_MAXHOST + (NI_MAXHOST / 64 + 1) + 1)
+
+#define DNAME_LABELENC_MAXLEN \
+ (_DNAME_LABELENC_MAXLEN + 8 - _DNAME_LABELENC_MAXLEN % 8)
+
+struct dnssl_addr {
+ TAILQ_ENTRY(dnssl_addr) da_next;
+
+ int da_len; /* length of entry */
+ char da_dom[DNAME_LABELENC_MAXLEN]; /* search domain name entry */
+};
+
+struct dnssl {
+ TAILQ_ENTRY(dnssl) dn_next;
+
+ TAILQ_HEAD(, dnssl_addr) dn_list; /* list of search domains */
+ u_int32_t dn_ltime; /* number of seconds valid */
+};
+
struct soliciter {
- struct soliciter *next;
- struct sockaddr_in6 addr;
+ TAILQ_ENTRY(soliciter) sol_next;
+
+ struct sockaddr_in6 sol_addr;
};
struct rainfo {
/* pointer for list */
- struct rainfo *next;
+ TAILQ_ENTRY(rainfo) rai_next;
/* timer related parameters */
- struct rtadvd_timer *timer;
- int initcounter; /* counter for the first few advertisements */
- struct timeval lastsent; /* timestamp when the latest RA was sent */
- int waiting; /* number of RS waiting for RA */
+ struct rtadvd_timer *rai_timer;
+ /* counter for the first few advertisements */
+ int rai_initcounter;
+ /* timestamp when the latest RA was sent */
+ struct timeval rai_lastsent;
+ /* number of RS waiting for RA */
+ int rai_waiting;
/* interface information */
- int ifindex;
- int advlinkopt; /* bool: whether include link-layer addr opt */
- struct sockaddr_dl *sdl;
- char ifname[16];
- int phymtu; /* mtu of the physical interface */
+ int rai_ifindex;
+ int rai_advlinkopt; /* bool: whether include link-layer addr opt */
+ int rai_advifprefix; /* bool: gather IF prefixes? */
+ struct sockaddr_dl *rai_sdl;
+ char rai_ifname[IFNAMSIZ];
+ u_int32_t rai_phymtu; /* mtu of the physical interface */
/* Router configuration variables */
- u_short lifetime; /* AdvDefaultLifetime */
- u_int maxinterval; /* MaxRtrAdvInterval */
- u_int mininterval; /* MinRtrAdvInterval */
- int managedflg; /* AdvManagedFlag */
- int otherflg; /* AdvOtherConfigFlag */
-
- int rtpref; /* router preference */
- u_int32_t linkmtu; /* AdvLinkMTU */
- u_int32_t reachabletime; /* AdvReachableTime */
- u_int32_t retranstimer; /* AdvRetransTimer */
- u_int hoplimit; /* AdvCurHopLimit */
- struct prefix prefix; /* AdvPrefixList(link head) */
- int pfxs; /* number of prefixes */
- long clockskew; /* used for consisitency check of lifetimes */
+ u_short rai_lifetime; /* AdvDefaultLifetime */
+ u_int rai_maxinterval; /* MaxRtrAdvInterval */
+ u_int rai_mininterval; /* MinRtrAdvInterval */
+ int rai_managedflg; /* AdvManagedFlag */
+ int rai_otherflg; /* AdvOtherConfigFlag */
+ int rai_rtpref; /* router preference */
+ u_int32_t rai_linkmtu; /* AdvLinkMTU */
+ u_int32_t rai_reachabletime; /* AdvReachableTime */
+ u_int32_t rai_retranstimer; /* AdvRetransTimer */
+ u_int rai_hoplimit; /* AdvCurHopLimit */
+
+ TAILQ_HEAD(, prefix) rai_prefix;/* AdvPrefixList(link head) */
+ int rai_pfxs; /* number of prefixes */
+
+ long rai_clockskew; /* used for consisitency check of lifetimes */
+
+ TAILQ_HEAD(, rdnss) rai_rdnss; /* DNS server list */
+ TAILQ_HEAD(, dnssl) rai_dnssl; /* search domain list */
#ifdef ROUTEINFO
- struct rtinfo route; /* route information option (link head) */
- int routes; /* number of route information options */
+ TAILQ_HEAD(, rtinfo) rai_route; /* route information option (link head) */
+ int rai_routes; /* number of route information options */
#endif
-
/* actual RA packet data and its length */
- size_t ra_datalen;
- u_char *ra_data;
+ size_t rai_ra_datalen;
+ u_char *rai_ra_data;
/* statistics */
- u_quad_t raoutput; /* number of RAs sent */
- u_quad_t rainput; /* number of RAs received */
- u_quad_t rainconsistent; /* number of RAs inconsistent with ours */
- u_quad_t rsinput; /* number of RSs received */
+ u_quad_t rai_raoutput; /* # of RAs sent */
+ u_quad_t rai_rainput; /* # of RAs received */
+ u_quad_t rai_rainconsistent; /* # of RAs inconsistent with ours */
+ u_quad_t rai_rsinput; /* # of RSs received */
/* info about soliciter */
- struct soliciter *soliciter; /* recent solication source */
+ TAILQ_HEAD(, soliciter) rai_soliciter; /* recent solication source */
};
-struct rtadvd_timer *ra_timeout(void *);
-void ra_timer_update(void *, struct timeval *);
+/* Interface list including RA information */
+extern TAILQ_HEAD(railist_head_t, rainfo) railist;
-int prefix_match(struct in6_addr *, int, struct in6_addr *, int);
-struct rainfo *if_indextorainfo(int);
-struct prefix *find_prefix(struct rainfo *, struct in6_addr *, int);
+struct rtadvd_timer *ra_timeout(void *);
+void ra_timer_update(void *, struct timeval *);
+void ra_output(struct rainfo *);
-extern struct in6_addr in6a_site_allrouters;
+int prefix_match(struct in6_addr *, int,
+ struct in6_addr *, int);
+struct rainfo *if_indextorainfo(int);
+struct prefix *find_prefix(struct rainfo *,
+ struct in6_addr *, int);
diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c
index 7fb0902..8cad6ad 100644
--- a/usr.sbin/rtadvd/timer.c
+++ b/usr.sbin/rtadvd/timer.c
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -31,6 +31,7 @@
*/
#include <sys/time.h>
+#include <sys/queue.h>
#include <unistd.h>
#include <syslog.h>
@@ -39,21 +40,19 @@
#include <search.h>
#include "timer.h"
-static struct rtadvd_timer timer_head;
-
#define MILLION 1000000
-#define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\
- (t1)->tv_usec == (t2)->tv_usec)
-static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
+struct rtadvd_timer_head_t ra_timer =
+ TAILQ_HEAD_INITIALIZER(ra_timer);
+static struct timeval tm_limit = {0x7fffffff, 0x7fffffff};
+static struct timeval tm_max;
void
-rtadvd_timer_init()
+rtadvd_timer_init(void)
{
- memset(&timer_head, 0, sizeof(timer_head));
- timer_head.next = timer_head.prev = &timer_head;
- timer_head.tm = tm_max;
+ tm_max = tm_limit;
+ TAILQ_INIT(&ra_timer);
}
struct rtadvd_timer *
@@ -61,54 +60,57 @@ rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
void (*update)(void *, struct timeval *),
void *timeodata, void *updatedata)
{
- struct rtadvd_timer *newtimer;
+ struct rtadvd_timer *rat;
- if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
+ if (timeout == NULL) {
syslog(LOG_ERR,
- "<%s> can't allocate memory", __func__);
+ "<%s> timeout function unspecified", __func__);
exit(1);
}
- memset(newtimer, 0, sizeof(*newtimer));
-
- if (timeout == NULL) {
+ rat = malloc(sizeof(*rat));
+ if (rat == NULL) {
syslog(LOG_ERR,
- "<%s> timeout function unspecified", __func__);
+ "<%s> can't allocate memory", __func__);
exit(1);
}
- newtimer->expire = timeout;
- newtimer->update = update;
- newtimer->expire_data = timeodata;
- newtimer->update_data = updatedata;
- newtimer->tm = tm_max;
+ memset(rat, 0, sizeof(*rat));
+
+ rat->rat_expire = timeout;
+ rat->rat_update = update;
+ rat->rat_expire_data = timeodata;
+ rat->rat_update_data = updatedata;
+ rat->rat_tm = tm_max;
/* link into chain */
- insque(newtimer, &timer_head);
+ TAILQ_INSERT_TAIL(&ra_timer, rat, rat_next);
- return(newtimer);
+ return (rat);
}
void
-rtadvd_remove_timer(struct rtadvd_timer **timer)
+rtadvd_remove_timer(struct rtadvd_timer *rat)
{
- remque(*timer);
- free(*timer);
- *timer = NULL;
+
+ if (rat == NULL)
+ return;
+
+ TAILQ_REMOVE(&ra_timer, rat, rat_next);
+ free(rat);
}
void
-rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
+rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *rat)
{
struct timeval now;
/* reset the timer */
gettimeofday(&now, NULL);
-
- TIMEVAL_ADD(&now, tm, &timer->tm);
+ TIMEVAL_ADD(&now, tm, &rat->rat_tm);
/* update the next expiration time */
- if (TIMEVAL_LT(timer->tm, timer_head.tm))
- timer_head.tm = timer->tm;
+ if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
+ tm_max = rat->rat_tm;
return;
}
@@ -119,58 +121,52 @@ rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
* Return the next interval for select() call.
*/
struct timeval *
-rtadvd_check_timer()
+rtadvd_check_timer(void)
{
static struct timeval returnval;
struct timeval now;
- struct rtadvd_timer *tm = timer_head.next, *tm_next;
+ struct rtadvd_timer *rat;
gettimeofday(&now, NULL);
-
- timer_head.tm = tm_max;
-
- for (tm = timer_head.next; tm != &timer_head; tm = tm_next) {
- tm_next = tm->next;
-
- if (TIMEVAL_LEQ(tm->tm, now)) {
- if (((*tm->expire)(tm->expire_data) == NULL))
+ tm_max = tm_limit;
+ TAILQ_FOREACH(rat, &ra_timer, rat_next) {
+ if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
+ if (((*rat->rat_expire)(rat->rat_expire_data) == NULL))
continue; /* the timer was removed */
- if (tm->update)
- (*tm->update)(tm->update_data, &tm->tm);
- TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
+ if (rat->rat_update)
+ (*rat->rat_update)(rat->rat_update_data, &rat->rat_tm);
+ TIMEVAL_ADD(&rat->rat_tm, &now, &rat->rat_tm);
}
-
- if (TIMEVAL_LT(tm->tm, timer_head.tm))
- timer_head.tm = tm->tm;
+ if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
+ tm_max = rat->rat_tm;
}
-
- if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) {
+ if (TIMEVAL_EQUAL(&tm_max, &tm_limit)) {
/* no need to timeout */
- return(NULL);
- } else if (TIMEVAL_LT(timer_head.tm, now)) {
+ return (NULL);
+ } else if (TIMEVAL_LT(&tm_max, &now)) {
/* this may occur when the interval is too small */
returnval.tv_sec = returnval.tv_usec = 0;
} else
- TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
- return(&returnval);
+ TIMEVAL_SUB(&tm_max, &now, &returnval);
+ return (&returnval);
}
struct timeval *
-rtadvd_timer_rest(struct rtadvd_timer *timer)
+rtadvd_timer_rest(struct rtadvd_timer *rat)
{
static struct timeval returnval, now;
gettimeofday(&now, NULL);
- if (TIMEVAL_LEQ(timer->tm, now)) {
+ if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
syslog(LOG_DEBUG,
- "<%s> a timer must be expired, but not yet",
- __func__);
+ "<%s> a timer must be expired, but not yet",
+ __func__);
returnval.tv_sec = returnval.tv_usec = 0;
}
else
- TIMEVAL_SUB(&timer->tm, &now, &returnval);
+ TIMEVAL_SUB(&rat->rat_tm, &now, &returnval);
- return(&returnval);
+ return (&returnval);
}
/* result = a + b */
diff --git a/usr.sbin/rtadvd/timer.h b/usr.sbin/rtadvd/timer.h
index 4526103..e2e0c65 100644
--- a/usr.sbin/rtadvd/timer.h
+++ b/usr.sbin/rtadvd/timer.h
@@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -31,35 +31,42 @@
*/
/* a < b */
-#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\
- (((a).tv_sec == (b).tv_sec) && \
- ((a).tv_usec < (b).tv_usec)))
+#define TIMEVAL_LT(a, b) \
+ (((a)->tv_sec < (b)->tv_sec) || \
+ (((a)->tv_sec == (b)->tv_sec) && \
+ ((a)->tv_usec < (b)->tv_usec)))
/* a <= b */
-#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\
- (((a).tv_sec == (b).tv_sec) &&\
- ((a).tv_usec <= (b).tv_usec)))
+#define TIMEVAL_LEQ(a, b) \
+ (((a)->tv_sec < (b)->tv_sec) || \
+ (((a)->tv_sec == (b)->tv_sec) && \
+ ((a)->tv_usec <= (b)->tv_usec)))
+#define TIMEVAL_EQUAL(a,b) \
+ (((a)->tv_sec == (b)->tv_sec) && \
+ ((a)->tv_usec == (b)->tv_usec))
+
+extern TAILQ_HEAD(rtadvd_timer_head_t, rtadvd_timer) ra_timer;
struct rtadvd_timer {
- struct rtadvd_timer *next;
- struct rtadvd_timer *prev;
- struct rainfo *rai;
- struct timeval tm;
+ TAILQ_ENTRY(rtadvd_timer) rat_next;
- struct rtadvd_timer *(*expire)(void *); /* expiration function */
- void *expire_data;
- void (*update)(void *, struct timeval *); /* update function */
- void *update_data;
+ struct rainfo *rat_rai;
+ struct timeval rat_tm;
+ struct rtadvd_timer *(*rat_expire)(void *);
+ void *rat_expire_data;
+ void (*rat_update)(void *, struct timeval *);
+ void *rat_update_data;
};
-void rtadvd_timer_init(void);
-struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
- void (*)(void *, struct timeval *), void *, void *);
-void rtadvd_set_timer(struct timeval *, struct rtadvd_timer *);
-void rtadvd_remove_timer(struct rtadvd_timer **);
-struct timeval * rtadvd_check_timer(void);
-struct timeval * rtadvd_timer_rest(struct rtadvd_timer *);
-void TIMEVAL_ADD(struct timeval *, struct timeval *,
- struct timeval *);
-void TIMEVAL_SUB(struct timeval *, struct timeval *,
- struct timeval *);
+void rtadvd_timer_init(void);
+struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
+ void (*)(void *, struct timeval *), void *, void *);
+void rtadvd_set_timer(struct timeval *,
+ struct rtadvd_timer *);
+void rtadvd_remove_timer(struct rtadvd_timer *);
+struct timeval *rtadvd_check_timer(void);
+struct timeval *rtadvd_timer_rest(struct rtadvd_timer *);
+void TIMEVAL_ADD(struct timeval *, struct timeval *,
+ struct timeval *);
+void TIMEVAL_SUB(struct timeval *, struct timeval *,
+ struct timeval *);
diff --git a/usr.sbin/rtsold/dump.c b/usr.sbin/rtsold/dump.c
index 2756b87..52d4b62 100644
--- a/usr.sbin/rtsold/dump.c
+++ b/usr.sbin/rtsold/dump.c
@@ -34,10 +34,12 @@
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
+#include <arpa/inet.h>
#include <syslog.h>
#include <time.h>
@@ -52,47 +54,73 @@ static FILE *fp;
extern struct ifinfo *iflist;
static void dump_interface_status(void);
-static const char *sec2str(time_t);
static const char * const ifstatstr[] = {"IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE"};
static void
dump_interface_status(void)
{
- struct ifinfo *ifinfo;
+ struct ifinfo *ifi;
+ struct rainfo *rai;
+ struct ra_opt *rao;
struct timeval now;
+ char ntopbuf[INET6_ADDRSTRLEN];
gettimeofday(&now, NULL);
- for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
- fprintf(fp, "Interface %s\n", ifinfo->ifname);
+ TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
+ fprintf(fp, "Interface %s\n", ifi->ifname);
fprintf(fp, " probe interval: ");
- if (ifinfo->probeinterval) {
- fprintf(fp, "%d\n", ifinfo->probeinterval);
- fprintf(fp, " probe timer: %d\n", ifinfo->probetimer);
+ if (ifi->probeinterval) {
+ fprintf(fp, "%d\n", ifi->probeinterval);
+ fprintf(fp, " probe timer: %d\n", ifi->probetimer);
} else {
fprintf(fp, "infinity\n");
fprintf(fp, " no probe timer\n");
}
fprintf(fp, " interface status: %s\n",
- ifinfo->active > 0 ? "active" : "inactive");
+ ifi->active > 0 ? "active" : "inactive");
fprintf(fp, " other config: %s\n",
- ifinfo->otherconfig ? "on" : "off");
- fprintf(fp, " rtsold status: %s\n", ifstatstr[ifinfo->state]);
+ ifi->otherconfig ? "on" : "off");
+ fprintf(fp, " rtsold status: %s\n", ifstatstr[ifi->state]);
fprintf(fp, " carrier detection: %s\n",
- ifinfo->mediareqok ? "available" : "unavailable");
+ ifi->mediareqok ? "available" : "unavailable");
fprintf(fp, " probes: %d, dadcount = %d\n",
- ifinfo->probes, ifinfo->dadcount);
- if (ifinfo->timer.tv_sec == tm_max.tv_sec &&
- ifinfo->timer.tv_usec == tm_max.tv_usec)
+ ifi->probes, ifi->dadcount);
+ if (ifi->timer.tv_sec == tm_max.tv_sec &&
+ ifi->timer.tv_usec == tm_max.tv_usec)
fprintf(fp, " no timer\n");
else {
fprintf(fp, " timer: interval=%d:%d, expire=%s\n",
- (int)ifinfo->timer.tv_sec,
- (int)ifinfo->timer.tv_usec,
- (ifinfo->expire.tv_sec < now.tv_sec) ? "expired"
- : sec2str(ifinfo->expire.tv_sec - now.tv_sec));
+ (int)ifi->timer.tv_sec,
+ (int)ifi->timer.tv_usec,
+ (ifi->expire.tv_sec < now.tv_sec) ? "expired"
+ : sec2str(&ifi->expire));
+ }
+ fprintf(fp, " number of valid RAs: %d\n", ifi->racnt);
+
+ TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) {
+ fprintf(fp, " RA from %s\n",
+ inet_ntop(AF_INET6, &rai->rai_saddr.sin6_addr,
+ ntopbuf, sizeof(ntopbuf)));
+ TAILQ_FOREACH(rao, &rai->rai_ra_opt, rao_next) {
+ fprintf(fp, " option: ");
+ switch (rao->rao_type) {
+ case ND_OPT_RDNSS:
+ fprintf(fp, "RDNSS: %s (expire: %s)\n",
+ (char *)rao->rao_msg,
+ sec2str(&rao->rao_expire));
+ break;
+ case ND_OPT_DNSSL:
+ fprintf(fp, "DNSSL: %s (expire: %s)\n",
+ (char *)rao->rao_msg,
+ sec2str(&rao->rao_expire));
+ break;
+ default:
+ break;
+ }
+ }
+ fprintf(fp, "\n");
}
- fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt);
}
}
@@ -108,8 +136,8 @@ rtsold_dump_file(const char *dumpfile)
fclose(fp);
}
-static const char *
-sec2str(time_t total)
+const char *
+sec2str(const struct timeval *total)
{
static char result[256];
int days, hours, mins, secs;
@@ -117,11 +145,19 @@ sec2str(time_t total)
char *p = result;
char *ep = &result[sizeof(result)];
int n;
+ struct timeval now;
+ time_t tsec;
- days = total / 3600 / 24;
- hours = (total / 3600) % 24;
- mins = (total / 60) % 60;
- secs = total % 60;
+ gettimeofday(&now, NULL);
+ tsec = total->tv_sec;
+ tsec += total->tv_usec / 1000000;
+ tsec -= now.tv_sec;
+ tsec -= now.tv_usec / 1000000;
+
+ days = tsec / 3600 / 24;
+ hours = (tsec / 3600) % 24;
+ mins = (tsec / 60) % 60;
+ secs = tsec % 60;
if (days) {
first = 0;
@@ -145,5 +181,6 @@ sec2str(time_t total)
p += n;
}
snprintf(p, ep - p, "%ds", secs);
- return(result);
+
+ return (result);
}
diff --git a/usr.sbin/rtsold/if.c b/usr.sbin/rtsold/if.c
index c555d2a..58ec514 100644
--- a/usr.sbin/rtsold/if.c
+++ b/usr.sbin/rtsold/if.c
@@ -91,25 +91,25 @@ interface_up(char *name)
if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s",
strerror(errno));
- return(-1);
+ return (-1);
}
if (!(ifr.ifr_flags & IFF_UP)) {
ifr.ifr_flags |= IFF_UP;
if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
warnmsg(LOG_ERR, __func__,
"ioctl(SIOCSIFFLAGS): %s", strerror(errno));
- return(-1);
+ return (-1);
}
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s",
strerror(errno));
- return(-1);
+ return (-1);
}
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s",
strerror(errno));
close(s);
- return(-1);
+ return (-1);
}
warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name);
@@ -122,13 +122,13 @@ interface_up(char *name)
"ioctl(SIOCSIFINFO_IN6): %s",
strerror(errno));
close(s);
- return(-1);
+ return (-1);
}
} else {
warnmsg(LOG_WARNING, __func__,
"%s is disabled.", name);
close(s);
- return(-1);
+ return (-1);
}
}
if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) {
@@ -139,13 +139,13 @@ interface_up(char *name)
"ioctl(SIOCSIFINFO_IN6): %s",
strerror(errno));
close(s);
- return(-1);
+ return (-1);
}
} else {
warnmsg(LOG_WARNING, __func__,
"%s does not accept Router Advertisement.", name);
close(s);
- return(-1);
+ return (-1);
}
}
close(s);
@@ -154,22 +154,22 @@ interface_up(char *name)
if (llflag < 0) {
warnmsg(LOG_WARNING, __func__,
"get_llflag() failed, anyway I'll try");
- return 0;
+ return (0);
}
if (!(llflag & IN6_IFF_NOTREADY)) {
warnmsg(LOG_DEBUG, __func__, "%s is ready", name);
- return(0);
+ return (0);
} else {
if (llflag & IN6_IFF_TENTATIVE) {
warnmsg(LOG_DEBUG, __func__, "%s is tentative",
name);
- return IFS_TENTATIVE;
+ return (IFS_TENTATIVE);
}
if (llflag & IN6_IFF_DUPLICATED)
warnmsg(LOG_DEBUG, __func__, "%s is duplicated",
name);
- return -1;
+ return (-1);
}
}
@@ -186,16 +186,14 @@ interface_status(struct ifinfo *ifinfo)
if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s",
ifname, strerror(errno));
- return(-1);
+ return (-1);
}
/*
* if one of UP and RUNNING flags is dropped,
* the interface is not active.
*/
- if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+ if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
goto inactive;
- }
-
/* Next, check carrier on the interface, if possible */
if (!ifinfo->mediareqok)
goto active;
@@ -232,10 +230,10 @@ interface_status(struct ifinfo *ifinfo)
}
inactive:
- return(0);
+ return (0);
active:
- return(1);
+ return (1);
}
#define ROUNDUP(a, size) \
@@ -254,9 +252,9 @@ lladdropt_length(struct sockaddr_dl *sdl)
#ifdef IFT_IEEE80211
case IFT_IEEE80211:
#endif
- return(ROUNDUP8(ETHER_ADDR_LEN + 2));
+ return (ROUNDUP8(ETHER_ADDR_LEN + 2));
default:
- return(0);
+ return (0);
}
}
@@ -301,7 +299,7 @@ if_nametosdl(char *name)
return(NULL);
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
free(buf);
- return(NULL);
+ return (NULL);
}
lim = buf + len;
@@ -327,17 +325,17 @@ if_nametosdl(char *name)
if (next == lim) {
/* search failed */
free(buf);
- return(NULL);
+ return (NULL);
}
if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) {
free(buf);
- return(NULL);
+ return (NULL);
}
memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
free(buf);
- return(ret_sdl);
+ return (ret_sdl);
}
int
@@ -350,9 +348,9 @@ getinet6sysctl(int code)
mib[3] = code;
size = sizeof(value);
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0)
- return -1;
+ return (-1);
else
- return value;
+ return (value);
}
int
@@ -366,9 +364,9 @@ setinet6sysctl(int code, int newval)
size = sizeof(value);
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size,
&newval, sizeof(newval)) < 0)
- return -1;
+ return (-1);
else
- return value;
+ return (value);
}
/*------------------------------------------------------------*/
@@ -414,12 +412,12 @@ get_llflag(const char *name)
freeifaddrs(ifap);
close(s);
- return ifr6.ifr_ifru.ifru_flags6;
+ return (ifr6.ifr_ifru.ifru_flags6);
}
freeifaddrs(ifap);
close(s);
- return -1;
+ return (-1);
}
diff --git a/usr.sbin/rtsold/probe.c b/usr.sbin/rtsold/probe.c
index 6d0ea79..657ae40 100644
--- a/usr.sbin/rtsold/probe.c
+++ b/usr.sbin/rtsold/probe.c
@@ -72,18 +72,18 @@ probe_init(void)
if (sndcmsgbuf == NULL &&
(sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__, "malloc failed");
- return(-1);
+ return (-1);
}
if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
- return(-1);
+ return (-1);
}
/* make the socket send-only */
if (shutdown(probesock, 0)) {
warnmsg(LOG_ERR, __func__, "shutdown: %s", strerror(errno));
- return(-1);
+ return (-1);
}
/* initialize msghdr for sending packets */
@@ -92,7 +92,8 @@ probe_init(void)
sndmhdr.msg_iovlen = 1;
sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
sndmhdr.msg_controllen = scmsglen;
- return(0);
+
+ return (0);
}
/*
diff --git a/usr.sbin/rtsold/rtsock.c b/usr.sbin/rtsold/rtsock.c
index 726c1e6..fe22bc7 100644
--- a/usr.sbin/rtsold/rtsock.c
+++ b/usr.sbin/rtsold/rtsock.c
@@ -83,7 +83,7 @@ int
rtsock_open(void)
{
- return socket(PF_ROUTE, SOCK_RAW, 0);
+ return (socket(PF_ROUTE, SOCK_RAW, 0));
}
int
@@ -130,7 +130,7 @@ rtsock_input(int s)
}
}
- return ret;
+ return (ret);
}
#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
@@ -142,7 +142,7 @@ rtsock_input_ifannounce(int s __unused, struct rt_msghdr *rtm, char *lim)
ifan = (struct if_announcemsghdr *)rtm;
if ((char *)(ifan + 1) > lim)
- return -1;
+ return (-1);
switch (ifan->ifan_what) {
case IFAN_ARRIVAL:
@@ -170,6 +170,6 @@ rtsock_input_ifannounce(int s __unused, struct rt_msghdr *rtm, char *lim)
break;
}
- return 0;
+ return (0);
}
#endif
diff --git a/usr.sbin/rtsold/rtsol.c b/usr.sbin/rtsold/rtsol.c
index be2a9b8..13845f3 100644
--- a/usr.sbin/rtsold/rtsol.c
+++ b/usr.sbin/rtsold/rtsol.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,13 +44,16 @@
#include <net/route.h>
#include <net/if_dl.h>
+#define __BSD_VISIBLE 1 /* IN6ADDR_LINKLOCAL_ALLROUTERS_INIT */
#include <netinet/in.h>
+#undef __BSD_VISIBLE
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
+#include <netdb.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
@@ -61,8 +65,6 @@
#include <syslog.h>
#include "rtsold.h"
-#define ALLROUTER "ff02::2"
-
static struct msghdr rcvmhdr;
static struct msghdr sndmhdr;
static struct iovec rcviov[2];
@@ -71,14 +73,40 @@ static struct sockaddr_in6 from;
static int rcvcmsglen;
int rssock;
+struct ifinfo_head_t ifinfo_head =
+ TAILQ_HEAD_INITIALIZER(ifinfo_head);
-static struct sockaddr_in6 sin6_allrouters = {
+static const struct sockaddr_in6 sin6_allrouters = {
.sin6_len = sizeof(sin6_allrouters),
.sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
};
-static void call_script(char *, char *);
+static void call_script(const int, const char *const *, void *);
+static size_t dname_labeldec(char *, size_t, const char *);
static int safefile(const char *);
+static struct ra_opt *find_raopt(struct rainfo *, int, void *, size_t);
+
+#define _ARGS_OTHER otherconf_script, ifi->ifname
+#define _ARGS_RESADD resolvconf_script, "-a", ifi->ifname
+#define _ARGS_RESDEL resolvconf_script, "-d", ifi->ifname
+
+#define CALL_SCRIPT(name, sm_head) \
+ do { \
+ const char *const sarg[] = { _ARGS_##name, NULL }; \
+ call_script(sizeof(sarg), sarg, sm_head); \
+ } while(0)
+
+#define ELM_MALLOC(p,error_action) \
+ do { \
+ p = malloc(sizeof(*p)); \
+ if (p == NULL) { \
+ warnmsg(LOG_ERR, __func__, "malloc failed: %s", \
+ strerror(errno)); \
+ error_action; \
+ } \
+ memset(p, 0, sizeof(*p)); \
+ } while(0)
int
sockopen(void)
@@ -93,63 +121,35 @@ sockopen(void)
if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__,
"malloc for receive msghdr failed");
- return(-1);
+ return (-1);
}
if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__,
"malloc for send msghdr failed");
- return(-1);
- }
- memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6));
- sin6_allrouters.sin6_family = AF_INET6;
- sin6_allrouters.sin6_len = sizeof(sin6_allrouters);
- if (inet_pton(AF_INET6, ALLROUTER,
- &sin6_allrouters.sin6_addr.s6_addr) != 1) {
- warnmsg(LOG_ERR, __func__, "inet_pton failed for %s",
- ALLROUTER);
- return(-1);
+ return (-1);
}
-
if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
- return(-1);
+ return (-1);
}
/* specify to tell receiving interface */
on = 1;
-#ifdef IPV6_RECVPKTINFO
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_RECVPKTINFO: %s",
strerror(errno));
exit(1);
}
-#else /* old adv. API */
- if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
- sizeof(on)) < 0) {
- warnmsg(LOG_ERR, __func__, "IPV6_PKTINFO: %s",
- strerror(errno));
- exit(1);
- }
-#endif
- on = 1;
/* specify to tell value of hoplimit field of received IP6 hdr */
-#ifdef IPV6_RECVHOPLIMIT
+ on = 1;
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_RECVHOPLIMIT: %s",
strerror(errno));
exit(1);
}
-#else /* old adv. API */
- if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
- sizeof(on)) < 0) {
- warnmsg(LOG_ERR, __func__, "IPV6_HOPLIMIT: %s",
- strerror(errno));
- exit(1);
- }
-#endif
/* specfiy to accept only router advertisements on the socket */
ICMP6_FILTER_SETBLOCKALL(&filt);
@@ -176,11 +176,11 @@ sockopen(void)
sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
sndmhdr.msg_controllen = sndcmsglen;
- return(rssock);
+ return (rssock);
}
void
-sendpacket(struct ifinfo *ifinfo)
+sendpacket(struct ifinfo *ifi)
{
struct in6_pktinfo *pi;
struct cmsghdr *cm;
@@ -189,11 +189,11 @@ sendpacket(struct ifinfo *ifinfo)
struct sockaddr_in6 dst;
dst = sin6_allrouters;
- dst.sin6_scope_id = ifinfo->linkid;
+ dst.sin6_scope_id = ifi->linkid;
sndmhdr.msg_name = (caddr_t)&dst;
- sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data;
- sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen;
+ sndmhdr.msg_iov[0].iov_base = (caddr_t)ifi->rs_data;
+ sndmhdr.msg_iov[0].iov_len = ifi->rs_datalen;
cm = CMSG_FIRSTHDR(&sndmhdr);
/* specify the outgoing interface */
@@ -202,7 +202,7 @@ sendpacket(struct ifinfo *ifinfo)
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
pi = (struct in6_pktinfo *)CMSG_DATA(cm);
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
- pi->ipi6_ifindex = ifinfo->sdl->sdl_index;
+ pi->ipi6_ifindex = ifi->sdl->sdl_index;
/* specify the hop limit of the packet */
cm = CMSG_NXTHDR(&sndmhdr, cm);
@@ -213,38 +213,53 @@ sendpacket(struct ifinfo *ifinfo)
warnmsg(LOG_DEBUG, __func__,
"send RS on %s, whose state is %d",
- ifinfo->ifname, ifinfo->state);
+ ifi->ifname, ifi->state);
i = sendmsg(rssock, &sndmhdr, 0);
- if (i < 0 || (size_t)i != ifinfo->rs_datalen) {
+ if (i < 0 || (size_t)i != ifi->rs_datalen) {
/*
* ENETDOWN is not so serious, especially when using several
* network cards on a mobile node. We ignore it.
*/
if (errno != ENETDOWN || dflag > 0)
warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s",
- ifinfo->ifname, strerror(errno));
+ ifi->ifname, strerror(errno));
}
/* update counter */
- ifinfo->probes++;
+ ifi->probes++;
}
void
rtsol_input(int s)
{
u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
- int ifindex = 0, *hlimp = NULL;
- ssize_t i;
+ int l, ifindex = 0, *hlimp = NULL;
+ ssize_t msglen;
struct in6_pktinfo *pi = NULL;
struct ifinfo *ifi = NULL;
+ struct ra_opt *rao = NULL;
struct icmp6_hdr *icp;
struct nd_router_advert *nd_ra;
struct cmsghdr *cm;
+ struct rainfo *rai;
+ char *raoptp;
+ char *p;
+ struct in6_addr *addr;
+ struct nd_opt_hdr *ndo;
+ struct nd_opt_rdnss *rdnss;
+ struct nd_opt_dnssl *dnssl;
+ size_t len;
+ char nsbuf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1];
+ char dname[NI_MAXHOST];
+ struct timeval now;
+ struct timeval lifetime;
+ int newent_rai;
+ int newent_rao;
/* get message. namelen and controllen must always be initialized. */
rcvmhdr.msg_namelen = sizeof(from);
rcvmhdr.msg_controllen = rcvcmsglen;
- if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
+ if ((msglen = recvmsg(s, &rcvmhdr, 0)) < 0) {
warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno));
return;
}
@@ -275,9 +290,9 @@ rtsol_input(int s)
return;
}
- if ((size_t)i < sizeof(struct nd_router_advert)) {
+ if ((size_t)msglen < sizeof(struct nd_router_advert)) {
warnmsg(LOG_INFO, __func__,
- "packet size(%zd) is too short", i);
+ "packet size(%zd) is too short", msglen);
return;
}
@@ -354,9 +369,179 @@ rtsol_input(int s)
warnmsg(LOG_DEBUG, __func__,
"OtherConfigFlag on %s is turned on", ifi->ifname);
ifi->otherconfig = 1;
- call_script(otherconf_script, ifi->ifname);
+ CALL_SCRIPT(OTHER, NULL);
+ }
+ gettimeofday(&now, NULL);
+ newent_rai = 0;
+ rai = find_rainfo(ifi, &from);
+ if (rai == NULL) {
+ ELM_MALLOC(rai, exit(1));
+ rai->rai_ifinfo = ifi;
+ TAILQ_INIT(&rai->rai_ra_opt);
+ memcpy(&rai->rai_saddr.sin6_addr, &from.sin6_addr,
+ sizeof(rai->rai_saddr.sin6_addr));
+ newent_rai = 1;
}
+#define RA_OPT_NEXT_HDR(x) (struct nd_opt_hdr *)((char *)x + \
+ (((struct nd_opt_hdr *)x)->nd_opt_len * 8))
+ /* Process RA options. */
+ warnmsg(LOG_DEBUG, __func__, "Processing RA");
+ raoptp = (char *)icp + sizeof(struct nd_router_advert);
+ while (raoptp < (char *)icp + msglen) {
+ ndo = (struct nd_opt_hdr *)raoptp;
+ warnmsg(LOG_DEBUG, __func__, "ndo = %p", raoptp);
+ warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_type = %d",
+ ndo->nd_opt_type);
+ warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_len = %d",
+ ndo->nd_opt_len);
+
+ switch (ndo->nd_opt_type) {
+ case ND_OPT_RDNSS:
+ rdnss = (struct nd_opt_rdnss *)raoptp;
+
+ /* Optlen sanity check (Section 5.3.1 in RFC 6106) */
+ if (rdnss->nd_opt_rdnss_len < 3) {
+ warnmsg(LOG_INFO, __func__,
+ "too short RDNSS option"
+ "in RA from %s was ignored.",
+ inet_ntop(AF_INET6, &from.sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN));
+ break;
+ }
+
+ addr = (struct in6_addr *)(raoptp + sizeof(*rdnss));
+ while ((char *)addr < (char *)RA_OPT_NEXT_HDR(raoptp)) {
+ if (inet_ntop(AF_INET6, addr, ntopbuf,
+ INET6_ADDRSTRLEN) == NULL) {
+ warnmsg(LOG_INFO, __func__,
+ "an invalid address in RDNSS option"
+ " in RA from %s was ignored.",
+ inet_ntop(AF_INET6, &from.sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN));
+ addr++;
+ continue;
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(addr))
+ /* XXX: % has to be escaped here */
+ l = snprintf(nsbuf, sizeof(nsbuf),
+ "%s%c%s", ntopbuf,
+ SCOPE_DELIMITER,
+ ifi->ifname);
+ else
+ l = snprintf(nsbuf, sizeof(nsbuf),
+ "%s", ntopbuf);
+ if (l < 0 || (size_t)l >= sizeof(nsbuf)) {
+ warnmsg(LOG_ERR, __func__,
+ "address copying error in "
+ "RDNSS option: %d.", l);
+ addr++;
+ continue;
+ }
+ warnmsg(LOG_DEBUG, __func__, "nsbuf = %s",
+ nsbuf);
+
+ newent_rao = 0;
+ rao = find_raopt(rai, ndo->nd_opt_type, nsbuf,
+ strlen(nsbuf));
+ if (rao == NULL) {
+ ELM_MALLOC(rao, break);
+ rao->rao_type = ndo->nd_opt_type;
+ rao->rao_len = strlen(nsbuf);
+ rao->rao_msg = strdup(nsbuf);
+ if (rao->rao_msg == NULL) {
+ warnmsg(LOG_ERR, __func__,
+ "strdup failed: %s",
+ strerror(errno));
+ free(rao);
+ addr++;
+ continue;
+ }
+ newent_rao = 1;
+ }
+ /* Set expiration timer */
+ memset(&rao->rao_expire, 0,
+ sizeof(rao->rao_expire));
+ memset(&lifetime, 0, sizeof(lifetime));
+ lifetime.tv_sec =
+ ntohl(rdnss->nd_opt_rdnss_lifetime);
+ timeradd(&now, &lifetime, &rao->rao_expire);
+
+ if (newent_rao)
+ TAILQ_INSERT_TAIL(&rai->rai_ra_opt,
+ rao, rao_next);
+ addr++;
+ }
+ break;
+ case ND_OPT_DNSSL:
+ dnssl = (struct nd_opt_dnssl *)raoptp;
+
+ /* Optlen sanity check (Section 5.3.1 in RFC 6106) */
+ if (dnssl->nd_opt_dnssl_len < 2) {
+ warnmsg(LOG_INFO, __func__,
+ "too short DNSSL option"
+ "in RA from %s was ignored.",
+ inet_ntop(AF_INET6, &from.sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN));
+ break;
+ }
+
+ /*
+ * Ensure NUL-termination in DNSSL in case of
+ * malformed field.
+ */
+ p = (char *)RA_OPT_NEXT_HDR(raoptp);
+ *(p - 1) = '\0';
+
+ p = raoptp + sizeof(*dnssl);
+ while (1 < (len = dname_labeldec(dname, sizeof(dname),
+ p))) {
+ /* length == 1 means empty string */
+ warnmsg(LOG_DEBUG, __func__, "dname = %s",
+ dname);
+
+ newent_rao = 0;
+ rao = find_raopt(rai, ndo->nd_opt_type, dname,
+ strlen(dname));
+ if (rao == NULL) {
+ ELM_MALLOC(rao, break);
+ rao->rao_type = ndo->nd_opt_type;
+ rao->rao_len = strlen(dname);
+ rao->rao_msg = strdup(dname);
+ if (rao->rao_msg == NULL) {
+ warnmsg(LOG_ERR, __func__,
+ "strdup failed: %s",
+ strerror(errno));
+ free(rao);
+ addr++;
+ continue;
+ }
+ newent_rao = 1;
+ }
+ /* Set expiration timer */
+ memset(&rao->rao_expire, 0,
+ sizeof(rao->rao_expire));
+ memset(&lifetime, 0, sizeof(lifetime));
+ lifetime.tv_sec =
+ ntohl(dnssl->nd_opt_dnssl_lifetime);
+ timeradd(&now, &lifetime, &rao->rao_expire);
+
+ if (newent_rao)
+ TAILQ_INSERT_TAIL(&rai->rai_ra_opt,
+ rao, rao_next);
+ p += len;
+ }
+ break;
+ default:
+ /* nothing to do for other options */
+ break;
+ }
+ raoptp = (char *)RA_OPT_NEXT_HDR(raoptp);
+ }
+ if (newent_rai)
+ TAILQ_INSERT_TAIL(&ifi->ifi_rainfo, rai, rai_next);
+
+ ra_opt_handler(ifi);
ifi->racnt++;
switch (ifi->state) {
@@ -371,23 +556,209 @@ rtsol_input(int s)
}
}
+static char resstr_ns_prefix[] = "nameserver ";
+static char resstr_sh_prefix[] = "search ";
+static char resstr_nl[] = "\n";
+static char resstr_sp[] = " ";
+
+int
+ra_opt_handler(struct ifinfo *ifi)
+{
+ struct ra_opt *rao;
+ struct rainfo *rai;
+ struct script_msg *smp1, *smp2, *smp3;
+ struct timeval now;
+ TAILQ_HEAD(, script_msg) sm_rdnss_head =
+ TAILQ_HEAD_INITIALIZER(sm_rdnss_head);
+ TAILQ_HEAD(, script_msg) sm_dnssl_head =
+ TAILQ_HEAD_INITIALIZER(sm_dnssl_head);
+ int dcount, dlen;
+
+ dcount = 0;
+ dlen = strlen(resstr_sh_prefix) + strlen(resstr_nl);
+ gettimeofday(&now, NULL);
+
+ /*
+ * All options from multiple RAs with the same or different
+ * source addresses on a single interface will be gathered and
+ * handled, not overridden. [RFC 4861 6.3.4]
+ */
+ TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) {
+ TAILQ_FOREACH(rao, &rai->rai_ra_opt, rao_next) {
+ switch (rao->rao_type) {
+ case ND_OPT_RDNSS:
+ if (timercmp(&now, &rao->rao_expire, >)) {
+ warnmsg(LOG_INFO, __func__,
+ "expired rdnss entry: %s",
+ (char *)rao->rao_msg);
+ break;
+ }
+ ELM_MALLOC(smp1, continue);
+ ELM_MALLOC(smp2, goto free1);
+ ELM_MALLOC(smp3, goto free2);
+ smp1->sm_msg = resstr_ns_prefix;
+ TAILQ_INSERT_TAIL(&sm_rdnss_head, smp1,
+ sm_next);
+ smp2->sm_msg = rao->rao_msg;
+ TAILQ_INSERT_TAIL(&sm_rdnss_head, smp2,
+ sm_next);
+ smp3->sm_msg = resstr_nl;
+ TAILQ_INSERT_TAIL(&sm_rdnss_head, smp3,
+ sm_next);
+ ifi->ifi_rdnss = IFI_DNSOPT_STATE_RECEIVED;
+
+ break;
+ case ND_OPT_DNSSL:
+ if (timercmp(&now, &rao->rao_expire, >)) {
+ warnmsg(LOG_INFO, __func__,
+ "expired dnssl entry: %s",
+ (char *)rao->rao_msg);
+ break;
+ }
+ dcount++;
+ /* Check resolv.conf(5) restrictions. */
+ if (dcount > 6) {
+ warnmsg(LOG_INFO, __func__,
+ "dnssl entry exceeding maximum count (%d>6)"
+ ": %s", dcount, (char *)rao->rao_msg);
+ break;
+ }
+ if (256 < dlen + strlen(rao->rao_msg) +
+ strlen(resstr_sp)) {
+ warnmsg(LOG_INFO, __func__,
+ "dnssl entry exceeding maximum length "
+ "(>256): %s", (char *)rao->rao_msg);
+ break;
+ }
+ ELM_MALLOC(smp1, continue);
+ ELM_MALLOC(smp2, goto free1);
+ if (TAILQ_EMPTY(&sm_dnssl_head)) {
+ ELM_MALLOC(smp3, goto free2);
+ smp3->sm_msg = resstr_sh_prefix;
+ TAILQ_INSERT_TAIL(&sm_dnssl_head, smp3,
+ sm_next);
+ }
+ smp1->sm_msg = rao->rao_msg;
+ TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1,
+ sm_next);
+ smp2->sm_msg = resstr_sp;
+ TAILQ_INSERT_TAIL(&sm_dnssl_head, smp2,
+ sm_next);
+ dlen += strlen(rao->rao_msg) +
+ strlen(resstr_sp);
+ break;
+
+ ifi->ifi_dnssl = IFI_DNSOPT_STATE_RECEIVED;
+ default:
+ break;
+ }
+ continue;
+free2:
+ free(smp2);
+free1:
+ free(smp1);
+ }
+ }
+ /* Add \n for DNSSL list. */
+ if (!TAILQ_EMPTY(&sm_dnssl_head)) {
+ ELM_MALLOC(smp1, goto ra_opt_handler_freeit);
+ smp1->sm_msg = resstr_nl;
+ TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1, sm_next);
+ }
+ TAILQ_CONCAT(&sm_rdnss_head, &sm_dnssl_head, sm_next);
+
+ if (!TAILQ_EMPTY(&sm_rdnss_head))
+ CALL_SCRIPT(RESADD, &sm_rdnss_head);
+ else if (ifi->ifi_rdnss == IFI_DNSOPT_STATE_RECEIVED ||
+ ifi->ifi_dnssl == IFI_DNSOPT_STATE_RECEIVED) {
+ CALL_SCRIPT(RESDEL, NULL);
+ ifi->ifi_rdnss = IFI_DNSOPT_STATE_NOINFO;
+ ifi->ifi_dnssl = IFI_DNSOPT_STATE_NOINFO;
+ }
+
+ra_opt_handler_freeit:
+ /* Clear script message queue. */
+ if (!TAILQ_EMPTY(&sm_rdnss_head)) {
+ while ((smp1 = TAILQ_FIRST(&sm_rdnss_head)) != NULL) {
+ TAILQ_REMOVE(&sm_rdnss_head, smp1, sm_next);
+ free(smp1);
+ }
+ }
+ if (!TAILQ_EMPTY(&sm_dnssl_head)) {
+ while ((smp1 = TAILQ_FIRST(&sm_dnssl_head)) != NULL) {
+ TAILQ_REMOVE(&sm_dnssl_head, smp1, sm_next);
+ free(smp1);
+ }
+ }
+ return (0);
+}
+
+static struct ra_opt *
+find_raopt(struct rainfo *rai, int type, void *msg, size_t len)
+{
+ struct ra_opt *rao;
+
+ TAILQ_FOREACH(rao, &rai->rai_ra_opt, rao_next) {
+ if (rao->rao_type == type &&
+ rao->rao_len == strlen(msg) &&
+ memcmp(rao->rao_msg, msg, len) == 0)
+ break;
+ }
+
+ return (rao);
+}
+
static void
-call_script(char *scriptpath, char *ifname)
+call_script(const int argc, const char *const argv[], void *head)
{
+ const char *scriptpath;
+ int fd[2];
+ int error;
pid_t pid, wpid;
+ TAILQ_HEAD(, script_msg) *sm_head;
- if (scriptpath == NULL)
+ if ((scriptpath = argv[0]) == NULL)
return;
+ fd[0] = fd[1] = -1;
+ sm_head = head;
+ if (sm_head != NULL && !TAILQ_EMPTY(sm_head)) {
+ error = pipe(fd);
+ if (error) {
+ warnmsg(LOG_ERR, __func__,
+ "failed to create a pipe: %s", strerror(errno));
+ return;
+ }
+ }
+
/* launch the script */
pid = fork();
if (pid < 0) {
warnmsg(LOG_ERR, __func__,
"failed to fork: %s", strerror(errno));
return;
- } else if (pid) {
+ } else if (pid) { /* parent */
int wstatus;
+ if (fd[0] != -1) { /* Send message to the child if any. */
+ ssize_t len;
+ struct script_msg *smp;
+
+ close(fd[0]);
+ TAILQ_FOREACH(smp, sm_head, sm_next) {
+ len = strlen(smp->sm_msg);
+ warnmsg(LOG_DEBUG, __func__,
+ "write to child = %s(%zd)",
+ smp->sm_msg, len);
+ if (write(fd[1], smp->sm_msg, len) != len) {
+ warnmsg(LOG_ERR, __func__,
+ "write to child failed: %s",
+ strerror(errno));
+ break;
+ }
+ }
+ close(fd[1]);
+ }
do {
wpid = wait(&wstatus);
} while (wpid != pid && wpid > 0);
@@ -395,17 +766,12 @@ call_script(char *scriptpath, char *ifname)
if (wpid < 0)
warnmsg(LOG_ERR, __func__,
"wait: %s", strerror(errno));
- else {
+ else
warnmsg(LOG_DEBUG, __func__,
"script \"%s\" terminated", scriptpath);
- }
- } else {
- char *argv[3];
- int fd;
-
- argv[0] = scriptpath;
- argv[1] = ifname;
- argv[2] = NULL;
+ } else { /* child */
+ int nullfd;
+ char **_argv;
if (safefile(scriptpath)) {
warnmsg(LOG_ERR, __func__,
@@ -413,20 +779,42 @@ call_script(char *scriptpath, char *ifname)
scriptpath);
exit(1);
}
-
- if ((fd = open("/dev/null", O_RDWR)) != -1) {
- dup2(fd, STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- if (fd > STDERR_FILENO)
- close(fd);
+ nullfd = open("/dev/null", O_RDWR);
+ if (nullfd < 0) {
+ warnmsg(LOG_ERR, __func__,
+ "open /dev/null: %s", strerror(errno));
+ exit(1);
}
-
- execv(scriptpath, argv);
-
+ if (fd[0] != -1) { /* Receive message from STDIN if any. */
+ close(fd[1]);
+ if (fd[0] != STDIN_FILENO) {
+ /* Connect a pipe read-end to child's STDIN. */
+ if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
+ warnmsg(LOG_ERR, __func__,
+ "dup2 STDIN: %s", strerror(errno));
+ exit(1);
+ }
+ close(fd[0]);
+ }
+ } else
+ dup2(nullfd, STDIN_FILENO);
+
+ dup2(nullfd, STDOUT_FILENO);
+ dup2(nullfd, STDERR_FILENO);
+ if (nullfd > STDERR_FILENO)
+ close(nullfd);
+
+ _argv = malloc(sizeof(*_argv) * argc);
+ if (_argv == NULL) {
+ warnmsg(LOG_ERR, __func__,
+ "malloc: %s", strerror(errno));
+ exit(1);
+ }
+ memcpy(_argv, argv, (size_t)argc);
+ execv(scriptpath, (char *const *)_argv);
warnmsg(LOG_ERR, __func__, "child: exec failed: %s",
strerror(errno));
- exit(0);
+ exit(1);
}
return;
@@ -471,3 +859,37 @@ safefile(const char *path)
return (0);
}
+
+/* Decode domain name label encoding in RFC 1035 Section 3.1 */
+static size_t
+dname_labeldec(char *dst, size_t dlen, const char *src)
+{
+ size_t len;
+ const char *src_origin;
+ const char *src_last;
+ const char *dst_origin;
+
+ src_origin = src;
+ src_last = strchr(src, '\0');
+ dst_origin = dst;
+ memset(dst, '\0', dlen);
+ while (src && (len = (uint8_t)(*src++) & 0x3f) &&
+ (src + len) <= src_last) {
+ if (dst != dst_origin)
+ *dst++ = '.';
+ warnmsg(LOG_DEBUG, __func__, "labellen = %zd", len);
+ memcpy(dst, src, len);
+ src += len;
+ dst += len;
+ }
+ *dst = '\0';
+
+ /*
+ * XXX validate that domain name only contains valid characters
+ * for two reasons: 1) correctness, 2) we do not want to pass
+ * possible malicious, unescaped characters like `` to a script
+ * or program that could be exploited that way.
+ */
+
+ return (src - src_origin);
+}
diff --git a/usr.sbin/rtsold/rtsold.8 b/usr.sbin/rtsold/rtsold.8
index 9ce0bb0..8eb2539 100644
--- a/usr.sbin/rtsold/rtsold.8
+++ b/usr.sbin/rtsold/rtsold.8
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 2, 2009
+.Dd May 28, 2011
.Dt RTSOLD 8
.Os
.\"
@@ -41,18 +41,24 @@
.Nm
.Op Fl dDfFm1
.Op Fl O Ar script-name
+.Op Fl P Ar pidfile
+.Op Fl R Ar script-name
.Ar interface ...
.Nm
.Op Fl dDfFm1
.Op Fl O Ar script-name
+.Op Fl P Ar pidfile
+.Op Fl R Ar script-name
.Fl a
.Nm rtsol
-.Op Fl dDF
+.Op Fl dD
.Op Fl O Ar script-name
+.Op Fl R Ar script-name
.Ar interface ...
.Nm rtsol
.Op Fl dD
.Op Fl O Ar script-name
+.Op Fl R Ar script-name
.Fl a
.\"
.Sh DESCRIPTION
@@ -221,6 +227,24 @@ configuration.
must be the absolute path from root to the script file, be a regular
file, and be created by the same owner who runs
.Nm .
+.It Fl P Ar pidfile
+Writes the process ID of
+.Nm
+to
+.Pa pidfile
+instead of the default PID file
+.Pa /var/run/rtsold.pid .
+.It Fl R Ar script-name
+Specifies a script to run when router advertisment options
+.Dv RDNSS Pq Recursive DNS Server
+or
+.Dv DNSSL Pq DNS Search List
+are encountered.
+The information of DNS servers and DNS search domains will be sent to
+standard input of this script.
+The
+.Xr resolvconf 8
+script is used by default.
.El
.Sh FILES
.Bl -tag -width /var/run/rtsold.dump -compact
@@ -235,6 +259,7 @@ dumps internal state on.
.Ex -std
.\"
.Sh SEE ALSO
+.Xr resolvconf 8 ,
.Xr rtadvd 8 ,
.Xr sysctl 8
.\"
diff --git a/usr.sbin/rtsold/rtsold.c b/usr.sbin/rtsold/rtsold.c
index 0db050c..94046a1 100644
--- a/usr.sbin/rtsold/rtsold.c
+++ b/usr.sbin/rtsold/rtsold.c
@@ -44,6 +44,7 @@
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <netinet/in_var.h>
+#include <arpa/inet.h>
#include <netinet6/nd6.h>
@@ -63,6 +64,9 @@
#include "rtsold.h"
+#define RTSOL_DUMPFILE "/var/run/rtsold.dump";
+#define RTSOL_PIDFILE "/var/run/rtsold.pid";
+
struct ifinfo *iflist;
struct timeval tm_max = {0x7fffffff, 0x7fffffff};
static int log_upto = 999;
@@ -72,7 +76,8 @@ int Fflag = 0; /* force setting sysctl parameters */
int aflag = 0;
int dflag = 0;
-char *otherconf_script;
+const char *otherconf_script;
+const char *resolvconf_script = "/sbin/resolvconf";
/* protocol constants */
#define MAX_RTR_SOLICITATION_DELAY 1 /* second */
@@ -85,35 +90,32 @@ char *otherconf_script;
*/
#define PROBE_INTERVAL 60
-int main(int, char **);
-
/* static variables and functions */
static int mobile_node = 0;
+static const char *pidfilename = RTSOL_PIDFILE;
+
#ifndef SMALL
static int do_dump;
-static const char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
-#endif
-#if 1
-static const char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */
+static const char *dumpfilename = RTSOL_DUMPFILE;
#endif
#if 0
static int ifreconfig(char *);
#endif
+
static int make_packet(struct ifinfo *);
static struct timeval *rtsol_check_timer(void);
#ifndef SMALL
static void rtsold_set_dump_file(int);
#endif
-static void usage(char *);
+static void usage(void);
int
main(int argc, char **argv)
{
int s, ch, once = 0;
struct timeval *timeout;
- char *argv0;
const char *opts;
#ifdef HAVE_POLL_H
struct pollfd set[2];
@@ -123,20 +125,19 @@ main(int argc, char **argv)
int maxfd;
#endif
int rtsock;
+ char *argv0;
- /*
- * Initialization
- */
+#ifndef SMALL
+ /* rtsold */
+ opts = "adDfFm1O:P:R:";
+#else
+ /* rtsol */
+ opts = "adDFO:P:R:";
+ fflag = 1;
+ once = 1;
+#endif
argv0 = argv[0];
- /* get option */
- if (argv0 && argv0[strlen(argv0) - 1] != 'd') {
- fflag = 1;
- once = 1;
- opts = "adDFO:";
- } else
- opts = "adDfFm1O:";
-
while ((ch = getopt(argc, argv, opts)) != -1) {
switch (ch) {
case 'a':
@@ -163,17 +164,23 @@ main(int argc, char **argv)
case 'O':
otherconf_script = optarg;
break;
+ case 'P':
+ pidfilename = optarg;
+ break;
+ case 'R':
+ resolvconf_script = optarg;
+ break;
default:
- usage(argv0);
- /*NOTREACHED*/
+ usage();
+ exit(1);
}
}
argc -= optind;
argv += optind;
if ((!aflag && argc == 0) || (aflag && argc != 0)) {
- usage(argv0);
- /*NOTREACHED*/
+ usage();
+ exit(1);
}
/* set log level */
@@ -196,7 +203,14 @@ main(int argc, char **argv)
errx(1, "configuration script (%s) must be an absolute path",
otherconf_script);
}
-
+ if (resolvconf_script && *resolvconf_script != '/') {
+ errx(1, "configuration script (%s) must be an absolute path",
+ resolvconf_script);
+ }
+ if (pidfilename && *pidfilename != '/') {
+ errx(1, "pid filename (%s) must be an absolute path",
+ pidfilename);
+ }
#ifndef HAVE_ARC4RANDOM
/* random value initialization */
srandom((u_long)time(NULL));
@@ -226,7 +240,6 @@ main(int argc, char **argv)
if ((s = sockopen()) < 0) {
warnmsg(LOG_ERR, __func__, "failed to open a socket");
exit(1);
- /*NOTREACHED*/
}
#ifdef HAVE_POLL_H
set[0].fd = s;
@@ -242,7 +255,6 @@ main(int argc, char **argv)
if ((rtsock = rtsock_open()) < 0) {
warnmsg(LOG_ERR, __func__, "failed to open a socket");
exit(1);
- /*NOTREACHED*/
}
#ifdef HAVE_POLL_H
set[1].fd = rtsock;
@@ -255,12 +267,12 @@ main(int argc, char **argv)
#ifndef HAVE_POLL_H
fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
if ((fdsetp = malloc(fdmasks)) == NULL) {
- err(1, "malloc");
- /*NOTREACHED*/
+ warnmsg(LOG_ERR, __func__, "malloc");
+ exit(1);
}
if ((selectfdp = malloc(fdmasks)) == NULL) {
- err(1, "malloc");
- /*NOTREACHED*/
+ warnmsg(LOG_ERR, __func__, "malloc");
+ exit(1);
}
#endif
@@ -269,7 +281,6 @@ main(int argc, char **argv)
warnmsg(LOG_ERR, __func__,
"failed to initialize interfaces");
exit(1);
- /*NOTREACHED*/
}
if (aflag)
argv = autoifprobe();
@@ -278,7 +289,6 @@ main(int argc, char **argv)
warnmsg(LOG_ERR, __func__,
"failed to initialize %s", *argv);
exit(1);
- /*NOTREACHED*/
}
argv++;
}
@@ -291,7 +301,6 @@ main(int argc, char **argv)
/*NOTREACHED*/
}
-#if 1
/* dump the current pid */
if (!once) {
pid_t pid = getpid();
@@ -306,8 +315,6 @@ main(int argc, char **argv)
fclose(fp);
}
}
-#endif
-
#ifndef HAVE_POLL_H
memset(fdsetp, 0, fdmasks);
FD_SET(s, fdsetp);
@@ -337,7 +344,7 @@ main(int argc, char **argv)
break;
/* if all interfaces have got RA packet, we are done */
- for (ifi = iflist; ifi; ifi = ifi->next) {
+ TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (ifi->state != IFS_DOWN && ifi->racnt == 0)
break;
}
@@ -373,102 +380,99 @@ main(int argc, char **argv)
}
/* NOTREACHED */
- return 0;
+ return (0);
}
int
ifconfig(char *ifname)
{
- struct ifinfo *ifinfo;
+ struct ifinfo *ifi;
struct sockaddr_dl *sdl;
int flags;
if ((sdl = if_nametosdl(ifname)) == NULL) {
warnmsg(LOG_ERR, __func__,
"failed to get link layer information for %s", ifname);
- return(-1);
+ return (-1);
}
if (find_ifinfo(sdl->sdl_index)) {
warnmsg(LOG_ERR, __func__,
"interface %s was already configured", ifname);
free(sdl);
- return(-1);
+ return (-1);
}
- if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) {
+ if ((ifi = malloc(sizeof(*ifi))) == NULL) {
warnmsg(LOG_ERR, __func__, "memory allocation failed");
free(sdl);
- return(-1);
+ return (-1);
}
- memset(ifinfo, 0, sizeof(*ifinfo));
- ifinfo->sdl = sdl;
-
- strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname));
+ memset(ifi, 0, sizeof(*ifi));
+ ifi->sdl = sdl;
+ ifi->ifi_rdnss = IFI_DNSOPT_STATE_NOINFO;
+ ifi->ifi_dnssl = IFI_DNSOPT_STATE_NOINFO;
+ TAILQ_INIT(&ifi->ifi_rainfo);
+ strlcpy(ifi->ifname, ifname, sizeof(ifi->ifname));
/* construct a router solicitation message */
- if (make_packet(ifinfo))
+ if (make_packet(ifi))
goto bad;
/* set link ID of this interface. */
#ifdef HAVE_SCOPELIB
- if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid))
+ if (inet_zoneid(AF_INET6, 2, ifname, &ifi->linkid))
goto bad;
#else
/* XXX: assume interface IDs as link IDs */
- ifinfo->linkid = ifinfo->sdl->sdl_index;
+ ifi->linkid = ifi->sdl->sdl_index;
#endif
/*
* check if the interface is available.
* also check if SIOCGIFMEDIA ioctl is OK on the interface.
*/
- ifinfo->mediareqok = 1;
- ifinfo->active = interface_status(ifinfo);
- if (!ifinfo->mediareqok) {
+ ifi->mediareqok = 1;
+ ifi->active = interface_status(ifi);
+ if (!ifi->mediareqok) {
/*
* probe routers periodically even if the link status
* does not change.
*/
- ifinfo->probeinterval = PROBE_INTERVAL;
+ ifi->probeinterval = PROBE_INTERVAL;
}
/* activate interface: interface_up returns 0 on success */
- flags = interface_up(ifinfo->ifname);
+ flags = interface_up(ifi->ifname);
if (flags == 0)
- ifinfo->state = IFS_DELAY;
+ ifi->state = IFS_DELAY;
else if (flags == IFS_TENTATIVE)
- ifinfo->state = IFS_TENTATIVE;
+ ifi->state = IFS_TENTATIVE;
else
- ifinfo->state = IFS_DOWN;
-
- rtsol_timer_update(ifinfo);
+ ifi->state = IFS_DOWN;
- /* link into chain */
- if (iflist)
- ifinfo->next = iflist;
- iflist = ifinfo;
+ rtsol_timer_update(ifi);
- return(0);
+ TAILQ_INSERT_TAIL(&ifinfo_head, ifi, ifi_next);
+ return (0);
bad:
- free(ifinfo->sdl);
- free(ifinfo);
- return(-1);
+ free(ifi->sdl);
+ free(ifi);
+ return (-1);
}
void
iflist_init(void)
{
- struct ifinfo *ifi, *next;
+ struct ifinfo *ifi;
- for (ifi = iflist; ifi; ifi = next) {
- next = ifi->next;
- if (ifi->sdl)
+ while ((ifi = TAILQ_FIRST(&ifinfo_head)) != NULL) {
+ TAILQ_REMOVE(&ifinfo_head, ifi, ifi_next);
+ if (ifi->sdl != NULL)
free(ifi->sdl);
- if (ifi->rs_data)
+ if (ifi->rs_data != NULL)
free(ifi->rs_data);
free(ifi);
- iflist = NULL;
}
}
@@ -480,7 +484,7 @@ ifreconfig(char *ifname)
int rv;
prev = NULL;
- for (ifi = iflist; ifi; ifi = ifi->next) {
+ TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
break;
prev = ifi;
@@ -494,43 +498,58 @@ ifreconfig(char *ifname)
free(ifi->rs_data);
free(ifi->sdl);
free(ifi);
- return rv;
+
+ return (rv);
}
#endif
+struct rainfo *
+find_rainfo(struct ifinfo *ifi, struct sockaddr_in6 *sin6)
+{
+ struct rainfo *rai;
+
+ TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next)
+ if (memcmp(&rai->rai_saddr.sin6_addr, &sin6->sin6_addr,
+ sizeof(rai->rai_saddr.sin6_addr)) == 0)
+ return (rai);
+
+ return (NULL);
+}
+
struct ifinfo *
find_ifinfo(int ifindex)
{
struct ifinfo *ifi;
- for (ifi = iflist; ifi; ifi = ifi->next)
+ TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (ifi->sdl->sdl_index == ifindex)
- return(ifi);
- return(NULL);
+ return (ifi);
+ }
+ return (NULL);
}
static int
-make_packet(struct ifinfo *ifinfo)
+make_packet(struct ifinfo *ifi)
{
size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0;
struct nd_router_solicit *rs;
char *buf;
- if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) {
+ if ((lladdroptlen = lladdropt_length(ifi->sdl)) == 0) {
warnmsg(LOG_INFO, __func__,
"link-layer address option has null length"
- " on %s. Treat as not included.", ifinfo->ifname);
+ " on %s. Treat as not included.", ifi->ifname);
}
packlen += lladdroptlen;
- ifinfo->rs_datalen = packlen;
+ ifi->rs_datalen = packlen;
/* allocate buffer */
if ((buf = malloc(packlen)) == NULL) {
warnmsg(LOG_ERR, __func__,
- "memory allocation failed for %s", ifinfo->ifname);
- return(-1);
+ "memory allocation failed for %s", ifi->ifname);
+ return (-1);
}
- ifinfo->rs_data = buf;
+ ifi->rs_data = buf;
/* fill in the message */
rs = (struct nd_router_solicit *)buf;
@@ -542,9 +561,9 @@ make_packet(struct ifinfo *ifinfo)
/* fill in source link-layer address option */
if (lladdroptlen)
- lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf);
+ lladdropt_fill(ifi->sdl, (struct nd_opt_hdr *)buf);
- return(0);
+ return (0);
}
static struct timeval *
@@ -552,56 +571,68 @@ rtsol_check_timer(void)
{
static struct timeval returnval;
struct timeval now, rtsol_timer;
- struct ifinfo *ifinfo;
+ struct ifinfo *ifi;
+ struct rainfo *rai;
+ struct ra_opt *rao;
int flags;
gettimeofday(&now, NULL);
rtsol_timer = tm_max;
- for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
- if (timercmp(&ifinfo->expire, &now, <=)) {
- if (dflag > 1)
- warnmsg(LOG_DEBUG, __func__,
- "timer expiration on %s, "
- "state = %d", ifinfo->ifname,
- ifinfo->state);
-
- switch (ifinfo->state) {
+ TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
+ if (timercmp(&ifi->expire, &now, <=)) {
+ warnmsg(LOG_DEBUG, __func__, "timer expiration on %s, "
+ "state = %d", ifi->ifname, ifi->state);
+
+ while((rai = TAILQ_FIRST(&ifi->ifi_rainfo)) != NULL) {
+ /* Remove all RA options. */
+ TAILQ_REMOVE(&ifi->ifi_rainfo, rai, rai_next);
+ while ((rao = TAILQ_FIRST(&rai->rai_ra_opt)) !=
+ NULL) {
+ TAILQ_REMOVE(&rai->rai_ra_opt, rao,
+ rao_next);
+ if (rao->rao_msg != NULL)
+ free(rao->rao_msg);
+ free(rao);
+ }
+ free(rai);
+ }
+ switch (ifi->state) {
case IFS_DOWN:
case IFS_TENTATIVE:
/* interface_up returns 0 on success */
- flags = interface_up(ifinfo->ifname);
+ flags = interface_up(ifi->ifname);
if (flags == 0)
- ifinfo->state = IFS_DELAY;
+ ifi->state = IFS_DELAY;
else if (flags == IFS_TENTATIVE)
- ifinfo->state = IFS_TENTATIVE;
+ ifi->state = IFS_TENTATIVE;
else
- ifinfo->state = IFS_DOWN;
+ ifi->state = IFS_DOWN;
break;
case IFS_IDLE:
{
- int oldstatus = ifinfo->active;
+ int oldstatus = ifi->active;
int probe = 0;
- ifinfo->active = interface_status(ifinfo);
+ ifi->active = interface_status(ifi);
- if (oldstatus != ifinfo->active) {
+ if (oldstatus != ifi->active) {
warnmsg(LOG_DEBUG, __func__,
"%s status is changed"
" from %d to %d",
- ifinfo->ifname,
- oldstatus, ifinfo->active);
+ ifi->ifname,
+ oldstatus, ifi->active);
probe = 1;
- ifinfo->state = IFS_DELAY;
- } else if (ifinfo->probeinterval &&
- (ifinfo->probetimer -=
- ifinfo->timer.tv_sec) <= 0) {
+ ifi->state = IFS_DELAY;
+ } else if (ifi->probeinterval &&
+ (ifi->probetimer -=
+ ifi->timer.tv_sec) <= 0) {
/* probe timer expired */
- ifinfo->probetimer =
- ifinfo->probeinterval;
+ ifi->probetimer =
+ ifi->probeinterval;
probe = 1;
- ifinfo->state = IFS_PROBE;
+ ifi->state = IFS_PROBE;
}
/*
@@ -609,77 +640,104 @@ rtsol_check_timer(void)
* status wrt the "other" configuration.
*/
if (probe)
- ifinfo->otherconfig = 0;
+ ifi->otherconfig = 0;
if (probe && mobile_node)
- defrouter_probe(ifinfo);
+ defrouter_probe(ifi);
break;
}
case IFS_DELAY:
- ifinfo->state = IFS_PROBE;
- sendpacket(ifinfo);
+ ifi->state = IFS_PROBE;
+ sendpacket(ifi);
break;
case IFS_PROBE:
- if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
- sendpacket(ifinfo);
+ if (ifi->probes < MAX_RTR_SOLICITATIONS)
+ sendpacket(ifi);
else {
warnmsg(LOG_INFO, __func__,
"No answer after sending %d RSs",
- ifinfo->probes);
- ifinfo->probes = 0;
- ifinfo->state = IFS_IDLE;
+ ifi->probes);
+ ifi->probes = 0;
+ ifi->state = IFS_IDLE;
}
break;
}
- rtsol_timer_update(ifinfo);
- }
+ rtsol_timer_update(ifi);
+ } else {
+ /* Expiration check for RA options. */
+ int expire = 0;
- if (timercmp(&ifinfo->expire, &rtsol_timer, <))
- rtsol_timer = ifinfo->expire;
+ TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) {
+ TAILQ_FOREACH(rao, &rai->rai_ra_opt, rao_next) {
+ warnmsg(LOG_DEBUG, __func__,
+ "RA expiration timer: "
+ "type=%d, msg=%s, expire=%s",
+ rao->rao_type, (char *)rao->rao_msg,
+ sec2str(&rao->rao_expire));
+ if (timercmp(&now, &rao->rao_expire,
+ >=)) {
+ warnmsg(LOG_DEBUG, __func__,
+ "RA expiration timer: "
+ "expired.");
+ TAILQ_REMOVE(&rai->rai_ra_opt,
+ rao, rao_next);
+ if (rao->rao_msg != NULL)
+ free(rao->rao_msg);
+ free(rao);
+ expire = 1;
+ }
+ }
+ }
+ if (expire)
+ ra_opt_handler(ifi);
+ }
+ if (timercmp(&ifi->expire, &rtsol_timer, <))
+ rtsol_timer = ifi->expire;
}
if (timercmp(&rtsol_timer, &tm_max, ==)) {
warnmsg(LOG_DEBUG, __func__, "there is no timer");
- return(NULL);
+ return (NULL);
} else if (timercmp(&rtsol_timer, &now, <))
/* this may occur when the interval is too small */
returnval.tv_sec = returnval.tv_usec = 0;
else
timersub(&rtsol_timer, &now, &returnval);
- if (dflag > 1)
- warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld",
- (long)returnval.tv_sec, (long)returnval.tv_usec);
+ now.tv_sec += returnval.tv_sec;
+ now.tv_usec += returnval.tv_usec;
+ warnmsg(LOG_DEBUG, __func__, "New timer is %s",
+ sec2str(&now));
- return(&returnval);
+ return (&returnval);
}
void
-rtsol_timer_update(struct ifinfo *ifinfo)
+rtsol_timer_update(struct ifinfo *ifi)
{
#define MILLION 1000000
#define DADRETRY 10 /* XXX: adhoc */
long interval;
struct timeval now;
- bzero(&ifinfo->timer, sizeof(ifinfo->timer));
+ bzero(&ifi->timer, sizeof(ifi->timer));
- switch (ifinfo->state) {
+ switch (ifi->state) {
case IFS_DOWN:
case IFS_TENTATIVE:
- if (++ifinfo->dadcount > DADRETRY) {
- ifinfo->dadcount = 0;
- ifinfo->timer.tv_sec = PROBE_INTERVAL;
+ if (++ifi->dadcount > DADRETRY) {
+ ifi->dadcount = 0;
+ ifi->timer.tv_sec = PROBE_INTERVAL;
} else
- ifinfo->timer.tv_sec = 1;
+ ifi->timer.tv_sec = 1;
break;
case IFS_IDLE:
if (mobile_node) {
/* XXX should be configurable */
- ifinfo->timer.tv_sec = 3;
+ ifi->timer.tv_sec = 3;
}
else
- ifinfo->timer = tm_max; /* stop timer(valid?) */
+ ifi->timer = tm_max; /* stop timer(valid?) */
break;
case IFS_DELAY:
#ifndef HAVE_ARC4RANDOM
@@ -687,12 +745,12 @@ rtsol_timer_update(struct ifinfo *ifinfo)
#else
interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION);
#endif
- ifinfo->timer.tv_sec = interval / MILLION;
- ifinfo->timer.tv_usec = interval % MILLION;
+ ifi->timer.tv_sec = interval / MILLION;
+ ifi->timer.tv_usec = interval % MILLION;
break;
case IFS_PROBE:
- if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
- ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
+ if (ifi->probes < MAX_RTR_SOLICITATIONS)
+ ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
else {
/*
* After sending MAX_RTR_SOLICITATIONS solicitations,
@@ -701,30 +759,29 @@ rtsol_timer_update(struct ifinfo *ifinfo)
* the timer value to MAX_RTR_SOLICITATION_DELAY based
* on RFC 2461, Section 6.3.7.
*/
- ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
+ ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
}
break;
default:
warnmsg(LOG_ERR, __func__,
"illegal interface state(%d) on %s",
- ifinfo->state, ifinfo->ifname);
+ ifi->state, ifi->ifname);
return;
}
/* reset the timer */
- if (timercmp(&ifinfo->timer, &tm_max, ==)) {
- ifinfo->expire = tm_max;
+ if (timercmp(&ifi->timer, &tm_max, ==)) {
+ ifi->expire = tm_max;
warnmsg(LOG_DEBUG, __func__,
- "stop timer for %s", ifinfo->ifname);
+ "stop timer for %s", ifi->ifname);
} else {
gettimeofday(&now, NULL);
- timeradd(&now, &ifinfo->timer, &ifinfo->expire);
+ timeradd(&now, &ifi->timer, &ifi->expire);
- if (dflag > 1)
- warnmsg(LOG_DEBUG, __func__,
- "set timer for %s to %d:%d", ifinfo->ifname,
- (int)ifinfo->timer.tv_sec,
- (int)ifinfo->timer.tv_usec);
+ now.tv_sec += ifi->timer.tv_sec;
+ now.tv_usec += ifi->timer.tv_usec;
+ warnmsg(LOG_DEBUG, __func__, "set timer for %s to %s",
+ ifi->ifname, sec2str(&now));
}
#undef MILLION
@@ -742,28 +799,23 @@ rtsold_set_dump_file(int sig __unused)
#endif
static void
-usage(char *progname)
+usage(void)
{
- if (progname && progname[strlen(progname) - 1] != 'd') {
- fprintf(stderr, "usage: rtsol [-dDF] interfaces...\n");
- fprintf(stderr, "usage: rtsol [-dDF] -a\n");
- } else {
- fprintf(stderr, "usage: rtsold [-adDfFm1] interfaces...\n");
- fprintf(stderr, "usage: rtsold [-dDfFm1] -a\n");
- }
- exit(1);
+#ifndef SMALL
+ fprintf(stderr, "usage: rtsold [-adDfFm1] [-O script-name] "
+ "[-P pidfile] [-R script-name] interfaces...\n");
+ fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
+ "[-P pidfile] [-R script-name] -a\n");
+#else
+ fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
+ "[-P pidfile] [-R script-name] interfaces...\n");
+ fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
+ "[-P pidfile] [-R script-name] -a\n");
+#endif
}
void
-#if __STDC__
warnmsg(int priority, const char *func, const char *msg, ...)
-#else
-warnmsg(priority, func, msg, va_alist)
- int priority;
- const char *func;
- const char *msg;
- va_dcl
-#endif
{
va_list ap;
char buf[BUFSIZ];
@@ -805,11 +857,11 @@ autoifprobe(void)
n = 0;
if (getifaddrs(&ifap) != 0)
- return NULL;
+ return (NULL);
if (!Fflag && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
- err(1, "socket");
- /* NOTREACHED */
+ warnmsg(LOG_ERR, __func__, "socket");
+ exit(1);
}
target = NULL;
@@ -845,8 +897,9 @@ autoifprobe(void)
memset(&nd, 0, sizeof(nd));
strlcpy(nd.ifname, ifa->ifa_name, sizeof(nd.ifname));
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
- err(1, "ioctl(SIOCGIFINFO_IN6)");
- /* NOTREACHED */
+ warnmsg(LOG_ERR, __func__,
+ "ioctl(SIOCGIFINFO_IN6)");
+ exit(1);
}
if ((nd.ndi.flags & ND6_IFF_IFDISABLED))
continue;
@@ -856,32 +909,40 @@ autoifprobe(void)
/* if we find multiple candidates, just warn. */
if (n != 0 && dflag > 1)
- warnx("multiple interfaces found");
+ warnmsg(LOG_WARNING, __func__,
+ "multiple interfaces found");
a = (char **)realloc(argv, (n + 1) * sizeof(char **));
- if (a == NULL)
- err(1, "realloc");
+ if (a == NULL) {
+ warnmsg(LOG_ERR, __func__, "realloc");
+ exit(1);
+ }
argv = a;
argv[n] = strdup(ifa->ifa_name);
- if (!argv[n])
- err(1, "malloc");
+ if (!argv[n]) {
+ warnmsg(LOG_ERR, __func__, "malloc");
+ exit(1);
+ }
n++;
}
if (n) {
a = (char **)realloc(argv, (n + 1) * sizeof(char **));
- if (a == NULL)
- err(1, "realloc");
+ if (a == NULL) {
+ warnmsg(LOG_ERR, __func__, "realloc");
+ exit(1);
+ }
argv = a;
argv[n] = NULL;
if (dflag > 0) {
for (i = 0; i < n; i++)
- warnx("probing %s", argv[i]);
+ warnmsg(LOG_WARNING, __func__, "probing %s",
+ argv[i]);
}
}
if (!Fflag)
close(s);
freeifaddrs(ifap);
- return argv;
+ return (argv);
}
diff --git a/usr.sbin/rtsold/rtsold.h b/usr.sbin/rtsold/rtsold.h
index 8aef490..0aa9b4f 100644
--- a/usr.sbin/rtsold/rtsold.h
+++ b/usr.sbin/rtsold/rtsold.h
@@ -31,8 +31,33 @@
* $FreeBSD$
*/
+struct script_msg {
+ TAILQ_ENTRY(script_msg) sm_next;
+
+ char *sm_msg;
+};
+
+struct ra_opt {
+ TAILQ_ENTRY(ra_opt) rao_next;
+
+ u_int8_t rao_type;
+ struct timeval rao_expire;
+ size_t rao_len;
+ void *rao_msg;
+};
+
+TAILQ_HEAD(rainfo_head, ra_opt);
+
+struct rainfo {
+ TAILQ_ENTRY(rainfo) rai_next;
+
+ struct ifinfo *rai_ifinfo;
+ struct sockaddr_in6 rai_saddr;
+ TAILQ_HEAD(, ra_opt) rai_ra_opt;
+};
+
struct ifinfo {
- struct ifinfo *next; /* pointer to the next interface */
+ TAILQ_ENTRY(ifinfo) ifi_next; /* pointer to the next interface */
struct sockaddr_dl *sdl; /* link-layer address */
char ifname[IF_NAMESIZE]; /* interface name */
@@ -49,8 +74,13 @@ struct ifinfo {
struct timeval timer;
struct timeval expire;
int errors; /* # of errors we've got - detect wedge */
+#define IFI_DNSOPT_STATE_NOINFO 0
+#define IFI_DNSOPT_STATE_RECEIVED 1
+ int ifi_rdnss; /* RDNSS option state */
+ int ifi_dnssl; /* DNSSL option state */
int racnt; /* total # of valid RAs it have got */
+ TAILQ_HEAD(, rainfo) ifi_rainfo;
size_t rs_datalen;
u_char *rs_data;
@@ -63,19 +93,50 @@ struct ifinfo {
#define IFS_DOWN 3
#define IFS_TENTATIVE 4
+/* Interface list */
+extern TAILQ_HEAD(ifinfo_head_t, ifinfo) ifinfo_head;
+
+/*
+ * RFC 3542 API deprecates IPV6_PKTINFO in favor of
+ * IPV6_RECVPKTINFO
+ */
+#ifndef IPV6_RECVPKTINFO
+#ifdef IPV6_PKTINFO
+#define IPV6_RECVPKTINFO IPV6_PKTINFO
+#endif
+#endif
+/*
+ * RFC 3542 API deprecates IPV6_HOPLIMIT in favor of
+ * IPV6_RECVHOPLIMIT
+ */
+#ifndef IPV6_RECVHOPLIMIT
+#ifdef IPV6_HOPLIMIT
+#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
+#endif
+#endif
+
+#ifndef IN6ADDR_LINKLOCAL_ALLROUTERS_INIT
+#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
+ {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
+#endif
+
/* rtsold.c */
extern struct timeval tm_max;
extern int dflag;
extern int aflag;
extern int Fflag;
-extern char *otherconf_script;
+extern const char *otherconf_script;
+extern const char *resolvconf_script;
extern int ifconfig(char *);
extern void iflist_init(void);
struct ifinfo *find_ifinfo(int);
+struct rainfo *find_rainfo(struct ifinfo *, struct sockaddr_in6 *);
void rtsol_timer_update(struct ifinfo *);
extern void warnmsg(int, const char *, const char *, ...)
__attribute__((__format__(__printf__, 3, 4)));
extern char **autoifprobe(void);
+extern int ra_opt_handler(struct ifinfo *);
/* if.c */
extern int ifinit(void);
@@ -98,6 +159,7 @@ extern void defrouter_probe(struct ifinfo *);
/* dump.c */
extern void rtsold_dump_file(const char *);
+extern const char *sec2str(const struct timeval *);
/* rtsock.c */
extern int rtsock_open(void);
diff --git a/usr.sbin/tcpdrop/tcpdrop.c b/usr.sbin/tcpdrop/tcpdrop.c
index 6aae85c..dce6c6d 100644
--- a/usr.sbin/tcpdrop/tcpdrop.c
+++ b/usr.sbin/tcpdrop/tcpdrop.c
@@ -20,12 +20,13 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
-#include <netinet/in.h>
+#include <netinet/in.h>
#include <netinet/in_pcb.h>
#define TCPSTATES
#include <netinet/tcp_fsm.h>
diff --git a/usr.sbin/usbdump/usbdump.8 b/usr.sbin/usbdump/usbdump.8
index f2b00e4..104c3b3 100644
--- a/usr.sbin/usbdump/usbdump.8
+++ b/usr.sbin/usbdump/usbdump.8
@@ -25,8 +25,8 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 4, 2010
-.Dt usbdump 8
+.Dd May 31, 2011
+.Dt USBDUMP 8
.Os
.Sh NAME
.Nm usbdump
@@ -63,16 +63,16 @@ Write the raw packets to
.Ar file .
.El
.Sh EXAMPLES
-Captures USB raw packets on usbus2:
+Capture the USB raw packets on usbus2:
.Pp
.Dl "usbdump -i usbus2 -s 256 -v"
.Pp
-Dumps the USB raw packets of usbus2 into the file without packet
+Dump the USB raw packets of usbus2 into the file without packet
size limit:
.Pp
.Dl "usbdump -i usbus2 -s 0 -w /tmp/dump_pkts"
.Pp
-Read the USB raw packets from previous file:
+Read and display the USB raw packets from previous file:
.Pp
.Dl "usbdump -r /tmp/dump_pkts -v"
.Sh OUTPUT FORMAT
diff --git a/usr.sbin/ypserv/yp_main.c b/usr.sbin/ypserv/yp_main.c
index ec39d1b..057174b 100644
--- a/usr.sbin/ypserv/yp_main.c
+++ b/usr.sbin/ypserv/yp_main.c
@@ -216,7 +216,7 @@ reaper(int sig)
static void
usage(void)
{
- fprintf(stderr, "usage: ypserv [-h] [-d] [-n] [-p path] [-P port]\n");
+ fprintf(stderr, "usage: ypserv [-h addr] [-d] [-n] [-p path] [-P port]\n");
exit(1);
}
OpenPOWER on IntegriCloud