summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/sh/eval.c3
-rw-r--r--bin/sh/options.c6
-rw-r--r--etc/network.subr28
-rw-r--r--lib/libiconv/Makefile1
-rw-r--r--release/ia64/mkisoimages.sh20
-rw-r--r--sbin/geom/class/part/gpart.874
-rw-r--r--sbin/geom/class/sched/Makefile2
-rw-r--r--sbin/ifconfig/af_inet6.c4
-rw-r--r--sbin/ifconfig/af_nd6.c74
-rw-r--r--sbin/ipfw/main.c5
-rw-r--r--sbin/mount/mount.813
-rw-r--r--sbin/rcorder/rcorder.88
-rw-r--r--share/man/man4/amdsbwd.48
-rw-r--r--sys/amd64/amd64/mp_machdep.c7
-rw-r--r--sys/cddl/compat/opensolaris/sys/atomic.h2
-rw-r--r--sys/conf/files2
-rw-r--r--sys/conf/options1
-rw-r--r--sys/dev/ath/if_ath.c10
-rw-r--r--sys/dev/cardbus/cardbus_cis.c5
-rw-r--r--sys/dev/cxgbe/adapter.h1
-rw-r--r--sys/dev/cxgbe/t4_main.c2
-rw-r--r--sys/dev/cxgbe/t4_sge.c10
-rw-r--r--sys/dev/pccard/pccard.c8
-rw-r--r--sys/dev/pci/pci.c11
-rw-r--r--sys/dev/puc/pucdata.c10
-rw-r--r--sys/fs/nfs/nfs_var.h19
-rw-r--r--sys/fs/nfsclient/nfs_clport.c66
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c18
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c32
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c12
-rw-r--r--sys/i386/i386/mp_machdep.c7
-rw-r--r--sys/ia64/acpica/acpi_machdep.c7
-rw-r--r--sys/ia64/ia64/machdep.c33
-rw-r--r--sys/ia64/ia64/pal.S25
-rw-r--r--sys/kern/subr_rman.c1
-rw-r--r--sys/netinet/icmp6.h21
-rw-r--r--sys/netinet/in_pcb.c229
-rw-r--r--sys/netinet/in_pcb.h86
-rw-r--r--sys/netinet/in_pcbgroup.c457
-rw-r--r--sys/netinet/ip_divert.c3
-rw-r--r--sys/netinet/ipfw/ip_fw2.c4
-rw-r--r--sys/netinet/ipfw/ip_fw_sockopt.c7
-rw-r--r--sys/netinet/raw_ip.c3
-rw-r--r--sys/netinet/tcp_subr.c3
-rw-r--r--sys/netinet/tcp_syncache.c9
-rw-r--r--sys/netinet/udp_usrreq.c3
-rw-r--r--sys/netinet6/in6.c26
-rw-r--r--sys/netinet6/in6.h5
-rw-r--r--sys/netinet6/in6_pcb.c167
-rw-r--r--sys/netinet6/in6_pcb.h10
-rw-r--r--sys/netinet6/in6_pcbgroup.c103
-rw-r--r--sys/netinet6/in6_proto.c11
-rw-r--r--sys/netinet6/ip6_var.h5
-rw-r--r--sys/netinet6/nd6.c48
-rw-r--r--sys/netinet6/nd6.h1
-rw-r--r--sys/netinet6/nd6_nbr.c14
-rw-r--r--sys/netinet6/nd6_rtr.c40
-rw-r--r--sys/netinet6/send.h2
-rw-r--r--sys/sys/mbuf.h40
-rw-r--r--sys/sys/soundcard.h3
-rw-r--r--sys/ufs/ffs/ffs_alloc.c6
-rw-r--r--tools/regression/bin/sh/expansion/heredoc1.025
-rw-r--r--tools/regression/bin/sh/expansion/heredoc2.015
-rw-r--r--usr.bin/calendar/io.c2
-rw-r--r--usr.bin/grep/Makefile2
-rw-r--r--usr.bin/iconv/Makefile2
-rw-r--r--usr.bin/kdump/mksubr2
-rw-r--r--usr.bin/rctl/Makefile2
-rw-r--r--usr.bin/su/su.116
-rw-r--r--usr.sbin/bluetooth/ath3kfw/Makefile1
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig_ipv61
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/Makefile2
-rw-r--r--usr.sbin/lastlogin/lastlogin.820
-rw-r--r--usr.sbin/lastlogin/lastlogin.c58
-rw-r--r--usr.sbin/rtadvd/advcap.c50
-rw-r--r--usr.sbin/rtadvd/config.c1020
-rw-r--r--usr.sbin/rtadvd/config.h9
-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.835
-rw-r--r--usr.sbin/rtadvd/rtadvd.c1288
-rw-r--r--usr.sbin/rtadvd/rtadvd.conf3
-rw-r--r--usr.sbin/rtadvd/rtadvd.conf.5111
-rw-r--r--usr.sbin/rtadvd/rtadvd.h226
-rw-r--r--usr.sbin/rtadvd/timer.c120
-rw-r--r--usr.sbin/rtadvd/timer.h61
-rw-r--r--usr.sbin/rtsold/Makefile1
-rw-r--r--usr.sbin/rtsold/dump.c40
-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.c503
-rw-r--r--usr.sbin/rtsold/rtsold.829
-rw-r--r--usr.sbin/rtsold/rtsold.c396
-rw-r--r--usr.sbin/rtsold/rtsold.h51
-rw-r--r--usr.sbin/tcpdrop/tcpdrop.c3
101 files changed, 4484 insertions, 2067 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 404de33..585f91e 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -409,6 +409,7 @@ evalsubshell(union node *n, int flags)
struct job *jp;
int backgnd = (n->type == NBACKGND);
+ oexitstatus = exitstatus;
expredir(n->nredir.redirect);
if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
@@ -436,6 +437,7 @@ evalredir(union node *n, int flags)
struct jmploc *savehandler;
volatile int in_redirect = 1;
+ oexitstatus = exitstatus;
expredir(n->nredir.redirect);
savehandler = handler;
if (setjmp(jmploc.loc)) {
@@ -478,7 +480,6 @@ expredir(union node *n)
for (redir = n ; redir ; redir = redir->nfile.next) {
struct arglist fn;
fn.lastp = &fn.list;
- oexitstatus = exitstatus;
switch (redir->type) {
case NFROM:
case NTO:
diff --git a/bin/sh/options.c b/bin/sh/options.c
index a99fe81..60c8852 100644
--- a/bin/sh/options.c
+++ b/bin/sh/options.c
@@ -83,6 +83,7 @@ void
procargs(int argc, char **argv)
{
int i;
+ char *scriptname;
argptr = argv;
if (argc > 0)
@@ -105,8 +106,9 @@ procargs(int argc, char **argv)
optlist[i].val = 0;
arg0 = argv[0];
if (sflag == 0 && minusc == NULL) {
- commandname = arg0 = *argptr++;
- setinputfile(commandname, 0);
+ scriptname = *argptr++;
+ setinputfile(scriptname, 0);
+ commandname = arg0 = scriptname;
}
/* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
if (argptr && minusc && *argptr)
diff --git a/etc/network.subr b/etc/network.subr
index 64fb0fe..ce71b78 100644
--- a/etc/network.subr
+++ b/etc/network.subr
@@ -100,25 +100,19 @@ ifconfig_up()
# inet6 specific
if afexists inet6; then
- if ipv6if $1; then
- if checkyesno ipv6_gateway_enable; then
- _ipv6_opts="-accept_rtadv"
- fi
- else
- if checkyesno ipv6_activate_all_interfaces; then
- _ipv6_opts="-ifdisabled"
- else
- _ipv6_opts="ifdisabled"
- fi
-
- # backward compatibility: $ipv6_enable
- case $ipv6_enable in
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
- _ipv6_opts="${_ipv6_opts} accept_rtadv"
- ;;
- esac
+ if checkyesno ipv6_activate_all_interfaces; then
+ _ipv6_opts="-ifdisabled"
+ elif [ "$1" != "lo0" ]; then
+ _ipv6_opts="ifdisabled"
fi
+ # backward compatibility: $ipv6_enable
+ case $ipv6_enable in
+ [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+ _ipv6_opts="${_ipv6_opts} accept_rtadv"
+ ;;
+ esac
+
if [ -n "${_ipv6_opts}" ]; then
ifconfig $1 inet6 ${_ipv6_opts}
fi
diff --git a/lib/libiconv/Makefile b/lib/libiconv/Makefile
index 078771e..71c2885 100644
--- a/lib/libiconv/Makefile
+++ b/lib/libiconv/Makefile
@@ -19,7 +19,6 @@ SRCS= citrus_bcs.c citrus_bcs_strtol.c citrus_bcs_strtoul.c \
citrus_module.c citrus_none.c citrus_pivot_factory.c \
citrus_prop.c citrus_stdenc.c iconv.c
-WARNS?= 6
CFLAGS+= --param max-inline-insns-single=128 -I ${.CURDIR}/../../include -I${.CURDIR}/../libc/include
.include <bsd.lib.mk>
diff --git a/release/ia64/mkisoimages.sh b/release/ia64/mkisoimages.sh
index 33ba192..f17185b 100644
--- a/release/ia64/mkisoimages.sh
+++ b/release/ia64/mkisoimages.sh
@@ -48,28 +48,32 @@ EFIPART=efipart.sys
if [ $bootable = yes ]; then
EFISZ=65536
MNT=/mnt
- dd if=/dev/zero of=$BASE/$EFIPART count=$EFISZ
- md=`mdconfig -a -t vnode -f $BASE/$EFIPART`
+ dd if=/dev/zero of=$EFIPART count=$EFISZ
+ md=`mdconfig -a -t vnode -f $EFIPART`
newfs_msdos -F 12 -S 512 -h 4 -o 0 -s $EFISZ -u 16 $md
mount -t msdosfs /dev/$md $MNT
mkdir -p $MNT/efi/boot $MNT/boot $MNT/boot/kernel
cp -R $BASE/boot/defaults $MNT/boot
cp $BASE/boot/kernel/kernel $MNT/boot/kernel
- cp $BASE/boot/kernel/ispfw.ko $MNT/boot/kernel
+ if [ -s $BASE/boot/kernel/ispfw.ko ]; then
+ cp $BASE/boot/kernel/ispfw.ko $MNT/boot/kernel
+ fi
cp $BASE/boot/device.hints $MNT/boot
cp $BASE/boot/loader.* $MNT/boot
- cp $BASE/boot/mfsroot.gz $MNT/boot
+ if [ -s $BASE/boot/mfsroot.gz ]; then
+ cp $BASE/boot/mfsroot.gz $MNT/boot
+ fi
cp $BASE/boot/support.4th $MNT/boot
mv $MNT/boot/loader.efi $MNT/efi/boot/bootia64.efi
umount $MNT
mdconfig -d -u $md
- BOOTOPTS="-b bootimage=i386;$EFIPART -o no-emul-boot"
+ BOOTOPTS="-o bootimage=i386;$EFIPART -o no-emul-boot"
else
BOOTOPTS=""
fi
-echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $1/etc/fstab
+echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $BASE/etc/fstab
makefs -t cd9660 $BOOTOPTS -o rockridge -o label=$LABEL $NAME $BASE $*
-rm -f $BASE/$EFIPART
-rm $1/etc/fstab
+rm $BASE/etc/fstab
+rm -f $EFIPART
exit 0
diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8
index 940620c..4365d6b 100644
--- a/sbin/geom/class/part/gpart.8
+++ b/sbin/geom/class/part/gpart.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 30, 2011
+.Dd June 6, 2011
.Dt GPART 8
.Os
.Sh NAME
@@ -530,16 +530,17 @@ about its use.
.El
.\"
.Sh PARTITION TYPES
+Partition types are identified on disk by particular strings or magic
+values.
The
.Nm
-utility uses symbolic names for common partition types to avoid that the
-user needs to know what the partitioning scheme in question is and what
-the actual number or identification needs to be used for a particular
-type.
+utility uses symbolic names for common partition types to avoid the
+user needing to know these values or other details of the partitioning
+scheme in question.
The
.Nm
utility also allows the user to specify scheme-specific partition types
-for partition types that do not have symbol names.
+for partition types that do not have symbolic names.
The symbolic names currently understood are:
.Bl -tag -width ".Cm freebsd-vinum"
.It Cm bios-boot
@@ -740,30 +741,30 @@ action or reverted with the
.Cm undo
action.
.Sh RECOVERING
-The GEOM class PART supports recovering of partition tables only for GPT.
+The GEOM PART class supports recovering of partition tables only for GPT.
The GUID partition table has a primary and secondary (backup) copy of
-metadata for redundance.
-They are stored in the begining and in the end of device respectively.
-Therefore it is acceptable to have some corruptions in the metadata that
-are not fatal to work with GPT.
-When kernel detects corrupt metadata it marks this table as corrupt and
-reports about corruption.
-Any changes in corrupt table are prohibited except
+metadata for redundance, these are stored at the begining and the end
+of the device respectively.
+As a result of having two copies, it is acceptable to have some corruption
+within the metadata that is not fatal to the working of GPT.
+When the kernel detects corrupt metadata it marks this table as corrupt and
+reports the corruption.
+Any operations on corrupt tables are prohibited except for
.Cm destroy
and
.Cm recover .
.Pp
-In case when only first sector is corrupt kernel can not detect GPT even
-if partition table is not corrupt.
-You can write protective MBR with
+If the first sector of a provider is corrupt, the kernel can not detect GPT
+even if partition table itself is not corrupt.
+You can rewrite the protective MBR using the
.Xr dd 1
-command to restore ability of GPT detection.
-The copy of protective MBR is usually located in the
+command, to restore the ability to detect the GPT.
+The copy of the protective MBR is usually located in the
.Pa /boot/pmbr
file.
.Pp
-In case when some of metadata is corrupt you will get to know about this
-from kernel's messages like these:
+If one GPT header appears to be corrupt but the other copy remains intact,
+the kernel will log the following:
.Bd -literal -offset indent
GEOM: provider: the primary GPT table is corrupt or invalid.
GEOM: provider: using the secondary instead -- recovery strongly advised.
@@ -777,32 +778,31 @@ GEOM: provider: using the primary only -- recovery suggested.
.Pp
Also
.Nm
-commands like
+commands such as
.Cm show , status
and
.Cm list
-will report about corrupt table.
+will report about corrupt tables.
.Pp
-In case when the size of device has changed (e.g.\& volume expansion) the
-secondary GPT header will become located not in the last sector.
+If the size of the device has changed (e.g.\& volume expansion) the
+secondary GPT header will no longer be located in the last sector.
This is not a metadata corruption, but it is dangerous because any
-corruption of the primary GPT will lead to lost of partition table.
-Kernel reports about this problem with message:
+corruption of the primary GPT will lead to loss of partition table.
+This problem is reported by the kernel with the message:
.Bd -literal -offset indent
GEOM: provider: the secondary GPT header is not in the last LBA.
.Ed
.Pp
-A corrupt table can be recovered with
+This situation can be recovered with the
.Cm recover
command.
-This command does reconstruction of corrupt metadata using
-known valid metadata.
-Also it can relocate secondary GPT to the end of device.
+This command reconstructs the corrupt metadata using known valid
+metadata and relocates the secondary GPT to the end of the device.
.Pp
.Em NOTE :
-The GEOM class PART can detect the same partition table on different GEOM
-providers and some of them will be marked as corrupt.
-Be careful when choosing a provider for recovering.
+The GEOM PART class can detect the same partition table visible through
+different GEOM providers, and some of them will be marked as corrupt.
+Be careful when choosing a provider for recovery.
If you choose incorrectly you can destroy the metadata of another GEOM class,
e.g.\& GEOM MIRROR or GEOM LABEL.
.Sh SYSCTL VARIABLES
@@ -815,11 +815,11 @@ The default value is shown next to each variable.
.Bl -tag -width indent
.It Va kern.geom.part.check_integrity : No 1
This variable controls the behaviour of metadata integrity checks.
-When integrity checks are enabled
+When integrity checks are enabled, the
.Nm PART
-GEOM class verifies all generic partition parameters that it gets from the
+GEOM class verifies all generic partition parameters obtained from the
disk metadata.
-If some inconsistency is detected, partition table will be
+If some inconsistency is detected, the partition table will be
rejected with a diagnostic message:
.Sy "GEOM_PART: Integrity check failed (provider, scheme)" .
.El
diff --git a/sbin/geom/class/sched/Makefile b/sbin/geom/class/sched/Makefile
index a6ccd58..6f54d3f 100644
--- a/sbin/geom/class/sched/Makefile
+++ b/sbin/geom/class/sched/Makefile
@@ -5,6 +5,4 @@
GEOM_CLASS= sched
-WARNS?= 6
-
.include <bsd.lib.mk>
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index 2337c34..585be05 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -69,6 +69,7 @@ static int explicit_prefix = 0;
extern void setnd6flags(const char *, int, int, const struct afswtch *);
extern void setnd6defif(const char *, int, int, const struct afswtch *);
+extern void nd6_status(int);
static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
@@ -498,6 +499,8 @@ static struct cmd inet6_cmds[] = {
DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags),
DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags),
+ DEF_CMD("no_radr", ND6_IFF_NO_RADR, setnd6flags),
+ DEF_CMD("-no_radr", -ND6_IFF_NO_RADR, setnd6flags),
DEF_CMD("defaultif", 1, setnd6defif),
DEF_CMD("-defaultif", -1, setnd6defif),
DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
@@ -519,6 +522,7 @@ static struct afswtch af_inet6 = {
.af_status = in6_status,
.af_getaddr = in6_getaddr,
.af_getprefix = in6_getprefix,
+ .af_other_status = nd6_status,
.af_postproc = in6_postproc,
.af_status_tunnel = in6_status_tunnel,
.af_settunnel = in6_set_tunnel,
diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c
index 5260c50..eed00ea 100644
--- a/sbin/ifconfig/af_nd6.c
+++ b/sbin/ifconfig/af_nd6.c
@@ -58,11 +58,12 @@ static const char rcsid[] =
#define MAX_SYSCTL_TRY 5
#define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
"\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \
- "\020DEFAULTIF"
+ "\007NO_RADR\020DEFAULTIF"
static int isnd6defif(int);
void setnd6flags(const char *, int, int, const struct afswtch *);
void setnd6defif(const char *, int, int, const struct afswtch *);
+void nd6_status(int);
void
setnd6flags(const char *dummyaddr __unused,
@@ -136,64 +137,13 @@ isnd6defif(int s)
return (ndifreq.ifindex == ifindex);
}
-static void
+void
nd6_status(int s)
{
struct in6_ndireq nd;
- struct rt_msghdr *rtm;
- size_t needed;
- char *buf, *next;
- int mib[6], ntry;
int s6;
int error;
- int isinet6, isdefif;
-
- /* Check if the interface has at least one IPv6 address. */
- mib[0] = CTL_NET;
- mib[1] = PF_ROUTE;
- mib[2] = 0;
- mib[3] = AF_INET6;
- mib[4] = NET_RT_IFLIST;
- mib[5] = if_nametoindex(ifr.ifr_name);
-
- /* Try to prevent a race between two sysctls. */
- ntry = 0;
- do {
- error = sysctl(mib, 6, NULL, &needed, NULL, 0);
- if (error) {
- warn("sysctl(NET_RT_IFLIST)/estimate");
- return;
- }
- buf = malloc(needed);
- if (buf == NULL) {
- warn("malloc for sysctl(NET_RT_IFLIST) failed");
- return;
- }
- if ((error = sysctl(mib, 6, buf, &needed, NULL, 0)) < 0) {
- if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
- warn("sysctl(NET_RT_IFLIST)/get");
- free(buf);
- return;
- }
- free(buf);
- buf = NULL;
- }
- } while (buf == NULL);
-
- isinet6 = 0;
- for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)next;
-
- if (rtm->rtm_version != RTM_VERSION)
- continue;
- if (rtm->rtm_type == RTM_NEWADDR) {
- isinet6 = 1;
- break;
- }
- }
- free(buf);
- if (!isinet6)
- return;
+ int isdefif;
memset(&nd, 0, sizeof(nd));
strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
@@ -215,19 +165,3 @@ nd6_status(int s)
(unsigned int)(nd.ndi.flags | (isdefif << 15)), ND6BITS);
putchar('\n');
}
-
-static struct afswtch af_nd6 = {
- .af_name = "nd6",
- .af_af = AF_LOCAL,
- .af_other_status= nd6_status,
-};
-
-static __constructor void
-nd6_ctor(void)
-{
-
- if (!feature_present("inet6"))
- return;
-
- af_register(&af_nd6);
-}
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
index fb3f3fb..109b62b 100644
--- a/sbin/ipfw/main.c
+++ b/sbin/ipfw/main.c
@@ -356,6 +356,7 @@ ipfw_main(int oldac, char **oldav)
*/
co.do_nat = 0;
co.do_pipe = 0;
+ co.use_set = 0;
if (!strncmp(*av, "nat", strlen(*av)))
co.do_nat = 1;
else if (!strncmp(*av, "pipe", strlen(*av)))
@@ -444,7 +445,7 @@ static void
ipfw_readfile(int ac, char *av[])
{
#define MAX_ARGS 32
- char buf[BUFSIZ];
+ char buf[4096];
char *progname = av[0]; /* original program name */
const char *cmd = NULL; /* preprocessor name, if any */
const char *filename = av[ac-1]; /* file to read */
@@ -552,7 +553,7 @@ ipfw_readfile(int ac, char *av[])
}
}
- while (fgets(buf, BUFSIZ, f)) { /* read commands */
+ while (fgets(buf, sizeof(buf), f)) { /* read commands */
char linename[20];
char *args[2];
diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8
index 2140b37..fdfd75c 100644
--- a/sbin/mount/mount.8
+++ b/sbin/mount/mount.8
@@ -28,7 +28,7 @@
.\" @(#)mount.8 8.8 (Berkeley) 6/16/94
.\" $FreeBSD$
.\"
-.Dd April 28, 2011
+.Dd June 6, 2011
.Dt MOUNT 8
.Os
.Sh NAME
@@ -348,7 +348,6 @@ option) may be passed as a comma separated list; these options are
distinguished by a leading
.Dq \&-
(dash).
-Options that take a value are specified using the syntax -option=value.
For example, the
.Nm
command:
@@ -363,6 +362,16 @@ to execute the equivalent of:
/sbin/mount_cd9660 -e /dev/cd0 /cdrom
.Ed
.Pp
+Options that take a value are specified using the -option=value syntax:
+.Bd -literal -offset indent
+mount -t msdosfs -o -u=fred,-g=wheel /dev/da0s1 /mnt
+.Ed
+.Pp
+is equivalent to
+.Bd -literal -offset indent
+/sbin/mount_msdosfs -u fred -g wheel /dev/da0s1 /mnt
+.Ed
+.Pp
Additional options specific to file system types
which are not internally known
(see the description of the
diff --git a/sbin/rcorder/rcorder.8 b/sbin/rcorder/rcorder.8
index b17b0a3..a47f013 100644
--- a/sbin/rcorder/rcorder.8
+++ b/sbin/rcorder/rcorder.8
@@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 9, 2008
+.Dd June 6, 2011
.Dt RCORDER 8
.Os
.Sh NAME
@@ -89,6 +89,12 @@ and
lines may appear, but all such lines must appear in a sequence without
any intervening lines, as once a line that does not follow the format
is reached, parsing stops.
+Note that for historical reasons,
+.Dq Li REQUIRES ,
+.Dq Li PROVIDES ,
+and
+.Dq Li KEYWORDS
+are also accepted in addition to the above.
.Pp
The options are as follows:
.Bl -tag -width indent
diff --git a/share/man/man4/amdsbwd.4 b/share/man/man4/amdsbwd.4
index 370cfa8..578640b 100644
--- a/share/man/man4/amdsbwd.4
+++ b/share/man/man4/amdsbwd.4
@@ -61,12 +61,14 @@ AMD SB600 and SB7xx south bridge chips.
The
.Nm
driver first appeared in
-.Fx 9.0 .
+.Fx 7.3
+and
+.Fx 8.1 .
.Sh AUTHORS
.An -nosplit
The
.Nm
driver was written by
-.An Andiry Gapon Aq avg@FreeBSD.org .
+.An Andriy Gapon Aq avg@FreeBSD.org .
This manual page was written by
-.An Andiry Gapon Aq avg@FreeBSD.org .
+.An Andriy Gapon Aq avg@FreeBSD.org .
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 9e20f95..d72afd6 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -242,8 +242,11 @@ topo_probe_0x4(void)
* logical processors that belong to the same core
* as BSP thus deducing number of threads per core.
*/
- cpuid_count(0x04, 0, p);
- max_cores = ((p[0] >> 26) & 0x3f) + 1;
+ if (cpu_high >= 0x4) {
+ cpuid_count(0x04, 0, p);
+ max_cores = ((p[0] >> 26) & 0x3f) + 1;
+ } else
+ max_cores = 1;
core_id_bits = mask_width(max_logical/max_cores);
if (core_id_bits < 0)
return;
diff --git a/sys/cddl/compat/opensolaris/sys/atomic.h b/sys/cddl/compat/opensolaris/sys/atomic.h
index af9cc5d..f34d77e 100644
--- a/sys/cddl/compat/opensolaris/sys/atomic.h
+++ b/sys/cddl/compat/opensolaris/sys/atomic.h
@@ -40,8 +40,6 @@
extern void atomic_add_64(volatile uint64_t *target, int64_t delta);
extern void atomic_dec_64(volatile uint64_t *target);
#endif
-#ifndef __LP64__
-#endif
#ifndef __sparc64__
extern uint32_t atomic_cas_32(volatile uint32_t *target, uint32_t cmp,
uint32_t newval);
diff --git a/sys/conf/files b/sys/conf/files
index 59286a5..d654c6f 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2748,6 +2748,7 @@ netinet/ip_gre.c optional gre inet
netinet/ip_id.c optional inet
netinet/in_mcast.c optional inet
netinet/in_pcb.c optional inet | inet6
+netinet/in_pcbgroup.c optional inet pcbgroup | inet6 pcbgroup
netinet/in_proto.c optional inet | inet6 \
compile-with "${NORMAL_C} -I$S/contrib/pf"
netinet/in_rmx.c optional inet
@@ -2825,6 +2826,7 @@ netinet6/in6_gif.c optional gif inet6 | netgraph_gif inet6
netinet6/in6_ifattach.c optional inet6
netinet6/in6_mcast.c optional inet6
netinet6/in6_pcb.c optional inet6
+netinet6/in6_pcbgroup.c optional inet6 pcbgroup
netinet6/in6_proto.c optional inet6
netinet6/in6_rmx.c optional inet6
netinet6/in6_src.c optional inet6
diff --git a/sys/conf/options b/sys/conf/options
index a608d86..ee696a8 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -419,6 +419,7 @@ MROUTING opt_mrouting.h
NCP
NETATALK opt_atalk.h
NFSLOCKD
+PCBGROUP opt_pcbgroup.h
RADIX_MPATH opt_mpath.h
ROUTETABLES opt_route.h
SLIP_IFF_OPTS opt_slip.h
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index 451bbeaf..6c7b0e7 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -3473,7 +3473,15 @@ ath_rx_proc(void *arg, int npending)
if (rs->rs_status & HAL_RXERR_PHY) {
sc->sc_stats.ast_rx_phyerr++;
/* Process DFS radar events */
- ath_dfs_process_phy_err(sc, mtod(m, char *), tsf, rs);
+ if ((rs->rs_phyerr == HAL_PHYERR_RADAR) ||
+ (rs->rs_phyerr == HAL_PHYERR_FALSE_RADAR_EXT)) {
+ /* Since we're touching the frame data, sync it */
+ bus_dmamap_sync(sc->sc_dmat,
+ bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ /* Now pass it to the radar processing code */
+ ath_dfs_process_phy_err(sc, mtod(m, char *), tsf, rs);
+ }
/* Be suitably paranoid about receiving phy errors out of the stats array bounds */
if (rs->rs_phyerr < 64)
diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c
index 2cfea19..3352a56 100644
--- a/sys/dev/cardbus/cardbus_cis.c
+++ b/sys/dev/cardbus/cardbus_cis.c
@@ -324,7 +324,7 @@ decode_tuple_bar(device_t cbdev, device_t child, int id,
* hint when the cardbus bridge is a child of pci0 (the main
* bus). The PC Card spec seems to indicate that this should
* only be done on x86 based machines, which suggests that on
- * non-x86 machines the adddresses can be anywhere. Since the
+ * non-x86 machines the addresses can be anywhere. Since the
* hardware can do it on non-x86 machines, it should be able
* to do it on x86 machines too. Therefore, we can and should
* ignore this hint. Furthermore, the PC Card spec recommends
@@ -430,7 +430,6 @@ cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
{
if (res != CIS_CONFIG_SPACE) {
bus_release_resource(child, SYS_RES_MEMORY, rid, res);
- bus_delete_resource(child, SYS_RES_MEMORY, rid);
}
}
@@ -467,7 +466,7 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
}
/* allocate the memory space to read CIS */
- res = bus_alloc_resource(child, SYS_RES_MEMORY, rid, 0, ~0, 1,
+ res = bus_alloc_resource_any(child, SYS_RES_MEMORY, rid,
rman_make_alignment_flags(4096) | RF_ACTIVE);
if (res == NULL) {
device_printf(cbdev, "Unable to allocate resource "
diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h
index 58ff04e..0b33b67 100644
--- a/sys/dev/cxgbe/adapter.h
+++ b/sys/dev/cxgbe/adapter.h
@@ -396,6 +396,7 @@ struct sge_ctrlq {
struct sge {
uint16_t timer_val[SGE_NTIMERS];
uint8_t counter_val[SGE_NCOUNTERS];
+ int fl_starve_threshold;
int nrxq; /* total rx queues (all ports and the rest) */
int ntxq; /* total tx queues (all ports and the rest) */
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 165a677..90e5001 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -492,6 +492,8 @@ t4_attach(device_t dev)
V_RXTSHIFTMAXR2(15) | V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
V_KEEPALIVEMAXR1(4) | V_KEEPALIVEMAXR2(9));
t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
+ t4_set_reg_field(sc, A_TP_PARA_REG3, F_TUNNELCNGDROP0 |
+ F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | F_TUNNELCNGDROP3, 0);
setup_memwin(sc);
diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c
index f8efda5..b3e3567 100644
--- a/sys/dev/cxgbe/t4_sge.c
+++ b/sys/dev/cxgbe/t4_sge.c
@@ -203,6 +203,9 @@ t4_sge_init(struct adapter *sc)
FL_BUF_SIZE(i));
}
+ i = t4_read_reg(sc, A_SGE_CONM_CTRL);
+ s->fl_starve_threshold = G_EGRTHRESHOLD(i) * 2 + 1;
+
t4_write_reg(sc, A_SGE_INGRESS_RX_THRESHOLD,
V_THRESHOLD_0(s->counter_val[0]) |
V_THRESHOLD_1(s->counter_val[1]) |
@@ -1233,7 +1236,8 @@ alloc_iq_fl(struct port_info *pi, struct sge_iq *iq, struct sge_fl *fl,
sc->sge.eqmap[cntxt_id] = (void *)fl;
FL_LOCK(fl);
- refill_fl(sc, fl, -1, 8);
+ /* Just enough to make sure it doesn't starve right away. */
+ refill_fl(sc, fl, roundup(sc->sge.fl_starve_threshold, 8), 8);
FL_UNLOCK(fl);
}
@@ -1389,6 +1393,10 @@ alloc_rxq(struct port_info *pi, struct sge_rxq *rxq, int intr_idx, int idx)
if (rc != 0)
return (rc);
+ FL_LOCK(&rxq->fl);
+ refill_fl(pi->adapter, &rxq->fl, rxq->fl.needed / 8, 8);
+ FL_UNLOCK(&rxq->fl);
+
#ifdef INET
rc = tcp_lro_init(&rxq->lro);
if (rc != 0)
diff --git a/sys/dev/pccard/pccard.c b/sys/dev/pccard/pccard.c
index 00cd1dc..1de571c 100644
--- a/sys/dev/pccard/pccard.c
+++ b/sys/dev/pccard/pccard.c
@@ -1405,8 +1405,8 @@ pccard_ccr_read_impl(device_t brdev, device_t child, uint32_t offset,
struct pccard_ivar *devi = PCCARD_IVAR(child);
*val = pccard_ccr_read(devi->pf, offset);
- device_printf(child, "ccr_read of %#x (%#x) is %#x\n", offset,
- devi->pf->pf_ccr_offset, *val);
+ DEVPRINTF((child, "ccr_read of %#x (%#x) is %#x\n", offset,
+ devi->pf->pf_ccr_offset, *val));
return 0;
}
@@ -1421,8 +1421,8 @@ pccard_ccr_write_impl(device_t brdev, device_t child, uint32_t offset,
* Can't use pccard_ccr_write since client drivers may access
* registers not contained in the 'mask' if they are non-standard.
*/
- device_printf(child, "ccr_write of %#x to %#x (%#x)\n", val, offset,
- devi->pf->pf_ccr_offset);
+ DEVPRINTF((child, "ccr_write of %#x to %#x (%#x)\n", val, offset,
+ devi->pf->pf_ccr_offset));
bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, pf->pf_ccr_offset + offset,
val);
return 0;
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 22046c1..9cd5a1c 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -2576,6 +2576,17 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl,
uint16_t cmd;
struct resource *res;
+ /*
+ * The BAR may already exist if the device is a CardBus card
+ * whose CIS is stored in this BAR.
+ */
+ pm = pci_find_bar(dev, reg);
+ if (pm != NULL) {
+ maprange = pci_maprange(pm->pm_value);
+ barlen = maprange == 64 ? 2 : 1;
+ return (barlen);
+ }
+
pci_read_bar(dev, reg, &map, &testval);
if (PCI_BAR_MEM(map)) {
type = SYS_RES_MEMORY;
diff --git a/sys/dev/puc/pucdata.c b/sys/dev/puc/pucdata.c
index a56971e..2b38d9b 100644
--- a/sys/dev/puc/pucdata.c
+++ b/sys/dev/puc/pucdata.c
@@ -51,12 +51,12 @@ static puc_config_f puc_config_amc;
static puc_config_f puc_config_diva;
static puc_config_f puc_config_exar;
static puc_config_f puc_config_icbook;
+static puc_config_f puc_config_oxford_pcie;
static puc_config_f puc_config_quatech;
static puc_config_f puc_config_syba;
static puc_config_f puc_config_siig;
static puc_config_f puc_config_timedia;
static puc_config_f puc_config_titan;
-static puc_config_f puc_config_oxford_pcie;
const struct puc_cfg puc_pci_devices[] = {
@@ -1366,14 +1366,12 @@ puc_config_oxford_pcie(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port,
bar = puc_get_bar(sc, cfg->rid);
if (bar == NULL)
return (ENXIO);
-
for (idx = 0; idx < sc->sc_nports; idx++) {
- value = bus_read_1(bar->b_res, 0x1000 + (idx << 9)
- + 0x92);
+ value = bus_read_1(bar->b_res, 0x1000 + (idx << 9) +
+ 0x92);
bus_write_1(bar->b_res, 0x1000 + (idx << 9) + 0x92,
- value | 0x10);
+ value | 0x10);
}
-
return (0);
case PUC_CFG_GET_LEN:
*res = 0x200;
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 8ed60a7..5f944b5 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -401,10 +401,10 @@ int nfsrpc_readdirplus(vnode_t, struct uio *, nfsuint64 *,
int nfsrpc_commit(vnode_t, u_quad_t, int, struct ucred *,
NFSPROC_T *, u_char *, struct nfsvattr *, int *, void *);
int nfsrpc_advlock(vnode_t, off_t, int, struct flock *, int,
- struct ucred *, NFSPROC_T *);
+ struct ucred *, NFSPROC_T *, void *, int);
int nfsrpc_lockt(struct nfsrv_descript *, vnode_t,
struct nfsclclient *, u_int64_t, u_int64_t, struct flock *,
- struct ucred *, NFSPROC_T *);
+ struct ucred *, NFSPROC_T *, void *, int);
int nfsrpc_lock(struct nfsrv_descript *, struct nfsmount *, vnode_t,
u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t,
u_int64_t, short, struct ucred *, NFSPROC_T *, int);
@@ -439,16 +439,16 @@ struct nfsclclient *nfscl_findcl(struct nfsmount *);
void nfscl_clientrelease(struct nfsclclient *);
void nfscl_freelock(struct nfscllock *, int);
int nfscl_getbytelock(vnode_t, u_int64_t, u_int64_t, short,
- struct ucred *, NFSPROC_T *, struct nfsclclient *, int, u_int8_t *,
- u_int8_t *, struct nfscllockowner **, int *, int *);
+ struct ucred *, NFSPROC_T *, struct nfsclclient *, int, void *, int,
+ u_int8_t *, u_int8_t *, struct nfscllockowner **, int *, int *);
int nfscl_relbytelock(vnode_t, u_int64_t, u_int64_t,
struct ucred *, NFSPROC_T *, int, struct nfsclclient *,
- struct nfscllockowner **, int *);
+ void *, int, struct nfscllockowner **, int *);
int nfscl_checkwritelocked(vnode_t, struct flock *,
- struct ucred *, NFSPROC_T *);
+ struct ucred *, NFSPROC_T *, void *, int);
void nfscl_lockrelease(struct nfscllockowner *, int, int);
void nfscl_fillclid(u_int64_t, char *, u_int8_t *, u_int16_t);
-void nfscl_filllockowner(NFSPROC_T *, u_int8_t *);
+void nfscl_filllockowner(void *, u_int8_t *, int);
void nfscl_freeopen(struct nfsclopen *, int);
void nfscl_umount(struct nfsmount *, NFSPROC_T *);
void nfscl_renewthread(struct nfsclclient *, NFSPROC_T *);
@@ -466,9 +466,10 @@ void nfscl_lockexcl(struct nfsv4lock *, void *);
void nfscl_lockunlock(struct nfsv4lock *);
void nfscl_lockderef(struct nfsv4lock *);
void nfscl_docb(struct nfsrv_descript *, NFSPROC_T *);
-void nfscl_releasealllocks(struct nfsclclient *, vnode_t, NFSPROC_T *);
+void nfscl_releasealllocks(struct nfsclclient *, vnode_t, NFSPROC_T *, void *,
+ int);
int nfscl_lockt(vnode_t, struct nfsclclient *, u_int64_t,
- u_int64_t, struct flock *, NFSPROC_T *);
+ u_int64_t, struct flock *, NFSPROC_T *, void *, int);
int nfscl_mustflush(vnode_t);
int nfscl_nodeleg(vnode_t, int);
int nfscl_removedeleg(vnode_t, NFSPROC_T *, nfsv4stateid_t *);
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index 0c3a4c9..4d88bd2 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -500,7 +500,7 @@ nfscl_fillclid(u_int64_t clval, char *uuid, u_int8_t *cp, u_int16_t idlen)
* Fill in a lock owner name. For now, pid + the process's creation time.
*/
void
-nfscl_filllockowner(struct thread *td, u_int8_t *cp)
+nfscl_filllockowner(void *id, u_int8_t *cp, int flags)
{
union {
u_int32_t lval;
@@ -508,37 +508,35 @@ nfscl_filllockowner(struct thread *td, u_int8_t *cp)
} tl;
struct proc *p;
-if (td == NULL) {
- printf("NULL td\n");
- bzero(cp, 12);
- return;
-}
- p = td->td_proc;
-if (p == NULL) {
- printf("NULL pid\n");
- bzero(cp, 12);
- return;
-}
- tl.lval = p->p_pid;
- *cp++ = tl.cval[0];
- *cp++ = tl.cval[1];
- *cp++ = tl.cval[2];
- *cp++ = tl.cval[3];
-if (p->p_stats == NULL) {
- printf("pstats null\n");
- bzero(cp, 8);
- return;
-}
- tl.lval = p->p_stats->p_start.tv_sec;
- *cp++ = tl.cval[0];
- *cp++ = tl.cval[1];
- *cp++ = tl.cval[2];
- *cp++ = tl.cval[3];
- tl.lval = p->p_stats->p_start.tv_usec;
- *cp++ = tl.cval[0];
- *cp++ = tl.cval[1];
- *cp++ = tl.cval[2];
- *cp = tl.cval[3];
+ if (id == NULL) {
+ printf("NULL id\n");
+ bzero(cp, NFSV4CL_LOCKNAMELEN);
+ return;
+ }
+ if ((flags & F_POSIX) != 0) {
+ p = (struct proc *)id;
+ tl.lval = p->p_pid;
+ *cp++ = tl.cval[0];
+ *cp++ = tl.cval[1];
+ *cp++ = tl.cval[2];
+ *cp++ = tl.cval[3];
+ tl.lval = p->p_stats->p_start.tv_sec;
+ *cp++ = tl.cval[0];
+ *cp++ = tl.cval[1];
+ *cp++ = tl.cval[2];
+ *cp++ = tl.cval[3];
+ tl.lval = p->p_stats->p_start.tv_usec;
+ *cp++ = tl.cval[0];
+ *cp++ = tl.cval[1];
+ *cp++ = tl.cval[2];
+ *cp = tl.cval[3];
+ } else if ((flags & F_FLOCK) != 0) {
+ bcopy(&id, cp, sizeof(id));
+ bzero(&cp[sizeof(id)], NFSV4CL_LOCKNAMELEN - sizeof(id));
+ } else {
+ printf("nfscl_filllockowner: not F_POSIX or F_FLOCK\n");
+ bzero(cp, NFSV4CL_LOCKNAMELEN);
+ }
}
/*
@@ -943,6 +941,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
sad.sin_family = AF_INET;
sad.sin_len = sizeof (struct sockaddr_in);
sad.sin_addr.s_addr = sin->sin_addr.s_addr;
+ CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
rt = rtalloc1((struct sockaddr *)&sad, 0, 0UL);
if (rt != NULL) {
if (rt->rt_ifp != NULL &&
@@ -956,6 +955,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
}
RTFREE_LOCKED(rt);
}
+ CURVNET_RESTORE();
#ifdef INET6
} else if (nmp->nm_nam->sa_family == AF_INET6) {
struct sockaddr_in6 sad6, *sin6;
@@ -966,6 +966,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
sad6.sin6_family = AF_INET6;
sad6.sin6_len = sizeof (struct sockaddr_in6);
sad6.sin6_addr = sin6->sin6_addr;
+ CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
rt = rtalloc1((struct sockaddr *)&sad6, 0, 0UL);
if (rt != NULL) {
if (rt->rt_ifp != NULL &&
@@ -980,6 +981,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
}
RTFREE_LOCKED(rt);
}
+ CURVNET_RESTORE();
#endif
}
return (retp);
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 0fc9bfd..5d83d0b 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -3459,7 +3459,7 @@ nfsmout:
*/
APPLESTATIC int
nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
- int reclaim, struct ucred *cred, NFSPROC_T *p)
+ int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
struct nfscllockowner *lp;
struct nfsclclient *clp;
@@ -3511,11 +3511,11 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
error = nfscl_getcl(vp, cred, p, &clp);
if (error)
return (error);
- error = nfscl_lockt(vp, clp, off, len, fl, p);
+ error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
if (!error) {
clidrev = clp->nfsc_clientidrev;
error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
- p);
+ p, id, flags);
} else if (error == -1) {
error = 0;
}
@@ -3530,7 +3530,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
return (error);
do {
error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
- clp, &lp, &dorpc);
+ clp, id, flags, &lp, &dorpc);
/*
* If it returns a NULL lp, we're done.
*/
@@ -3538,7 +3538,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
if (callcnt == 0)
nfscl_clientrelease(clp);
else
- nfscl_releasealllocks(clp, vp, p);
+ nfscl_releasealllocks(clp, vp, p, id, flags);
return (error);
}
if (nmp->nm_clp != NULL)
@@ -3572,10 +3572,10 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
}
callcnt++;
} while (error == 0 && nd->nd_repstat == 0);
- nfscl_releasealllocks(clp, vp, p);
+ nfscl_releasealllocks(clp, vp, p, id, flags);
} else if (op == F_SETLK) {
error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
- NULL, 0, NULL, NULL, &lp, &newone, &donelocally);
+ NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
if (error || donelocally) {
return (error);
}
@@ -3625,7 +3625,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
APPLESTATIC int
nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
- struct ucred *cred, NFSPROC_T *p)
+ struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
u_int32_t *tl;
int error, type, size;
@@ -3643,7 +3643,7 @@ nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
tl += 2;
*tl++ = clp->nfsc_clientid.lval[0];
*tl = clp->nfsc_clientid.lval[1];
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
(void) nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN);
error = nfscl_request(nd, vp, p, cred, NULL);
if (error)
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index 86d71b6..aa81437 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -226,7 +226,7 @@ nfscl_open(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t amode, int usedeleg,
* If none found, add the new one or return error, depending upon
* "create".
*/
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(p->td_proc, own, F_POSIX);
NFSLOCKCLSTATE();
dp = NULL;
/* First check the delegation list */
@@ -521,7 +521,7 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
* If p != NULL, we want to search the parentage tree
* for a matching OpenOwner and use that.
*/
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(p->td_proc, own, F_POSIX);
error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, NULL, p,
mode, NULL, &op);
if (error == 0) {
@@ -596,7 +596,7 @@ nfscl_getopen(struct nfsclownerhead *ohp, u_int8_t *nfhp, int fhlen,
op = NULL;
while (op == NULL && (nproc != NULL || rown != NULL)) {
if (nproc != NULL) {
- nfscl_filllockowner(nproc, own);
+ nfscl_filllockowner(nproc->td_proc, own, F_POSIX);
ownp = own;
} else {
ownp = rown;
@@ -881,7 +881,7 @@ nfscl_clientrelease(struct nfsclclient *clp)
APPLESTATIC int
nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
short type, struct ucred *cred, NFSPROC_T *p, struct nfsclclient *rclp,
- int recovery, u_int8_t *rownp, u_int8_t *ropenownp,
+ int recovery, void *id, int flags, u_int8_t *rownp, u_int8_t *ropenownp,
struct nfscllockowner **lpp, int *newonep, int *donelocallyp)
{
struct nfscllockowner *lp;
@@ -942,7 +942,7 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
if (recovery) {
ownp = rownp;
} else {
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
ownp = own;
}
if (!recovery) {
@@ -1079,7 +1079,8 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
APPLESTATIC int
nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
__unused struct ucred *cred, NFSPROC_T *p, int callcnt,
- struct nfsclclient *clp, struct nfscllockowner **lpp, int *dorpcp)
+ struct nfsclclient *clp, void *id, int flags,
+ struct nfscllockowner **lpp, int *dorpcp)
{
struct nfscllockowner *lp;
struct nfsclowner *owp;
@@ -1116,7 +1117,7 @@ nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
*other_lop = *nlop;
}
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
dp = NULL;
NFSLOCKCLSTATE();
if (callcnt == 0)
@@ -1188,7 +1189,8 @@ nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
* Release all lockowners marked in progess for this process and file.
*/
APPLESTATIC void
-nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
+nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p,
+ void *id, int flags)
{
struct nfsclowner *owp;
struct nfsclopen *op;
@@ -1197,7 +1199,7 @@ nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
u_int8_t own[NFSV4CL_LOCKNAMELEN];
np = VTONFS(vp);
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
@@ -1226,7 +1228,7 @@ nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
*/
APPLESTATIC int
nfscl_checkwritelocked(vnode_t vp, struct flock *fl,
- struct ucred *cred, NFSPROC_T *p)
+ struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
struct nfsclowner *owp;
struct nfscllockowner *lp;
@@ -1266,7 +1268,7 @@ nfscl_checkwritelocked(vnode_t vp, struct flock *fl,
error = nfscl_getcl(vp, cred, p, &clp);
if (error)
return (1);
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
/*
@@ -1641,7 +1643,7 @@ nfscl_cleanup(NFSPROC_T *p)
if (!nfscl_inited)
return;
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(p->td_proc, own, F_POSIX);
NFSLOCKCLSTATE();
/*
@@ -3322,7 +3324,7 @@ nfscl_checkconflict(struct nfscllockownerhead *lhp, struct nfscllock *nlop,
*/
APPLESTATIC int
nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off,
- u_int64_t len, struct flock *fl, NFSPROC_T *p)
+ u_int64_t len, struct flock *fl, NFSPROC_T *p, void *id, int flags)
{
struct nfscllock *lop, nlck;
struct nfscldeleg *dp;
@@ -3340,7 +3342,7 @@ nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off,
return (NFSERR_INVAL);
}
np = VTONFS(vp);
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
@@ -3615,7 +3617,7 @@ nfscl_relock(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp,
off = lop->nfslo_first;
len = lop->nfslo_end - lop->nfslo_first;
error = nfscl_getbytelock(vp, off, len, lop->nfslo_type, cred, p,
- clp, 1, lp->nfsl_owner, lp->nfsl_openowner, &nlp, &newone,
+ clp, 1, NULL, 0, lp->nfsl_owner, lp->nfsl_openowner, &nlp, &newone,
&donelocally);
if (error || donelocally)
return (error);
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 984724d..3e1c66d 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -2884,8 +2884,11 @@ nfs_advlock(struct vop_advlock_args *ap)
int ret, error = EOPNOTSUPP;
u_quad_t size;
- if (NFS_ISV4(vp) && (ap->a_flags & F_POSIX)) {
- cred = p->p_ucred;
+ if (NFS_ISV4(vp) && (ap->a_flags & (F_POSIX | F_FLOCK)) != 0) {
+ if ((ap->a_flags & F_POSIX) != 0)
+ cred = p->p_ucred;
+ else
+ cred = td->td_ucred;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
if (vp->v_iflag & VI_DOOMED) {
VOP_UNLOCK(vp, 0);
@@ -2898,7 +2901,8 @@ nfs_advlock(struct vop_advlock_args *ap)
* RFC3530 Sec. 9.3.2.
*/
if (ap->a_op == F_UNLCK &&
- nfscl_checkwritelocked(vp, ap->a_fl, cred, td))
+ nfscl_checkwritelocked(vp, ap->a_fl, cred, td, ap->a_id,
+ ap->a_flags))
(void) ncl_flush(vp, MNT_WAIT, cred, td, 1, 0);
/*
@@ -2907,7 +2911,7 @@ nfs_advlock(struct vop_advlock_args *ap)
*/
do {
ret = nfsrpc_advlock(vp, np->n_size, ap->a_op,
- ap->a_fl, 0, cred, td);
+ ap->a_fl, 0, cred, td, ap->a_id, ap->a_flags);
if (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) &&
ap->a_op == F_SETLK) {
VOP_UNLOCK(vp, 0);
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index fbaae89..be603eb 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -290,8 +290,11 @@ topo_probe_0x4(void)
* logical processors that belong to the same core
* as BSP thus deducing number of threads per core.
*/
- cpuid_count(0x04, 0, p);
- max_cores = ((p[0] >> 26) & 0x3f) + 1;
+ if (cpu_high >= 0x4) {
+ cpuid_count(0x04, 0, p);
+ max_cores = ((p[0] >> 26) & 0x3f) + 1;
+ } else
+ max_cores = 1;
core_id_bits = mask_width(max_logical/max_cores);
if (core_id_bits < 0)
return;
diff --git a/sys/ia64/acpica/acpi_machdep.c b/sys/ia64/acpica/acpi_machdep.c
index b7b612f..1466cfe 100644
--- a/sys/ia64/acpica/acpi_machdep.c
+++ b/sys/ia64/acpica/acpi_machdep.c
@@ -56,7 +56,14 @@ acpi_machdep_quirks(int *quirks)
void
acpi_cpu_c1()
{
+#ifdef INVARIANTS
+ register_t ie;
+
+ ie = intr_disable();
+ KASSERT(ie == 0, ("%s called with interrupts enabled\n", __func__));
+#endif
ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
+ ia64_enable_intr();
}
void *
diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c
index 7252865..fc7df7a 100644
--- a/sys/ia64/ia64/machdep.c
+++ b/sys/ia64/ia64/machdep.c
@@ -411,12 +411,34 @@ cpu_halt()
void
cpu_idle(int busy)
{
- struct ia64_pal_result res;
+ register_t ie;
- if (cpu_idle_hook != NULL)
+#if 0
+ if (!busy) {
+ critical_enter();
+ cpu_idleclock();
+ }
+#endif
+
+ ie = intr_disable();
+ KASSERT(ie != 0, ("%s called with interrupts disabled\n", __func__));
+
+ if (sched_runnable())
+ ia64_enable_intr();
+ else if (cpu_idle_hook != NULL) {
(*cpu_idle_hook)();
- else
- res = ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
+ /* The hook must enable interrupts! */
+ } else {
+ ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
+ ia64_enable_intr();
+ }
+
+#if 0
+ if (!busy) {
+ cpu_activeclock();
+ critical_exit();
+ }
+#endif
}
int
@@ -644,9 +666,12 @@ calculate_frequencies(void)
{
struct ia64_sal_result sal;
struct ia64_pal_result pal;
+ register_t ie;
+ ie = intr_disable();
sal = ia64_sal_entry(SAL_FREQ_BASE, 0, 0, 0, 0, 0, 0, 0);
pal = ia64_call_pal_static(PAL_FREQ_RATIOS, 0, 0, 0);
+ intr_restore(ie);
if (sal.sal_status == 0 && pal.pal_status == 0) {
if (bootverbose) {
diff --git a/sys/ia64/ia64/pal.S b/sys/ia64/ia64/pal.S
index 2f0d0da..2e3f4cd 100644
--- a/sys/ia64/ia64/pal.S
+++ b/sys/ia64/ia64/pal.S
@@ -38,43 +38,40 @@ ia64_pal_entry: .quad 0
* u_int64_t arg1, u_int64_t arg2, u_int64_t arg3)
*/
ENTRY(ia64_call_pal_static, 4)
-
- .regstk 4,5,0,0
+
+ .regstk 4,4,0,0
palret = loc0
entry = loc1
rpsave = loc2
pfssave = loc3
-psrsave = loc4
- alloc pfssave=ar.pfs,4,5,0,0
+ alloc pfssave=ar.pfs,4,4,0,0
;;
mov rpsave=rp
-
movl entry=@gprel(ia64_pal_entry)
+
1: mov palret=ip // for return address
;;
add entry=entry,gp
- mov psrsave=psr
+ add palret=2f-1b,palret // calculate return address
mov r28=in0 // procedure number
- ;;
- ld8 entry=[entry] // read entry point
mov r29=in1 // copy arguments
mov r30=in2
mov r31=in3
;;
- mov b6=entry
- add palret=2f-1b,palret // calculate return address
- ;;
+ ld8 entry=[entry] // read entry point
mov b0=palret
- rsm psr.i // disable interrupts
+ ;;
+ mov b6=entry
;;
br.cond.sptk b6 // call into firmware
-2: mov psr.l=psrsave
+ ;;
+2:
mov rp=rpsave
mov ar.pfs=pfssave
;;
- srlz.d
br.ret.sptk rp
+ ;;
END(ia64_call_pal_static)
/*
diff --git a/sys/kern/subr_rman.c b/sys/kern/subr_rman.c
index 3014b19..abd72c0 100644
--- a/sys/kern/subr_rman.c
+++ b/sys/kern/subr_rman.c
@@ -839,6 +839,7 @@ int_rman_release_resource(struct rman *rm, struct resource_i *r)
* without freeing anything.
*/
r->r_flags &= ~RF_ALLOCATED;
+ r->r_dev = NULL;
return 0;
}
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h
index 5faae7c..c9da86a 100644
--- a/sys/netinet/icmp6.h
+++ b/sys/netinet/icmp6.h
@@ -297,8 +297,9 @@ struct nd_opt_hdr { /* Neighbor discovery option header */
#define ND_OPT_PREFIX_INFORMATION 3
#define ND_OPT_REDIRECTED_HEADER 4
#define ND_OPT_MTU 5
-
-#define ND_OPT_ROUTE_INFO 200 /* draft-ietf-ipngwg-router-preference, not officially assigned yet */
+#define ND_OPT_ROUTE_INFO 24 /* RFC 4191 */
+#define ND_OPT_RDNSS 25 /* RFC 6016 */
+#define ND_OPT_DNSSL 31 /* RFC 6016 */
struct nd_opt_prefix_info { /* prefix information */
u_int8_t nd_opt_pi_type;
@@ -338,6 +339,22 @@ struct nd_opt_route_info { /* route info */
/* prefix follows */
} __packed;
+struct nd_opt_rdnss { /* RDNSS option (RFC 6106) */
+ u_int8_t nd_opt_rdnss_type;
+ u_int8_t nd_opt_rdnss_len;
+ u_int16_t nd_opt_rdnss_reserved;
+ u_int32_t nd_opt_rdnss_lifetime;
+ /* followed by list of recursive DNS servers */
+} __packed;
+
+struct nd_opt_dnssl { /* DNSSL option (RFC 6106) */
+ u_int8_t nd_opt_dnssl_type;
+ u_int8_t nd_opt_dnssl_len;
+ u_int16_t nd_opt_dnssl_reserved;
+ u_int32_t nd_opt_dnssl_lifetime;
+ /* followed by list of DNS search domains */
+} __packed;
+
/*
* icmp6 namelookup
*/
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 4aa998f..4eb309a 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ipsec.h"
#include "opt_inet.h"
#include "opt_inet6.h"
+#include "opt_pcbgroup.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -212,7 +213,7 @@ void
in_pcbinfo_init(struct inpcbinfo *pcbinfo, const char *name,
struct inpcbhead *listhead, int hash_nelements, int porthash_nelements,
char *inpcbzone_name, uma_init inpcbzone_init, uma_fini inpcbzone_fini,
- uint32_t inpcbzone_flags)
+ uint32_t inpcbzone_flags, u_int hashfields)
{
INP_INFO_LOCK_INIT(pcbinfo, name);
@@ -227,6 +228,9 @@ in_pcbinfo_init(struct inpcbinfo *pcbinfo, const char *name,
&pcbinfo->ipi_hashmask);
pcbinfo->ipi_porthashbase = hashinit(porthash_nelements, M_PCB,
&pcbinfo->ipi_porthashmask);
+#ifdef PCBGROUP
+ in_pcbgroup_init(pcbinfo, hashfields, hash_nelements);
+#endif
pcbinfo->ipi_zone = uma_zcreate(inpcbzone_name, sizeof(struct inpcb),
NULL, NULL, inpcbzone_init, inpcbzone_fini, UMA_ALIGN_PTR,
inpcbzone_flags);
@@ -246,6 +250,9 @@ in_pcbinfo_destroy(struct inpcbinfo *pcbinfo)
hashdestroy(pcbinfo->ipi_hashbase, M_PCB, pcbinfo->ipi_hashmask);
hashdestroy(pcbinfo->ipi_porthashbase, M_PCB,
pcbinfo->ipi_porthashmask);
+#ifdef PCBGROUP
+ in_pcbgroup_destroy(pcbinfo);
+#endif
uma_zdestroy(pcbinfo->ipi_zone);
INP_HASH_LOCK_DESTROY(pcbinfo);
INP_INFO_LOCK_DESTROY(pcbinfo);
@@ -1053,7 +1060,8 @@ in_pcbdetach(struct inpcb *inp)
* in_pcbref() bumps the reference count on an inpcb in order to maintain
* stability of an inpcb pointer despite the inpcb lock being released. This
* is used in TCP when the inpcbinfo lock needs to be acquired or upgraded,
- * but where the inpcb lock is already held.
+ * but where the inpcb lock may already held, or when acquiring a reference
+ * via a pcbgroup.
*
* in_pcbref() should be used only to provide brief memory stability, and
* must always be followed by a call to INP_WLOCK() and in_pcbrele() to
@@ -1223,6 +1231,9 @@ in_pcbdrop(struct inpcb *inp)
}
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
inp->inp_flags &= ~INP_INHASHLIST;
+#ifdef PCBGROUP
+ in_pcbgroup_remove(inp);
+#endif
}
}
@@ -1472,6 +1483,148 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
}
#undef INP_LOOKUP_MAPPED_PCB_COST
+#ifdef PCBGROUP
+/*
+ * Lookup PCB in hash list, using pcbgroup tables.
+ */
+static struct inpcb *
+in_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
+ struct in_addr faddr, u_int fport_arg, struct in_addr laddr,
+ u_int lport_arg, int lookupflags, struct ifnet *ifp)
+{
+ struct inpcbhead *head;
+ struct inpcb *inp, *tmpinp;
+ u_short fport = fport_arg, lport = lport_arg;
+
+ /*
+ * First look for an exact match.
+ */
+ tmpinp = NULL;
+ INP_GROUP_LOCK(pcbgroup);
+ head = &pcbgroup->ipg_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport,
+ pcbgroup->ipg_hashmask)];
+ LIST_FOREACH(inp, head, inp_pcbgrouphash) {
+#ifdef INET6
+ /* XXX inp locking */
+ if ((inp->inp_vflag & INP_IPV4) == 0)
+ continue;
+#endif
+ if (inp->inp_faddr.s_addr == faddr.s_addr &&
+ inp->inp_laddr.s_addr == laddr.s_addr &&
+ inp->inp_fport == fport &&
+ inp->inp_lport == lport) {
+ /*
+ * XXX We should be able to directly return
+ * the inp here, without any checks.
+ * Well unless both bound with SO_REUSEPORT?
+ */
+ if (prison_flag(inp->inp_cred, PR_IP4))
+ goto found;
+ if (tmpinp == NULL)
+ tmpinp = inp;
+ }
+ }
+ if (tmpinp != NULL) {
+ inp = tmpinp;
+ goto found;
+ }
+
+ /*
+ * Then look for a wildcard match, if requested.
+ */
+ if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {
+ struct inpcb *local_wild = NULL, *local_exact = NULL;
+#ifdef INET6
+ struct inpcb *local_wild_mapped = NULL;
+#endif
+ struct inpcb *jail_wild = NULL;
+ struct inpcbhead *head;
+ int injail;
+
+ /*
+ * Order of socket selection - we always prefer jails.
+ * 1. jailed, non-wild.
+ * 2. jailed, wild.
+ * 3. non-jailed, non-wild.
+ * 4. non-jailed, wild.
+ */
+ head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, lport,
+ 0, pcbinfo->ipi_wildmask)];
+ LIST_FOREACH(inp, head, inp_pcbgroup_wild) {
+#ifdef INET6
+ /* XXX inp locking */
+ if ((inp->inp_vflag & INP_IPV4) == 0)
+ continue;
+#endif
+ if (inp->inp_faddr.s_addr != INADDR_ANY ||
+ inp->inp_lport != lport)
+ continue;
+
+ /* XXX inp locking */
+ if (ifp && ifp->if_type == IFT_FAITH &&
+ (inp->inp_flags & INP_FAITH) == 0)
+ continue;
+
+ injail = prison_flag(inp->inp_cred, PR_IP4);
+ if (injail) {
+ if (prison_check_ip4(inp->inp_cred,
+ &laddr) != 0)
+ continue;
+ } else {
+ if (local_exact != NULL)
+ continue;
+ }
+
+ if (inp->inp_laddr.s_addr == laddr.s_addr) {
+ if (injail)
+ goto found;
+ else
+ local_exact = inp;
+ } else if (inp->inp_laddr.s_addr == INADDR_ANY) {
+#ifdef INET6
+ /* XXX inp locking, NULL check */
+ if (inp->inp_vflag & INP_IPV6PROTO)
+ local_wild_mapped = inp;
+ else
+#endif /* INET6 */
+ if (injail)
+ jail_wild = inp;
+ else
+ local_wild = inp;
+ }
+ } /* LIST_FOREACH */
+ inp = jail_wild;
+ if (inp == NULL)
+ inp = local_exact;
+ if (inp == NULL)
+ inp = local_wild;
+#ifdef INET6
+ if (inp == NULL)
+ inp = local_wild_mapped;
+#endif /* defined(INET6) */
+ if (inp != NULL)
+ goto found;
+ } /* if (lookupflags & INPLOOKUP_WILDCARD) */
+ INP_GROUP_UNLOCK(pcbgroup);
+ return (NULL);
+
+found:
+ in_pcbref(inp);
+ INP_GROUP_UNLOCK(pcbgroup);
+ if (lookupflags & INPLOOKUP_WLOCKPCB) {
+ INP_WLOCK(inp);
+ if (in_pcbrele_wlocked(inp))
+ return (NULL);
+ } else if (lookupflags & INPLOOKUP_RLOCKPCB) {
+ INP_RLOCK(inp);
+ if (in_pcbrele_rlocked(inp))
+ return (NULL);
+ } else
+ panic("%s: locking bug", __func__);
+ return (inp);
+}
+#endif /* PCBGROUP */
+
/*
* Lookup PCB in hash list, using pcbinfo tables. This variation assumes
* that the caller has locked the hash list, and will not perform any further
@@ -1636,17 +1789,30 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
/*
* Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf
* from which a pre-calculated hash value may be extracted.
+ *
+ * Possibly more of this logic should be in in_pcbgroup.c.
*/
struct inpcb *
in_pcblookup(struct inpcbinfo *pcbinfo, struct in_addr faddr, u_int fport,
struct in_addr laddr, u_int lport, int lookupflags, struct ifnet *ifp)
{
+#if defined(PCBGROUP)
+ struct inpcbgroup *pcbgroup;
+#endif
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
+#if defined(PCBGROUP)
+ if (in_pcbgroup_enabled(pcbinfo)) {
+ pcbgroup = in_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
+ fport);
+ return (in_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
+ laddr, lport, lookupflags, ifp));
+ }
+#endif
return (in_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
lookupflags, ifp));
}
@@ -1656,12 +1822,28 @@ in_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in_addr faddr,
u_int fport, struct in_addr laddr, u_int lport, int lookupflags,
struct ifnet *ifp, struct mbuf *m)
{
+#ifdef PCBGROUP
+ struct inpcbgroup *pcbgroup;
+#endif
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
+#ifdef PCBGROUP
+ if (in_pcbgroup_enabled(pcbinfo)) {
+ pcbgroup = in_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
+ m->m_pkthdr.flowid);
+ if (pcbgroup != NULL)
+ return (in_pcblookup_group(pcbinfo, pcbgroup, faddr,
+ fport, laddr, lport, lookupflags, ifp));
+ pcbgroup = in_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
+ fport);
+ return (in_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
+ laddr, lport, lookupflags, ifp));
+ }
+#endif
return (in_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
lookupflags, ifp));
}
@@ -1670,8 +1852,8 @@ in_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in_addr faddr,
/*
* Insert PCB onto various hash lists.
*/
-int
-in_pcbinshash(struct inpcb *inp)
+static int
+in_pcbinshash_internal(struct inpcb *inp, int do_pcbgroup_update)
{
struct inpcbhead *pcbhash;
struct inpcbporthead *pcbporthash;
@@ -1721,10 +1903,39 @@ in_pcbinshash(struct inpcb *inp)
LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
inp->inp_flags |= INP_INHASHLIST;
+#ifdef PCBGROUP
+ if (do_pcbgroup_update)
+ in_pcbgroup_update(inp);
+#endif
return (0);
}
/*
+ * For now, there are two public interfaces to insert an inpcb into the hash
+ * lists -- one that does update pcbgroups, and one that doesn't. The latter
+ * is used only in the TCP syncache, where in_pcbinshash is called before the
+ * full 4-tuple is set for the inpcb, and we don't want to install in the
+ * pcbgroup until later.
+ *
+ * XXXRW: This seems like a misfeature. in_pcbinshash should always update
+ * connection groups, and partially initialised inpcbs should not be exposed
+ * to either reservation hash tables or pcbgroups.
+ */
+int
+in_pcbinshash(struct inpcb *inp)
+{
+
+ return (in_pcbinshash_internal(inp, 1));
+}
+
+int
+in_pcbinshash_nopcbgroup(struct inpcb *inp)
+{
+
+ return (in_pcbinshash_internal(inp, 0));
+}
+
+/*
* Move PCB to the proper hash bucket when { faddr, fport } have been
* changed. NOTE: This does not handle the case of the lport changing (the
* hashed port list would have to be updated as well), so the lport must
@@ -1755,6 +1966,13 @@ in_pcbrehash_mbuf(struct inpcb *inp, struct mbuf *m)
LIST_REMOVE(inp, inp_hash);
LIST_INSERT_HEAD(head, inp, inp_hash);
+
+#ifdef PCBGROUP
+ if (m != NULL)
+ in_pcbgroup_update_mbuf(inp, m);
+ else
+ in_pcbgroup_update(inp);
+#endif
}
void
@@ -1791,6 +2009,9 @@ in_pcbremlists(struct inpcb *inp)
}
LIST_REMOVE(inp, inp_list);
pcbinfo->ipi_count--;
+#ifdef PCBGROUP
+ in_pcbgroup_remove(inp);
+#endif
}
/*
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 809bc05..a8524be 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -141,6 +141,7 @@ struct icmp6_filter;
*
* Key:
* (c) - Constant after initialization
+ * (g) - Protected by the pcbgroup lock
* (i) - Protected by the inpcb lock
* (p) - Protected by the pcbinfo lock for the inpcb
* (s) - Protected by another subsystem's locks
@@ -160,9 +161,12 @@ struct icmp6_filter;
*/
struct inpcb {
LIST_ENTRY(inpcb) inp_hash; /* (i/p) hash list */
+ LIST_ENTRY(inpcb) inp_pcbgrouphash; /* (g/i) hash list */
LIST_ENTRY(inpcb) inp_list; /* (i/p) list for all PCBs for proto */
void *inp_ppcb; /* (i) pointer to per-protocol pcb */
struct inpcbinfo *inp_pcbinfo; /* (c) PCB list info */
+ struct inpcbgroup *inp_pcbgroup; /* (g/i) PCB group list */
+ LIST_ENTRY(inpcb) inp_pcbgroup_wild; /* (g/i/p) group wildcard entry */
struct socket *inp_socket; /* (i) back pointer to socket */
struct ucred *inp_cred; /* (c) cache of socket cred */
u_int32_t inp_flow; /* (i) IPv6 flow information */
@@ -272,13 +276,14 @@ struct inpcbport {
* the former covering mutable global fields (such as the global pcb list),
* and the latter covering the hashed lookup tables. The lock order is:
*
- * ipi_lock (before) inpcb locks (before) ipi_hash_lock
+ * ipi_lock (before) inpcb locks (before) {ipi_hash_lock, pcbgroup locks}
*
* Locking key:
*
* (c) Constant or nearly constant after initialisation
* (g) Locked by ipi_lock
- * (h) Read using either ipi_hash_lock or inpcb lock; write requires both.
+ * (h) Read using either ipi_hash_lock or inpcb lock; write requires both
+ * (p) Protected by one or more pcbgroup locks
* (x) Synchronisation properties poorly defined
*/
struct inpcbinfo {
@@ -312,7 +317,16 @@ struct inpcbinfo {
struct uma_zone *ipi_zone; /* (c) */
/*
- * Global lock protecting hash lookup tables.
+ * Connection groups associated with this protocol. These fields are
+ * constant, but pcbgroup structures themselves are protected by
+ * per-pcbgroup locks.
+ */
+ struct inpcbgroup *ipi_pcbgroups; /* (c) */
+ u_int ipi_npcbgroups; /* (c) */
+ u_int ipi_hashfields; /* (c) */
+
+ /*
+ * Global lock protecting non-pcbgroup hash lookup tables.
*/
struct rwlock ipi_hash_lock;
@@ -330,6 +344,14 @@ struct inpcbinfo {
u_long ipi_porthashmask; /* (h) */
/*
+ * List of wildcard inpcbs for use with pcbgroups. In the past, was
+ * per-pcbgroup but is now global. All pcbgroup locks must be held
+ * to modify the list, so any is sufficient to read it.
+ */
+ struct inpcbhead *ipi_wildbase; /* (p) */
+ u_long ipi_wildmask; /* (p) */
+
+ /*
* Pointer to network stack instance
*/
struct vnet *ipi_vnet; /* (c) */
@@ -340,6 +362,31 @@ struct inpcbinfo {
void *ipi_pspare[2];
};
+/*
+ * Connection groups hold sets of connections that have similar CPU/thread
+ * affinity. Each connection belongs to exactly one connection group.
+ */
+struct inpcbgroup {
+ /*
+ * Per-connection group hash of inpcbs, hashed by local and foreign
+ * addresses and port numbers.
+ */
+ struct inpcbhead *ipg_hashbase; /* (c) */
+ u_long ipg_hashmask; /* (c) */
+
+ /*
+ * Notional affinity of this pcbgroup.
+ */
+ u_int ipg_cpu; /* (p) */
+
+ /*
+ * Per-connection group lock, not to be confused with ipi_lock.
+ * Protects the hash table hung off the group, but also the global
+ * wildcard list in inpcbinfo.
+ */
+ struct mtx ipg_lock;
+} __aligned(CACHE_LINE_SIZE);
+
#define INP_LOCK_INIT(inp, d, t) \
rw_init_flags(&(inp)->inp_lock, (t), RW_RECURSE | RW_DUPOK)
#define INP_LOCK_DESTROY(inp) rw_destroy(&(inp)->inp_lock)
@@ -423,6 +470,14 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
#define INP_HASH_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \
RA_WLOCKED)
+#define INP_GROUP_LOCK_INIT(ipg, d) mtx_init(&(ipg)->ipg_lock, (d), NULL, \
+ MTX_DEF | MTX_DUPOK)
+#define INP_GROUP_LOCK_DESTROY(ipg) mtx_destroy(&(ipg)->ipg_lock)
+
+#define INP_GROUP_LOCK(ipg) mtx_lock(&(ipg)->ipg_lock)
+#define INP_GROUP_LOCK_ASSERT(ipg) mtx_assert(&(ipg)->ipg_lock, MA_OWNED)
+#define INP_GROUP_UNLOCK(ipg) mtx_unlock(&(ipg)->ipg_lock)
+
#define INP_PCBHASH(faddr, lport, fport, mask) \
(((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask))
#define INP_PCBPORTHASH(lport, mask) \
@@ -482,6 +537,7 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
*/
#define INP_LLE_VALID 0x00000001 /* cached lle is valid */
#define INP_RT_VALID 0x00000002 /* cached rtentry is valid */
+#define INP_PCBGROUPWILD 0x00000004 /* in pcbgroup wildcard list */
/*
* Flags passed to in_pcblookup*() functions.
@@ -500,6 +556,13 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
#define INP_CHECK_SOCKAF(so, af) (INP_SOCKAF(so) == af)
+/*
+ * Constants for pcbinfo.ipi_hashfields.
+ */
+#define IPI_HASHFIELDS_NONE 0
+#define IPI_HASHFIELDS_2TUPLE 1
+#define IPI_HASHFIELDS_4TUPLE 2
+
#ifdef _KERNEL
VNET_DECLARE(int, ipport_reservedhigh);
VNET_DECLARE(int, ipport_reservedlow);
@@ -531,7 +594,21 @@ VNET_DECLARE(int, ipport_tcpallocs);
void in_pcbinfo_destroy(struct inpcbinfo *);
void in_pcbinfo_init(struct inpcbinfo *, const char *, struct inpcbhead *,
- int, int, char *, uma_init, uma_fini, uint32_t);
+ int, int, char *, uma_init, uma_fini, uint32_t, u_int);
+
+struct inpcbgroup *
+ in_pcbgroup_byhash(struct inpcbinfo *, u_int, uint32_t);
+struct inpcbgroup *
+ in_pcbgroup_byinpcb(struct inpcb *);
+struct inpcbgroup *
+ in_pcbgroup_bytuple(struct inpcbinfo *, struct in_addr, u_short,
+ struct in_addr, u_short);
+void in_pcbgroup_destroy(struct inpcbinfo *);
+int in_pcbgroup_enabled(struct inpcbinfo *);
+void in_pcbgroup_init(struct inpcbinfo *, u_int, int);
+void in_pcbgroup_remove(struct inpcb *);
+void in_pcbgroup_update(struct inpcb *);
+void in_pcbgroup_update_mbuf(struct inpcb *, struct mbuf *);
void in_pcbpurgeif0(struct inpcbinfo *, struct ifnet *);
int in_pcballoc(struct socket *, struct inpcbinfo *);
@@ -551,6 +628,7 @@ void in_pcbdisconnect(struct inpcb *);
void in_pcbdrop(struct inpcb *);
void in_pcbfree(struct inpcb *);
int in_pcbinshash(struct inpcb *);
+int in_pcbinshash_nopcbgroup(struct inpcb *);
struct inpcb *
in_pcblookup_local(struct inpcbinfo *,
struct in_addr, u_short, int, struct ucred *);
diff --git a/sys/netinet/in_pcbgroup.c b/sys/netinet/in_pcbgroup.c
new file mode 100644
index 0000000..c9f5c70
--- /dev/null
+++ b/sys/netinet/in_pcbgroup.c
@@ -0,0 +1,457 @@
+/*-
+ * Copyright (c) 2010-2011 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
+#include <sys/socketvar.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#ifdef INET6
+#include <netinet6/in6_pcb.h>
+#endif /* INET6 */
+
+/*
+ * pcbgroups, or "connection groups" are based on Willman, Rixner, and Cox's
+ * 2006 USENIX paper, "An Evaluation of Network Stack Parallelization
+ * Strategies in Modern Operating Systems". This implementation differs
+ * significantly from that described in the paper, in that it attempts to
+ * introduce not just notions of affinity for connections and distribute work
+ * so as to reduce lock contention, but also align those notions with
+ * hardware work distribution strategies such as RSS. In this construction,
+ * connection groups supplement, rather than replace, existing reservation
+ * tables for protocol 4-tuples, offering CPU-affine lookup tables with
+ * minimal cache line migration and lock contention during steady state
+ * operation.
+ *
+ * Internet protocols, such as UDP and TCP, register to use connection groups
+ * by providing an ipi_hashfields value other than IPI_HASHFIELDS_NONE; this
+ * indicates to the connection group code whether a 2-tuple or 4-tuple is
+ * used as an argument to hashes that assign a connection to a particular
+ * group. This must be aligned with any hardware offloaded distribution
+ * model, such as RSS or similar approaches taken in embedded network boards.
+ * Wildcard sockets require special handling, as in Willman 2006, and are
+ * shared between connection groups -- while being protected by group-local
+ * locks. This means that connection establishment and teardown can be
+ * signficantly more expensive than without connection groups, but that
+ * steady-state processing can be significantly faster.
+ *
+ * Most of the implementation of connection groups is in this file; however,
+ * connection group lookup is implemented in in_pcb.c alongside reservation
+ * table lookups -- see in_pcblookup_group().
+ *
+ * TODO:
+ *
+ * Implement dynamic rebalancing of buckets with connection groups; when
+ * load is unevenly distributed, search for more optimal balancing on
+ * demand. This might require scaling up the number of connection groups
+ * by <<1.
+ *
+ * Provide an IP 2-tuple or 4-tuple netisr m2cpu handler based on connection
+ * groups for ip_input and ip6_input, allowing non-offloaded work
+ * distribution.
+ *
+ * Expose effective CPU affinity of connections to userspace using socket
+ * options.
+ *
+ * Investigate per-connection affinity overrides based on socket options; an
+ * option could be set, certainly resulting in work being distributed
+ * differently in software, and possibly propagated to supporting hardware
+ * with TCAMs or hardware hash tables. This might require connections to
+ * exist in more than one connection group at a time.
+ *
+ * Hook netisr thread reconfiguration events, and propagate those to RSS so
+ * that rebalancing can occur when the thread pool grows or shrinks.
+ *
+ * Expose per-pcbgroup statistics to userspace monitoring tools such as
+ * netstat, in order to allow better debugging and profiling.
+ */
+
+void
+in_pcbgroup_init(struct inpcbinfo *pcbinfo, u_int hashfields,
+ int hash_nelements)
+{
+ struct inpcbgroup *pcbgroup;
+ u_int numpcbgroups, pgn;
+
+ /*
+ * Only enable connection groups for a protocol if it has been
+ * specifically requested.
+ */
+ if (hashfields == IPI_HASHFIELDS_NONE)
+ return;
+
+ /*
+ * Connection groups are about multi-processor load distribution,
+ * lock contention, and connection CPU affinity. As such, no point
+ * in turning them on for a uniprocessor machine, it only wastes
+ * memory.
+ */
+ if (mp_ncpus == 1)
+ return;
+
+ /*
+ * Use one group per CPU for now. If we decide to do dynamic
+ * rebalancing a la RSS, we'll need to shift left by at least 1.
+ */
+ numpcbgroups = mp_ncpus;
+
+ pcbinfo->ipi_hashfields = hashfields;
+ pcbinfo->ipi_pcbgroups = malloc(numpcbgroups *
+ sizeof(*pcbinfo->ipi_pcbgroups), M_PCB, M_WAITOK | M_ZERO);
+ pcbinfo->ipi_npcbgroups = numpcbgroups;
+ pcbinfo->ipi_wildbase = hashinit(hash_nelements, M_PCB,
+ &pcbinfo->ipi_wildmask);
+ for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++) {
+ pcbgroup = &pcbinfo->ipi_pcbgroups[pgn];
+ pcbgroup->ipg_hashbase = hashinit(hash_nelements, M_PCB,
+ &pcbgroup->ipg_hashmask);
+ INP_GROUP_LOCK_INIT(pcbgroup, "pcbgroup");
+
+ /*
+ * Initialise notional affinity of the pcbgroup -- for RSS,
+ * we want the same notion of affinity as NICs to be used.
+ * Just round robin for the time being.
+ */
+ pcbgroup->ipg_cpu = (pgn % mp_ncpus);
+ }
+}
+
+void
+in_pcbgroup_destroy(struct inpcbinfo *pcbinfo)
+{
+ struct inpcbgroup *pcbgroup;
+ u_int pgn;
+
+ if (pcbinfo->ipi_npcbgroups == 0)
+ return;
+
+ for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++) {
+ pcbgroup = &pcbinfo->ipi_pcbgroups[pgn];
+ KASSERT(LIST_EMPTY(pcbinfo->ipi_listhead),
+ ("in_pcbinfo_destroy: listhead not empty"));
+ INP_GROUP_LOCK_DESTROY(pcbgroup);
+ hashdestroy(pcbgroup->ipg_hashbase, M_PCB,
+ pcbgroup->ipg_hashmask);
+ }
+ hashdestroy(pcbinfo->ipi_wildbase, M_PCB, pcbinfo->ipi_wildmask);
+ free(pcbinfo->ipi_pcbgroups, M_PCB);
+ pcbinfo->ipi_pcbgroups = NULL;
+ pcbinfo->ipi_npcbgroups = 0;
+ pcbinfo->ipi_hashfields = 0;
+}
+
+/*
+ * Given a hash of whatever the covered tuple might be, return a pcbgroup
+ * index.
+ */
+static __inline u_int
+in_pcbgroup_getbucket(struct inpcbinfo *pcbinfo, uint32_t hash)
+{
+
+ return (hash % pcbinfo->ipi_npcbgroups);
+}
+
+/*
+ * Map a (hashtype, hash) tuple into a connection group, or NULL if the hash
+ * information is insufficient to identify the pcbgroup.
+ */
+struct inpcbgroup *
+in_pcbgroup_byhash(struct inpcbinfo *pcbinfo, u_int hashtype, uint32_t hash)
+{
+
+ return (NULL);
+}
+
+static struct inpcbgroup *
+in_pcbgroup_bymbuf(struct inpcbinfo *pcbinfo, struct mbuf *m)
+{
+
+ return (in_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
+ m->m_pkthdr.flowid));
+}
+
+struct inpcbgroup *
+in_pcbgroup_bytuple(struct inpcbinfo *pcbinfo, struct in_addr laddr,
+ u_short lport, struct in_addr faddr, u_short fport)
+{
+ uint32_t hash;
+
+ switch (pcbinfo->ipi_hashfields) {
+ case IPI_HASHFIELDS_4TUPLE:
+ hash = faddr.s_addr ^ fport;
+ break;
+
+ case IPI_HASHFIELDS_2TUPLE:
+ hash = faddr.s_addr ^ laddr.s_addr;
+ break;
+
+ default:
+ hash = 0;
+ }
+ return (&pcbinfo->ipi_pcbgroups[in_pcbgroup_getbucket(pcbinfo,
+ hash)]);
+}
+
+struct inpcbgroup *
+in_pcbgroup_byinpcb(struct inpcb *inp)
+{
+
+ return (in_pcbgroup_bytuple(inp->inp_pcbinfo, inp->inp_laddr,
+ inp->inp_lport, inp->inp_faddr, inp->inp_fport));
+}
+
+static void
+in_pcbwild_add(struct inpcb *inp)
+{
+ struct inpcbinfo *pcbinfo;
+ struct inpcbhead *head;
+ u_int pgn;
+
+ INP_WLOCK_ASSERT(inp);
+ KASSERT(!(inp->inp_flags2 & INP_PCBGROUPWILD),
+ ("%s: is wild",__func__));
+
+ pcbinfo = inp->inp_pcbinfo;
+ for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++)
+ INP_GROUP_LOCK(&pcbinfo->ipi_pcbgroups[pgn]);
+ head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, inp->inp_lport,
+ 0, pcbinfo->ipi_wildmask)];
+ LIST_INSERT_HEAD(head, inp, inp_pcbgroup_wild);
+ inp->inp_flags2 |= INP_PCBGROUPWILD;
+ for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++)
+ INP_GROUP_UNLOCK(&pcbinfo->ipi_pcbgroups[pgn]);
+}
+
+static void
+in_pcbwild_remove(struct inpcb *inp)
+{
+ struct inpcbinfo *pcbinfo;
+ u_int pgn;
+
+ INP_WLOCK_ASSERT(inp);
+ KASSERT((inp->inp_flags2 & INP_PCBGROUPWILD),
+ ("%s: not wild", __func__));
+
+ pcbinfo = inp->inp_pcbinfo;
+ for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++)
+ INP_GROUP_LOCK(&pcbinfo->ipi_pcbgroups[pgn]);
+ LIST_REMOVE(inp, inp_pcbgroup_wild);
+ for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++)
+ INP_GROUP_UNLOCK(&pcbinfo->ipi_pcbgroups[pgn]);
+ inp->inp_flags2 &= ~INP_PCBGROUPWILD;
+}
+
+static __inline int
+in_pcbwild_needed(struct inpcb *inp)
+{
+
+#ifdef INET6
+ if (inp->inp_vflag & INP_IPV6)
+ return (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr));
+ else
+#endif
+ return (inp->inp_faddr.s_addr == htonl(INADDR_ANY));
+}
+
+static void
+in_pcbwild_update_internal(struct inpcb *inp)
+{
+ int wildcard_needed;
+
+ wildcard_needed = in_pcbwild_needed(inp);
+ if (wildcard_needed && !(inp->inp_flags2 & INP_PCBGROUPWILD))
+ in_pcbwild_add(inp);
+ else if (!wildcard_needed && (inp->inp_flags2 & INP_PCBGROUPWILD))
+ in_pcbwild_remove(inp);
+}
+
+/*
+ * Update the pcbgroup of an inpcb, which might include removing an old
+ * pcbgroup reference and/or adding a new one. Wildcard processing is not
+ * performed here, although ideally we'll never install a pcbgroup for a
+ * wildcard inpcb (asserted below).
+ */
+static void
+in_pcbgroup_update_internal(struct inpcbinfo *pcbinfo,
+ struct inpcbgroup *newpcbgroup, struct inpcb *inp)
+{
+ struct inpcbgroup *oldpcbgroup;
+ struct inpcbhead *pcbhash;
+ uint32_t hashkey_faddr;
+
+ INP_WLOCK_ASSERT(inp);
+
+ oldpcbgroup = inp->inp_pcbgroup;
+ if (oldpcbgroup != NULL && oldpcbgroup != newpcbgroup) {
+ INP_GROUP_LOCK(oldpcbgroup);
+ LIST_REMOVE(inp, inp_pcbgrouphash);
+ inp->inp_pcbgroup = NULL;
+ INP_GROUP_UNLOCK(oldpcbgroup);
+ }
+ if (newpcbgroup != NULL && oldpcbgroup != newpcbgroup) {
+#ifdef INET6
+ if (inp->inp_vflag & INP_IPV6)
+ hashkey_faddr = inp->in6p_faddr.s6_addr32[3]; /* XXX */
+ else
+#endif
+ hashkey_faddr = inp->inp_faddr.s_addr;
+ INP_GROUP_LOCK(newpcbgroup);
+ pcbhash = &newpcbgroup->ipg_hashbase[
+ INP_PCBHASH(hashkey_faddr, inp->inp_lport, inp->inp_fport,
+ newpcbgroup->ipg_hashmask)];
+ LIST_INSERT_HEAD(pcbhash, inp, inp_pcbgrouphash);
+ inp->inp_pcbgroup = newpcbgroup;
+ INP_GROUP_UNLOCK(newpcbgroup);
+ }
+
+ KASSERT(!(newpcbgroup != NULL && in_pcbwild_needed(inp)),
+ ("%s: pcbgroup and wildcard!", __func__));
+}
+
+/*
+ * Two update paths: one in which the 4-tuple on an inpcb has been updated
+ * and therefore connection groups may need to change (or a wildcard entry
+ * may needed to be installed), and another in which the 4-tuple has been
+ * set as a result of a packet received, in which case we may be able to use
+ * the hash on the mbuf to avoid doing a software hash calculation for RSS.
+ *
+ * In each case: first, let the wildcard code have a go at placing it as a
+ * wildcard socket. If it was a wildcard, or if the connection has been
+ * dropped, then no pcbgroup is required (so potentially clear it);
+ * otherwise, calculate and update the pcbgroup for the inpcb.
+ */
+void
+in_pcbgroup_update(struct inpcb *inp)
+{
+ struct inpcbinfo *pcbinfo;
+ struct inpcbgroup *newpcbgroup;
+
+ INP_WLOCK_ASSERT(inp);
+
+ pcbinfo = inp->inp_pcbinfo;
+ if (!in_pcbgroup_enabled(pcbinfo))
+ return;
+
+ in_pcbwild_update_internal(inp);
+ if (!(inp->inp_flags2 & INP_PCBGROUPWILD) &&
+ !(inp->inp_flags & INP_DROPPED)) {
+#ifdef INET6
+ if (inp->inp_vflag & INP_IPV6)
+ newpcbgroup = in6_pcbgroup_byinpcb(inp);
+ else
+#endif
+ newpcbgroup = in_pcbgroup_byinpcb(inp);
+ } else
+ newpcbgroup = NULL;
+ in_pcbgroup_update_internal(pcbinfo, newpcbgroup, inp);
+}
+
+void
+in_pcbgroup_update_mbuf(struct inpcb *inp, struct mbuf *m)
+{
+ struct inpcbinfo *pcbinfo;
+ struct inpcbgroup *newpcbgroup;
+
+ INP_WLOCK_ASSERT(inp);
+
+ pcbinfo = inp->inp_pcbinfo;
+ if (!in_pcbgroup_enabled(pcbinfo))
+ return;
+
+ /*
+ * Possibly should assert !INP_PCBGROUPWILD rather than testing for
+ * it; presumably this function should never be called for anything
+ * other than non-wildcard socket?
+ */
+ in_pcbwild_update_internal(inp);
+ if (!(inp->inp_flags2 & INP_PCBGROUPWILD) &&
+ !(inp->inp_flags & INP_DROPPED)) {
+ newpcbgroup = in_pcbgroup_bymbuf(pcbinfo, m);
+#ifdef INET6
+ if (inp->inp_vflag & INP_IPV6) {
+ if (newpcbgroup == NULL)
+ newpcbgroup = in6_pcbgroup_byinpcb(inp);
+ } else {
+#endif
+ if (newpcbgroup == NULL)
+ newpcbgroup = in_pcbgroup_byinpcb(inp);
+#ifdef INET6
+ }
+#endif
+ } else
+ newpcbgroup = NULL;
+ in_pcbgroup_update_internal(pcbinfo, newpcbgroup, inp);
+}
+
+/*
+ * Remove pcbgroup entry and optional pcbgroup wildcard entry for this inpcb.
+ */
+void
+in_pcbgroup_remove(struct inpcb *inp)
+{
+ struct inpcbgroup *pcbgroup;
+
+ INP_WLOCK_ASSERT(inp);
+
+ if (!in_pcbgroup_enabled(inp->inp_pcbinfo))
+ return;
+
+ if (inp->inp_flags2 & INP_PCBGROUPWILD)
+ in_pcbwild_remove(inp);
+
+ pcbgroup = inp->inp_pcbgroup;
+ if (pcbgroup != NULL) {
+ INP_GROUP_LOCK(pcbgroup);
+ LIST_REMOVE(inp, inp_pcbgrouphash);
+ inp->inp_pcbgroup = NULL;
+ INP_GROUP_UNLOCK(pcbgroup);
+ }
+}
+
+/*
+ * Query whether or not it is appropriate to use pcbgroups to look up inpcbs
+ * for a protocol.
+ */
+int
+in_pcbgroup_enabled(struct inpcbinfo *pcbinfo)
+{
+
+ return (pcbinfo->ipi_npcbgroups > 0);
+}
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index 6f5bce7..527ce56 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -153,7 +153,8 @@ div_init(void)
* place for hashbase == NULL.
*/
in_pcbinfo_init(&V_divcbinfo, "div", &V_divcb, 1, 1, "divcb",
- div_inpcb_init, div_inpcb_fini, UMA_ZONE_NOFREE);
+ div_inpcb_init, div_inpcb_fini, UMA_ZONE_NOFREE,
+ IPI_HASHFIELDS_NONE);
}
static void
diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c
index b4d3abb..49c48b9 100644
--- a/sys/netinet/ipfw/ip_fw2.c
+++ b/sys/netinet/ipfw/ip_fw2.c
@@ -692,6 +692,10 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
lookupflags |= INPLOOKUP_RLOCKPCB;
match = 0;
if (*ugid_lookupp == 0) {
+ /*
+ * XXXRW: If we had the mbuf here, could use
+ * in_pcblookup_mbuf().
+ */
pcb = (oif) ?
in_pcblookup(pi,
dst_ip, htons(dst_port),
diff --git a/sys/netinet/ipfw/ip_fw_sockopt.c b/sys/netinet/ipfw/ip_fw_sockopt.c
index f81d57d..2347456 100644
--- a/sys/netinet/ipfw/ip_fw_sockopt.c
+++ b/sys/netinet/ipfw/ip_fw_sockopt.c
@@ -349,12 +349,13 @@ del_entry(struct ip_fw_chain *chain, uint32_t arg)
}
if (n == 0) {
- /* A flush request (arg == 0) on empty ruleset
- * returns with no error. On the contrary,
+ /* A flush request (arg == 0 or cmd == 1) on empty
+ * ruleset returns with no error. On the contrary,
* if there is no match on a specific request,
* we return EINVAL.
*/
- error = (arg == 0) ? 0 : EINVAL;
+ if (arg != 0 && cmd != 1)
+ error = EINVAL;
break;
}
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 635f08f..e754b88 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -205,7 +205,8 @@ rip_init(void)
{
in_pcbinfo_init(&V_ripcbinfo, "rip", &V_ripcb, INP_PCBHASH_RAW_SIZE,
- 1, "ripcb", rip_inpcb_init, NULL, UMA_ZONE_NOFREE);
+ 1, "ripcb", rip_inpcb_init, NULL, UMA_ZONE_NOFREE,
+ IPI_HASHFIELDS_NONE);
EVENTHANDLER_REGISTER(maxsockets_change, rip_zone_change, NULL,
EVENTHANDLER_PRI_ANY);
}
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 06854ec..6ed58911 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -300,7 +300,8 @@ tcp_init(void)
hashsize = 512; /* safe default */
}
in_pcbinfo_init(&V_tcbinfo, "tcp", &V_tcb, hashsize, hashsize,
- "tcp_inpcb", tcp_inpcb_init, NULL, UMA_ZONE_NOFREE);
+ "tcp_inpcb", tcp_inpcb_init, NULL, UMA_ZONE_NOFREE,
+ IPI_HASHFIELDS_4TUPLE);
/*
* These have to be type stable for the benefit of the timers.
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 5125134..66e4732 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
+#include "opt_pcbgroup.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -676,8 +677,14 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
#ifdef INET6
}
#endif
+
+ /*
+ * Install in the reservation hash table for now, but don't yet
+ * install a connection group since the full 4-tuple isn't yet
+ * configured.
+ */
inp->inp_lport = sc->sc_inc.inc_lport;
- if ((error = in_pcbinshash(inp)) != 0) {
+ if ((error = in_pcbinshash_nopcbgroup(inp)) != 0) {
/*
* Undo the assignments above if we failed to
* put the PCB on the hash lists.
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index fd864c0..28eb8fd 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -186,7 +186,8 @@ udp_init(void)
{
in_pcbinfo_init(&V_udbinfo, "udp", &V_udb, UDBHASHSIZE, UDBHASHSIZE,
- "udp_inpcb", udp_inpcb_init, NULL, UMA_ZONE_NOFREE);
+ "udp_inpcb", udp_inpcb_init, NULL, UMA_ZONE_NOFREE,
+ IPI_HASHFIELDS_2TUPLE);
V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(V_udpcb_zone, maxsockets);
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 9e8e5cd..9558d1b 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -652,8 +652,32 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
* that is, this address might make other addresses detached.
*/
pfxlist_onlink_check();
- if (error == 0 && ia)
+ if (error == 0 && ia) {
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
+ /*
+ * Try to clear the flag when a new
+ * IPv6 address is added onto an
+ * IFDISABLED interface and it
+ * succeeds.
+ */
+ struct in6_ndireq nd;
+
+ memset(&nd, 0, sizeof(nd));
+ nd.ndi.flags = ND_IFINFO(ifp)->flags;
+ nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
+ if (nd6_ioctl(SIOCSIFINFO_FLAGS,
+ (caddr_t)&nd, ifp) < 0)
+ log(LOG_NOTICE, "SIOCAIFADDR_IN6: "
+ "SIOCSIFINFO_FLAGS for -ifdisabled "
+ "failed.");
+ /*
+ * Ignore failure of clearing the flag
+ * intentionally. The failure means
+ * address duplication was detected.
+ */
+ }
EVENTHANDLER_INVOKE(ifaddr_event, ifp);
+ }
break;
}
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index 32759af..ae0da6a 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -611,7 +611,10 @@ struct ip6_mtuinfo {
#define IPV6CTL_STEALTH 45
#define ICMPV6CTL_ND6_ONLINKNSRFC4861 47
-#define IPV6CTL_MAXID 48
+#define IPV6CTL_NO_RADR 48 /* No defroute from RA */
+#define IPV6CTL_NORBIT_RAIF 49 /* Disable R-bit in NA on RA
+ * receiving IF. */
+#define IPV6CTL_MAXID 50
#endif /* __BSD_VISIBLE */
/*
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index da73f21..d15c605 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
+#include "opt_pcbgroup.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -827,6 +828,141 @@ in6_rtchange(struct inpcb *inp, int errno)
return inp;
}
+#ifdef PCBGROUP
+/*
+ * Lookup PCB in hash list, using pcbgroup tables.
+ */
+static struct inpcb *
+in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
+ struct in6_addr *faddr, u_int fport_arg, struct in6_addr *laddr,
+ u_int lport_arg, int lookupflags, struct ifnet *ifp)
+{
+ struct inpcbhead *head;
+ struct inpcb *inp, *tmpinp;
+ u_short fport = fport_arg, lport = lport_arg;
+ int faith;
+
+ if (faithprefix_p != NULL)
+ faith = (*faithprefix_p)(laddr);
+ else
+ faith = 0;
+
+ /*
+ * First look for an exact match.
+ */
+ tmpinp = NULL;
+ INP_GROUP_LOCK(pcbgroup);
+ head = &pcbgroup->ipg_hashbase[
+ INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, lport, fport,
+ pcbgroup->ipg_hashmask)];
+ LIST_FOREACH(inp, head, inp_pcbgrouphash) {
+ /* XXX inp locking */
+ if ((inp->inp_vflag & INP_IPV6) == 0)
+ continue;
+ if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) &&
+ IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&
+ inp->inp_fport == fport &&
+ inp->inp_lport == lport) {
+ /*
+ * XXX We should be able to directly return
+ * the inp here, without any checks.
+ * Well unless both bound with SO_REUSEPORT?
+ */
+ if (prison_flag(inp->inp_cred, PR_IP6))
+ goto found;
+ if (tmpinp == NULL)
+ tmpinp = inp;
+ }
+ }
+ if (tmpinp != NULL) {
+ inp = tmpinp;
+ goto found;
+ }
+
+ /*
+ * Then look for a wildcard match, if requested.
+ */
+ if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {
+ struct inpcb *local_wild = NULL, *local_exact = NULL;
+ struct inpcb *jail_wild = NULL;
+ int injail;
+
+ /*
+ * Order of socket selection - we always prefer jails.
+ * 1. jailed, non-wild.
+ * 2. jailed, wild.
+ * 3. non-jailed, non-wild.
+ * 4. non-jailed, wild.
+ */
+ head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, lport,
+ 0, pcbinfo->ipi_wildmask)];
+ LIST_FOREACH(inp, head, inp_pcbgroup_wild) {
+ /* XXX inp locking */
+ if ((inp->inp_vflag & INP_IPV6) == 0)
+ continue;
+
+ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
+ inp->inp_lport != lport) {
+ continue;
+ }
+
+ /* XXX inp locking */
+ if (faith && (inp->inp_flags & INP_FAITH) == 0)
+ continue;
+
+ injail = prison_flag(inp->inp_cred, PR_IP6);
+ if (injail) {
+ if (prison_check_ip6(inp->inp_cred,
+ laddr) != 0)
+ continue;
+ } else {
+ if (local_exact != NULL)
+ continue;
+ }
+
+ if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) {
+ if (injail)
+ goto found;
+ else
+ local_exact = inp;
+ } else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
+ if (injail)
+ jail_wild = inp;
+ else
+ local_wild = inp;
+ }
+ } /* LIST_FOREACH */
+
+ inp = jail_wild;
+ if (inp == NULL)
+ inp = jail_wild;
+ if (inp == NULL)
+ inp = local_exact;
+ if (inp == NULL)
+ inp = local_wild;
+ if (inp != NULL)
+ goto found;
+ } /* if ((lookupflags & INPLOOKUP_WILDCARD) != 0) */
+ INP_GROUP_UNLOCK(pcbgroup);
+ return (NULL);
+
+found:
+ in_pcbref(inp);
+ INP_GROUP_UNLOCK(pcbgroup);
+ if (lookupflags & INPLOOKUP_WLOCKPCB) {
+ INP_WLOCK(inp);
+ if (in_pcbrele_wlocked(inp))
+ return (NULL);
+ } else if (lookupflags & INPLOOKUP_RLOCKPCB) {
+ INP_RLOCK(inp);
+ if (in_pcbrele_rlocked(inp))
+ return (NULL);
+ } else
+ panic("%s: locking buf", __func__);
+ return (inp);
+}
+#endif /* PCBGROUP */
+
/*
* Lookup PCB in hash list.
*/
@@ -983,16 +1119,30 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
/*
* Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf
* from which a pre-calculated hash value may be extracted.
+ *
+ * Possibly more of this logic should be in in6_pcbgroup.c.
*/
struct inpcb *
in6_pcblookup(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, u_int fport,
struct in6_addr *laddr, u_int lport, int lookupflags, struct ifnet *ifp)
{
+#if defined(PCBGROUP)
+ struct inpcbgroup *pcbgroup;
+#endif
+
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
+#if defined(PCBGROUP)
+ if (in_pcbgroup_enabled(pcbinfo)) {
+ pcbgroup = in6_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
+ fport);
+ return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
+ laddr, lport, lookupflags, ifp));
+ }
+#endif
return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
lookupflags, ifp));
}
@@ -1002,11 +1152,28 @@ in6_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
u_int fport, struct in6_addr *laddr, u_int lport, int lookupflags,
struct ifnet *ifp, struct mbuf *m)
{
+#ifdef PCBGROUP
+ struct inpcbgroup *pcbgroup;
+#endif
+
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
+#ifdef PCBGROUP
+ if (in_pcbgroup_enabled(pcbinfo)) {
+ pcbgroup = in6_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
+ m->m_pkthdr.flowid);
+ if (pcbgroup != NULL)
+ return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr,
+ fport, laddr, lport, lookupflags, ifp));
+ pcbgroup = in6_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
+ fport);
+ return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
+ laddr, lport, lookupflags, ifp));
+ }
+#endif
return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
lookupflags, ifp));
}
diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h
index cf24704..8398d54 100644
--- a/sys/netinet6/in6_pcb.h
+++ b/sys/netinet6/in6_pcb.h
@@ -69,6 +69,16 @@
#define sin6tosa(sin6) ((struct sockaddr *)(sin6))
#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
+struct inpcbgroup *
+ in6_pcbgroup_byhash(struct inpcbinfo *, u_int, uint32_t);
+struct inpcbgroup *
+ in6_pcbgroup_byinpcb __P((struct inpcb *));
+struct inpcbgroup *
+ in6_pcbgroup_bymbuf(struct inpcbinfo *, struct mbuf *);
+struct inpcbgroup *
+ in6_pcbgroup_bytuple __P((struct inpcbinfo *, const struct in6_addr *,
+ u_short, const struct in6_addr *, u_short));
+
void in6_pcbpurgeif0 __P((struct inpcbinfo *, struct ifnet *));
void in6_losing __P((struct inpcb *));
int in6_pcbbind __P((struct inpcb *, struct sockaddr *, struct ucred *));
diff --git a/sys/netinet6/in6_pcbgroup.c b/sys/netinet6/in6_pcbgroup.c
new file mode 100644
index 0000000..850d7f4
--- /dev/null
+++ b/sys/netinet6/in6_pcbgroup.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2010-2011 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#ifdef INET6
+#include <netinet6/in6_pcb.h>
+#endif /* INET6 */
+
+/*
+ * Given a hash of whatever the covered tuple might be, return a pcbgroup
+ * index.
+ */
+static __inline u_int
+in6_pcbgroup_getbucket(struct inpcbinfo *pcbinfo, uint32_t hash)
+{
+
+ return (hash % pcbinfo->ipi_npcbgroups);
+}
+
+/*
+ * Map a (hashtype, hash) tuple into a connection group, or NULL if the hash
+ * information is insufficient to identify the pcbgroup.
+ */
+struct inpcbgroup *
+in6_pcbgroup_byhash(struct inpcbinfo *pcbinfo, u_int hashtype, uint32_t hash)
+{
+
+ return (NULL);
+}
+
+struct inpcbgroup *
+in6_pcbgroup_bymbuf(struct inpcbinfo *pcbinfo, struct mbuf *m)
+{
+
+ return (in6_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
+ m->m_pkthdr.flowid));
+}
+
+struct inpcbgroup *
+in6_pcbgroup_bytuple(struct inpcbinfo *pcbinfo, const struct in6_addr *laddrp,
+ u_short lport, const struct in6_addr *faddrp, u_short fport)
+{
+ uint32_t hash;
+
+ switch (pcbinfo->ipi_hashfields) {
+ case IPI_HASHFIELDS_4TUPLE:
+ hash = faddrp->s6_addr32[3] ^ fport;
+ break;
+
+ case IPI_HASHFIELDS_2TUPLE:
+ hash = faddrp->s6_addr32[3] ^ laddrp->s6_addr32[3];
+ break;
+
+ default:
+ hash = 0;
+ }
+ return (&pcbinfo->ipi_pcbgroups[in6_pcbgroup_getbucket(pcbinfo,
+ hash)]);
+}
+
+struct inpcbgroup *
+in6_pcbgroup_byinpcb(struct inpcb *inp)
+{
+
+ return (in6_pcbgroup_bytuple(inp->inp_pcbinfo, &inp->in6p_laddr,
+ inp->inp_lport, &inp->in6p_faddr, inp->inp_fport));
+}
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index ab54755..9e78e9a 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -409,6 +409,8 @@ VNET_DEFINE(int, ip6_sendredirects) = IPV6_SENDREDIRECTS;
VNET_DEFINE(int, ip6_defhlim) = IPV6_DEFHLIM;
VNET_DEFINE(int, ip6_defmcasthlim) = IPV6_DEFAULT_MULTICAST_HOPS;
VNET_DEFINE(int, ip6_accept_rtadv) = 0;
+VNET_DEFINE(int, ip6_no_radr) = 0;
+VNET_DEFINE(int, ip6_norbit_raif) = 0;
VNET_DEFINE(int, ip6_maxfragpackets); /* initialized in frag6.c:frag6_init() */
VNET_DEFINE(int, ip6_maxfrags); /* initialized in frag6.c:frag6_init() */
VNET_DEFINE(int, ip6_log_interval) = 5;
@@ -537,6 +539,15 @@ SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_ACCEPT_RTADV, accept_rtadv,
CTLFLAG_RW, &VNET_NAME(ip6_accept_rtadv), 0,
"Default value of per-interface flag for accepting ICMPv6 Router"
"Advertisement messages");
+SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_NO_RADR, no_radr,
+ CTLFLAG_RW, &VNET_NAME(ip6_no_radr), 0,
+ "Default value of per-interface flag to control whether routers "
+ "sending ICMPv6 RA messages on that interface are added into the "
+ "default router list.");
+SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_NORBIT_RAIF, norbit_raif, CTLFLAG_RW,
+ &VNET_NAME(ip6_norbit_raif), 0,
+ "Always set 0 to R flag in ICMPv6 NA messages when accepting RA"
+ " on the interface.");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
&VNET_NAME(ip6_keepfaith), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_LOG_INTERVAL, log_interval,
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index 4e44d9f..dbfba9a 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -316,6 +316,9 @@ VNET_DECLARE(int, ip6_maxfragpackets); /* Maximum packets in reassembly
VNET_DECLARE(int, ip6_maxfrags); /* Maximum fragments in reassembly
* queue */
VNET_DECLARE(int, ip6_accept_rtadv); /* Acts as a host not a router */
+VNET_DECLARE(int, ip6_no_radr); /* No defroute from RA */
+VNET_DECLARE(int, ip6_norbit_raif); /* Disable R-bit in NA on RA
+ * receiving IF. */
VNET_DECLARE(int, ip6_keepfaith); /* Firewall Aided Internet Translator */
VNET_DECLARE(int, ip6_log_interval);
VNET_DECLARE(time_t, ip6_log_time);
@@ -327,6 +330,8 @@ VNET_DECLARE(int, ip6_dad_count); /* DupAddrDetectionTransmits */
#define V_ip6_maxfragpackets VNET(ip6_maxfragpackets)
#define V_ip6_maxfrags VNET(ip6_maxfrags)
#define V_ip6_accept_rtadv VNET(ip6_accept_rtadv)
+#define V_ip6_no_radr VNET(ip6_no_radr)
+#define V_ip6_norbit_raif VNET(ip6_norbit_raif)
#define V_ip6_keepfaith VNET(ip6_keepfaith)
#define V_ip6_log_interval VNET(ip6_log_interval)
#define V_ip6_log_time VNET(ip6_log_time)
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index f1e48ea..2b51e43 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -193,6 +193,8 @@ nd6_ifattach(struct ifnet *ifp)
/* A loopback interface does not need to accept RTADV. */
if (V_ip6_accept_rtadv && !(ifp->if_flags & IFF_LOOPBACK))
nd->flags |= ND6_IFF_ACCEPT_RTADV;
+ if (V_ip6_no_radr && !(ifp->if_flags & IFF_LOOPBACK))
+ nd->flags |= ND6_IFF_NO_RADR;
/* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
nd6_setmtu0(ifp, nd);
@@ -825,7 +827,7 @@ nd6_purge(struct ifnet *ifp)
if (V_nd6_defifindex == ifp->if_index)
nd6_setdefaultiface(0);
- if (!V_ip6_forwarding && ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/* Refresh default router list. */
defrouter_select();
}
@@ -958,10 +960,9 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
/*
* If the default router list is empty, all addresses are regarded
* as on-link, and thus, as a neighbor.
- * XXX: we restrict the condition to hosts, because routers usually do
- * not have the "default router list".
*/
- if (!V_ip6_forwarding && TAILQ_FIRST(&V_nd_defrouter) == NULL &&
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV &&
+ TAILQ_FIRST(&V_nd_defrouter) == NULL &&
V_nd6_defifindex == ifp->if_index) {
return (1);
}
@@ -1022,8 +1023,7 @@ nd6_free(struct llentry *ln, int gc)
ifp = ln->lle_tbl->llt_ifp;
- if (!V_ip6_forwarding) {
-
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
dr = defrouter_lookup(&L3_ADDR_SIN6(ln)->sin6_addr, ifp);
if (dr != NULL && dr->expire &&
@@ -1322,6 +1322,16 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
struct ifaddr *ifa;
struct in6_ifaddr *ia;
+ /*
+ * Try to clear ifdisabled flag when enabling
+ * accept_rtadv or auto_linklocal.
+ */
+ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
+ !(ND.flags & ND6_IFF_IFDISABLED) &&
+ (ND.flags & (ND6_IFF_ACCEPT_RTADV |
+ ND6_IFF_AUTO_LINKLOCAL)))
+ ND.flags &= ~ND6_IFF_IFDISABLED;
+
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
!(ND.flags & ND6_IFF_IFDISABLED)) {
/* ifdisabled 1->0 transision */
@@ -1340,7 +1350,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
continue;
ia = (struct in6_ifaddr *)ifa;
if ((ia->ia6_flags & IN6_IFF_DUPLICATED) &&
- IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
+ IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) {
duplicated_linklocal = 1;
break;
}
@@ -1379,6 +1389,28 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
/* If no link-local address on ifp, configure */
ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL;
in6_ifattach(ifp, NULL);
+ } else if ((ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) &&
+ !(ND.flags & ND6_IFF_IFDISABLED)) {
+ /*
+ * When the IF already has
+ * ND6_IFF_AUTO_LINKLOCAL and no link-local
+ * address is assigned, try to assign one.
+ */
+ int haslinklocal = 0;
+
+ IF_ADDR_LOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ia = (struct in6_ifaddr *)ifa;
+ if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) {
+ haslinklocal = 1;
+ break;
+ }
+ }
+ IF_ADDR_UNLOCK(ifp);
+ if (!haslinklocal)
+ in6_ifattach(ifp, NULL);
}
}
ND_IFINFO(ifp)->flags = ND.flags;
@@ -1718,7 +1750,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* for those are not autoconfigured hosts, we explicitly avoid such
* cases for safety.
*/
- if (do_update && router && !V_ip6_forwarding &&
+ if (do_update && router &&
ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/*
* guaranteed recursion
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index abcfcb7..6f63192 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -85,6 +85,7 @@ struct nd_ifinfo {
*/
#define ND6_IFF_DONT_SET_IFROUTE 0x10
#define ND6_IFF_AUTO_LINKLOCAL 0x20
+#define ND6_IFF_NO_RADR 0x40
#define ND6_CREATE LLE_CREATE
#define ND6_EXCLUSIVE LLE_EXCLUSIVE
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index fd5bcf2..fb8e379 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -112,10 +112,14 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
int lladdrlen = 0;
int anycast = 0, proxy = 0, tentative = 0;
int tlladdr;
+ int rflag;
union nd_opts ndopts;
struct sockaddr_dl proxydl;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
+ rflag = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0;
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && V_ip6_norbit_raif)
+ rflag = 0;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, icmp6len,);
nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
@@ -339,8 +343,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
goto bad;
nd6_na_output(ifp, &in6_all, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
- tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
+ rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
goto freeit;
}
@@ -349,8 +352,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
nd6_na_output(ifp, &saddr6, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
- tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
+ rflag | ND_NA_FLAG_SOLICITED, tlladdr,
+ proxy ? (struct sockaddr *)&proxydl : NULL);
freeit:
if (ifa != NULL)
ifa_free(ifa);
@@ -862,7 +865,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
dr = defrouter_lookup(in6, ln->lle_tbl->llt_ifp);
if (dr)
defrtrlist_del(dr);
- else if (!V_ip6_forwarding) {
+ else if (ND_IFINFO(ln->lle_tbl->llt_ifp)->flags &
+ ND6_IFF_ACCEPT_RTADV) {
/*
* Even if the neighbor is not in the default
* router list, the neighbor may be used
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index 19ec989..e791e2e 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -127,8 +127,11 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len)
union nd_opts ndopts;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
- /* If I'm not a router, ignore it. */
- if (!V_ip6_forwarding)
+ /*
+ * Accept RS only when V_ip6_forwarding=1 and the interface has
+ * no ND6_IFF_ACCEPT_RTADV.
+ */
+ if (!V_ip6_forwarding || ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV)
goto freeit;
/* Sanity checks */
@@ -213,11 +216,10 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
/*
- * We only accept RAs only when
- * the node is not a router and
- * per-interface variable allows RAs on the receiving interface.
+ * We only accept RAs only when the per-interface flag
+ * ND6_IFF_ACCEPT_RTADV is on the receiving interface.
*/
- if (V_ip6_forwarding || !(ndi->flags & ND6_IFF_ACCEPT_RTADV))
+ if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
goto freeit;
if (ip6->ip6_hlim != 255) {
@@ -266,7 +268,15 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
bzero(&dr0, sizeof(dr0));
dr0.rtaddr = saddr6;
dr0.flags = nd_ra->nd_ra_flags_reserved;
- dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
+ /*
+ * Effectively-disable the route in the RA packet
+ * when ND6_IFF_NO_RADR on the receiving interface or
+ * ip6.forwarding=1.
+ */
+ if (ndi->flags & ND6_IFF_NO_RADR || V_ip6_forwarding)
+ dr0.rtlifetime = 0;
+ else
+ dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
dr0.expire = time_second + dr0.rtlifetime;
dr0.ifp = ifp;
/* unspecified or not? (RFC 2461 6.3.4) */
@@ -557,7 +567,7 @@ defrtrlist_del(struct nd_defrouter *dr)
* Flush all the routing table entries that use the router
* as a next hop.
*/
- if (!V_ip6_forwarding)
+ if (ND_IFINFO(dr->ifp)->flags & ND6_IFF_ACCEPT_RTADV)
rt6_flush(&dr->rtaddr, dr->ifp);
if (dr->installed) {
@@ -616,20 +626,6 @@ defrouter_select(void)
struct llentry *ln = NULL;
/*
- * This function should be called only when acting as an autoconfigured
- * host. Although the remaining part of this function is not effective
- * if the node is not an autoconfigured host, we explicitly exclude
- * such cases here for safety.
- */
- if (V_ip6_forwarding) {
- nd6log((LOG_WARNING,
- "defrouter_select: called unexpectedly (forwarding=%d)\n",
- V_ip6_forwarding));
- splx(s);
- return;
- }
-
- /*
* Let's handle easy case (3) first:
* If default router list is empty, there's nothing to be done.
*/
diff --git a/sys/netinet6/send.h b/sys/netinet6/send.h
index 36ba571..9795d14 100644
--- a/sys/netinet6/send.h
+++ b/sys/netinet6/send.h
@@ -33,7 +33,7 @@
#define SND_IN 1 /* Incoming traffic. */
struct sockaddr_send {
- unsigned char send_len; /* total length */
+ uint8_t send_len; /* total length */
sa_family_t send_family; /* address family */
int send_direction;
int send_ifidx;
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index 654f145..c2b7081 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -199,7 +199,9 @@ struct mbuf {
#define M_PROTO6 0x00080000 /* protocol-specific */
#define M_PROTO7 0x00100000 /* protocol-specific */
#define M_PROTO8 0x00200000 /* protocol-specific */
-#define M_FLOWID 0x00400000 /* flowid is valid */
+#define M_FLOWID 0x00400000 /* deprecated: flowid is valid */
+#define M_HASHTYPEBITS 0x0F000000 /* mask of bits holding flowid hash type */
+
/*
* For RELENG_{6,7} steal these flags for limited multiple routing table
* support. In RELENG_8 and beyond, use just one flag and a tag.
@@ -215,11 +217,45 @@ struct mbuf {
(M_PROTO1|M_PROTO2|M_PROTO3|M_PROTO4|M_PROTO5|M_PROTO6|M_PROTO7|M_PROTO8)
/*
+ * Network interface cards are able to hash protocol fields (such as IPv4
+ * addresses and TCP port numbers) classify packets into flows. These flows
+ * can then be used to maintain ordering while delivering packets to the OS
+ * via parallel input queues, as well as to provide a stateless affinity
+ * model. NIC drivers can pass up the hash via m->m_pkthdr.flowid, and set
+ * m_flag fields to indicate how the hash should be interpreted by the
+ * network stack.
+ *
+ * Most NICs support RSS, which provides ordering and explicit affinity, and
+ * use the hash m_flag bits to indicate what header fields were covered by
+ * the hash. M_HASHTYPE_OPAQUE can be set by non-RSS cards or configurations
+ * that provide an opaque flow identifier, allowing for ordering and
+ * distribution without explicit affinity.
+ */
+#define M_HASHTYPE_SHIFT 24
+#define M_HASHTYPE_NONE 0x0
+#define M_HASHTYPE_RSS_IPV4 0x1 /* IPv4 2-tuple */
+#define M_HASHTYPE_RSS_TCP_IPV4 0x2 /* TCPv4 4-tuple */
+#define M_HASHTYPE_RSS_IPV6 0x3 /* IPv6 2-tuple */
+#define M_HASHTYPE_RSS_TCP_IPV6 0x4 /* TCPv6 4-tuple */
+#define M_HASHTYPE_RSS_IPV6_EX 0x5 /* IPv6 2-tuple + ext hdrs */
+#define M_HASHTYPE_RSS_TCP_IPV6_EX 0x6 /* TCPv6 4-tiple + ext hdrs */
+#define M_HASHTYPE_OPAQUE 0xf /* ordering, not affinity */
+
+#define M_HASHTYPE_CLEAR(m) (m)->m_flags &= ~(M_HASHTYPEBITS)
+#define M_HASHTYPE_GET(m) (((m)->m_flags & M_HASHTYPEBITS) >> \
+ M_HASHTYPE_SHIFT)
+#define M_HASHTYPE_SET(m, v) do { \
+ (m)->m_flags &= ~M_HASHTYPEBITS; \
+ (m)->m_flags |= ((v) << M_HASHTYPE_SHIFT); \
+} while (0)
+#define M_HASHTYPE_TEST(m, v) (M_HASHTYPE_GET(m) == (v))
+
+/*
* Flags preserved when copying m_pkthdr.
*/
#define M_COPYFLAGS \
(M_PKTHDR|M_EOR|M_RDONLY|M_PROTOFLAGS|M_SKIP_FIREWALL|M_BCAST|M_MCAST|\
- M_FRAG|M_FIRSTFRAG|M_LASTFRAG|M_VLANTAG|M_PROMISC|M_FIB)
+ M_FRAG|M_FIRSTFRAG|M_LASTFRAG|M_VLANTAG|M_PROMISC|M_FIB|M_HASHTYPEBITS)
/*
* External buffer types: identify ext_buf type.
diff --git a/sys/sys/soundcard.h b/sys/sys/soundcard.h
index c4cfc27..a6817df 100644
--- a/sys/sys/soundcard.h
+++ b/sys/sys/soundcard.h
@@ -311,7 +311,8 @@ typedef struct _snd_capabilities {
* IOCTL Commands for /dev/sequencer
*/
-#define SNDCTL_SEQ_RESET _IO ('Q', 0)
+#define SNDCTL_SEQ_HALT _IO ('Q', 0)
+#define SNDCTL_SEQ_RESET SNDCTL_SEQ_HALT /* Historic interface */
#define SNDCTL_SEQ_SYNC _IO ('Q', 1)
#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info)
#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer res.(hz) */
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index 5b8f3c8..7f5d1b4 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -420,13 +420,13 @@ nospace:
*/
if (reclaimed == 0) {
reclaimed = 1;
- softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT);
UFS_UNLOCK(ump);
if (bp) {
brelse(bp);
bp = NULL;
}
UFS_LOCK(ump);
+ softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT);
goto retry;
}
UFS_UNLOCK(ump);
@@ -2356,8 +2356,8 @@ ffs_fserr(fs, inum, cp)
* specified inode by the specified amount. Under normal
* operation the count should always go down. Decrementing
* the count to zero will cause the inode to be freed.
- * adjblkcnt(inode, amt) - adjust the number of blocks used to
- * by the specifed amount.
+ * adjblkcnt(inode, amt) - adjust the number of blocks used by the
+ * inode by the specified amount.
* adjndir, adjbfree, adjifree, adjffree, adjnumclusters(amt) -
* adjust the superblock summary.
* freedirs(inode, count) - directory inodes [inode..inode + count - 1]
diff --git a/tools/regression/bin/sh/expansion/heredoc1.0 b/tools/regression/bin/sh/expansion/heredoc1.0
new file mode 100644
index 0000000..a67b2da
--- /dev/null
+++ b/tools/regression/bin/sh/expansion/heredoc1.0
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+f() { return $1; }
+
+[ `f 42; { cat; } <<EOF
+$?
+EOF
+` = 42 ] || echo compound command bad
+
+[ `f 42; (cat) <<EOF
+$?
+EOF
+` = 42 ] || echo subshell bad
+
+long=`printf %08192d 0`
+
+[ `f 42; { cat; } <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long compound command bad
+
+[ `f 42; (cat) <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long subshell bad
diff --git a/tools/regression/bin/sh/expansion/heredoc2.0 b/tools/regression/bin/sh/expansion/heredoc2.0
new file mode 100644
index 0000000..2551432
--- /dev/null
+++ b/tools/regression/bin/sh/expansion/heredoc2.0
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+f() { return $1; }
+
+[ `f 42; cat <<EOF
+$?
+EOF
+` = 42 ] || echo simple command bad
+
+long=`printf %08192d 0`
+
+[ `f 42; cat <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long simple command bad
diff --git a/usr.bin/calendar/io.c b/usr.bin/calendar/io.c
index ef98d5d..eb37eac 100644
--- a/usr.bin/calendar/io.c
+++ b/usr.bin/calendar/io.c
@@ -346,7 +346,7 @@ closecal(FILE *fp)
write(pdes[1], pw->pw_name, strlen(pw->pw_name));
write(pdes[1], ">\nTo: <", 7);
write(pdes[1], pw->pw_name, strlen(pw->pw_name));
- write(pdes[1], ">\nSubject: ", 12);
+ write(pdes[1], ">\nSubject: ", 11);
write(pdes[1], dayname, strlen(dayname));
write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30);
diff --git a/usr.bin/grep/Makefile b/usr.bin/grep/Makefile
index 8cd490d..f09a7d6 100644
--- a/usr.bin/grep/Makefile
+++ b/usr.bin/grep/Makefile
@@ -28,8 +28,6 @@ MLINKS= grep.1 egrep.1 \
bsdgrep.1: grep.1
cp ${.ALLSRC} ${.TARGET}
-WARNS?= 6
-
LDADD= -lz -lbz2
DPADD= ${LIBZ} ${LIBBZ2}
diff --git a/usr.bin/iconv/Makefile b/usr.bin/iconv/Makefile
index 7e8f6e7..deab092 100644
--- a/usr.bin/iconv/Makefile
+++ b/usr.bin/iconv/Makefile
@@ -7,8 +7,6 @@ PROG= iconv
#SRCS= iconv.c
MAN= iconv.1
-WARNS?= 6
-
LDADD+= -lcrypt
DPADD+= ${LIBCRYPT}
diff --git a/usr.bin/kdump/mksubr b/usr.bin/kdump/mksubr
index afff24d..dbde92b 100644
--- a/usr.bin/kdump/mksubr
+++ b/usr.bin/kdump/mksubr
@@ -345,7 +345,7 @@ auto_if_type "sockfamilyname" "AF_[[:alnum:]]+[[:space:]]+" "sys/socket.h"
auto_if_type "sockipprotoname" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h"
auto_switch_type "sockoptname" "SO_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h"
auto_switch_type "socktypename" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h"
-auto_switch_type "ptraceopname" "PT_[[:alnum:]]+[[:space:]]+[0-9]+" "sys/ptrace.h"
+auto_switch_type "ptraceopname" "PT_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/ptrace.h"
cat <<_EOF_
/*
diff --git a/usr.bin/rctl/Makefile b/usr.bin/rctl/Makefile
index 1088cf1..c5c32eb 100644
--- a/usr.bin/rctl/Makefile
+++ b/usr.bin/rctl/Makefile
@@ -6,6 +6,4 @@ MAN= rctl.8
DPADD= ${LIBUTIL}
LDADD= -lutil
-WARNS?= 6
-
.include <bsd.prog.mk>
diff --git a/usr.bin/su/su.1 b/usr.bin/su/su.1
index 8b79d41..d9180e3 100644
--- a/usr.bin/su/su.1
+++ b/usr.bin/su/su.1
@@ -28,7 +28,7 @@
.\" @(#)su.1 8.2 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
-.Dd July 1, 2008
+.Dd June 6, 2011
.Dt SU 1
.Os
.Sh NAME
@@ -193,16 +193,22 @@ PAM configuration for
.Sh EXAMPLES
.Bl -tag -width 5n -compact
.It Li "su -m man -c catman"
-Runs the command
-.Li catman
-as user
-.Li man .
+Starts a shell as user
+.Li man ,
+and runs the command
+.Li catman .
You will be asked for man's password unless your real UID is 0.
Note that the
.Fl m
option is required since user
.Dq man
does not have a valid shell by default.
+In this example,
+.Fl c
+is passed to the shell of the user
+.Dq man ,
+and is not interpreted as an argument to
+.Nm .
.It Li "su -m man -c 'catman /usr/share/man /usr/local/man'"
Same as above, but the target command consists of more than a
single word and hence is quoted for use with the
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/scripts/netconfig_ipv6 b/usr.sbin/bsdinstall/scripts/netconfig_ipv6
index 70bd203..8bff816 100755
--- a/usr.sbin/bsdinstall/scripts/netconfig_ipv6
+++ b/usr.sbin/bsdinstall/scripts/netconfig_ipv6
@@ -33,7 +33,6 @@
#
# TODO:
-# - Add -R /sbin/resolvconf to rtsol once support is in tree.
# - Add DHCPv6 support once FreeBSD ships with it.
#
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/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/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c
index 792ea27..b0f5ee0 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,11 @@ char *RM;
static char *tbuf;
static int hopcount; /* detect infinite loops in termcap, init 0 */
-static char *remotefile;
-
-extern char *conffile;
+static const char *remotefile;
+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 +100,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 +123,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 +177,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 */
@@ -233,8 +226,7 @@ tnchktc()
* name (before the first field) stops us.
*/
int
-tnamatch(np)
- char *np;
+tnamatch(char *np)
{
char *Np, *Bp;
@@ -260,8 +252,7 @@ tnamatch(np)
* into the termcap file in octal.
*/
static char *
-tskip(bp)
- char *bp;
+tskip(char *bp)
{
int dquote;
@@ -305,8 +296,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 +331,7 @@ tgetnum(id)
* not given.
*/
int
-tgetflag(id)
- char *id;
+tgetflag(char *id)
{
char *bp = tbuf;
@@ -369,8 +358,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 +383,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..ff5d90f 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;
-#define MUSTHAVE(var, cap) \
+ 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) \
do { \
int64_t t; \
if ((t = agetnum(cap)) < 0) { \
@@ -97,60 +123,158 @@ 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
+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;
+ 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);
+ }
+
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) {
+ rai = malloc(sizeof(*rai));
+ if (rai == 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;
+ memset(rai, 0, sizeof(*rai));
+ 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);
+ return (-1);
}
- 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 +283,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);
+ return (-1);
}
- 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);
+ return (-1);
}
- 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 +317,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);
+ return (-1);
}
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);
+ return (-1);
}
- 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);
+ return (-1);
}
- /*
- * 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);
+ return (-1);
}
- 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);
+ return (-1);
}
- 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__);
+ return (-1);
}
/* prefix information */
@@ -271,12 +381,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 +393,41 @@ 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));
/* link into chain */
- insque(pfx, &tmp->prefix);
- tmp->pfxs++;
- pfx->rainfo = tmp;
+ TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next);
+ rai->rai_pfxs++;
+ pfx->pfx_origin = PREFIX_FROM_CONFIG;
- 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);
+ return (-1);
}
- 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);
+ return (-1);
}
- 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);
+ return (-1);
}
- pfx->prefixlen = (int)val;
+ pfx->pfx_prefixlen = (int)val;
makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
if ((flagstr = (char *)agetstr(entbuf, &bp))) {
@@ -339,8 +440,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 +449,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);
+ return (-1);
}
- 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 +469,45 @@ 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);
+ return (-1);
}
- 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;
}
}
- 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);
+ return (-1);
}
- 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);
+ return (-1);
}
#ifdef SIOCSIFINFO_IN6
@@ -415,65 +517,56 @@ 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));
+ ELM_MALLOC(rti, exit(1));
/* link into chain */
- insque(rti, &tmp->route);
- tmp->routes++;
+ TAILQ_INSERT_TAIL(&rai->rai_route, rti, rti_next);
+ rai->rai_routes++;
- 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);
+ return (-1);
}
#if 0
/*
@@ -485,17 +578,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);
+ return (-1);
}
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);
+ return (-1);
}
#endif
@@ -505,19 +598,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);
+ return (-1);
}
- rti->prefixlen = (int)val;
+ rti->rti_prefixlen = (int)val;
makeentry(entbuf, sizeof(entbuf), i, "rtflags");
if ((flagstr = (char *)agetstr(entbuf, &bp))) {
@@ -541,17 +634,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);
+ return (-1);
}
/*
@@ -565,60 +658,143 @@ 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);
+ return (-1);
}
- rti->ltime = (u_int32_t)val64;
+ rti->rti_ltime = (u_int32_t)val64;
}
#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, exit(1));
+ if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) {
+ syslog(LOG_ERR, "<%s> inet_pton failed for %s",
+ __func__, abuf);
+ free(rdna);
+ return (-1);
+ }
+ 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);
+ return (-1);
+ }
+ rdn->rd_ltime = val;
+
+ /* link into chain */
+ TAILQ_INSERT_TAIL(&rai->rai_rdnss, rdn, rd_next);
+ }
+
+ for (i = -1; i < MAXDNSSLENT ; i++) {
+ struct dnssl *dns;
+ struct dnssl_addr *dnsa;
+ char *ap;
+ int c;
- /* okey */
- tmp->next = ralist;
- ralist = tmp;
+ 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, exit(1));
+ 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);
+ }
+
+ 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);
+ return (-1);
+ }
+ dns->dn_ltime = val;
+
+ /* link into chain */
+ TAILQ_INSERT_TAIL(&rai->rai_dnssl, dns, dn_next);
+ }
/* construct the sending packet */
- make_packet(tmp);
+ make_packet(rai);
+ 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);
}
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 +807,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 +819,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 +877,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 +908,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 +943,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 +982,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 +1003,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 +1021,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 +1048,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 +1063,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 +1074,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 +1144,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 +1219,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..38c19b8 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,8 @@
* SUCH DAMAGE.
*/
-extern void getconfig(char *);
+extern int getconfig(int);
+extern int rmconfig(int);
extern void delete_prefix(struct prefix *);
extern void invalidate_prefix(struct prefix *);
extern void update_prefix(struct prefix *);
@@ -45,3 +46,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..5159624 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,
@@ -176,7 +177,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 +194,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..6423e7b 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;
@@ -78,26 +87,27 @@ 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 +115,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,
};
-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 *);
+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,
+};
+
+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 ra_output(struct rainfo *);
+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];
@@ -162,18 +197,19 @@ main(argc, argv)
int i, ch;
int fflag = 0, logopt;
pid_t pid, otherpid;
+ int error;
/* 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,16 +268,26 @@ 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++);
+ for (i = 0; i < ifl_len; i++) {
+ int idx;
- if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) {
- fprintf(stderr, "fatal: inet_pton failed\n");
- exit(1);
+ idx = if_nametoindex(ifl_names[i]);
+ if (idx == 0) {
+ syslog(LOG_INFO,
+ "<%s> interface %s not found."
+ "Ignored at this moment.", __func__, ifl_names[i]);
+ continue;
+ }
+ error = getconfig(idx);
+ if (error)
+ syslog(LOG_INFO,
+ "<%s> invalid configuration for %s."
+ "Ignored at this moment.", __func__, ifl_names[i]);
}
pfh = pidfile_open(pidfilename, 0600, &otherpid);
@@ -292,7 +341,6 @@ main(argc, argv)
if (rtsock >= 0)
FD_SET(rtsock, fdsetp);
#endif
-
signal(SIGTERM, set_die);
signal(SIGUSR1, rtadvd_set_dump_file);
@@ -300,7 +348,6 @@ main(argc, argv)
#ifndef HAVE_POLL_H
memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */
#endif
-
if (do_dump) { /* SIGUSR1 */
do_dump = 0;
rtadvd_dump_file(dumpfilename);
@@ -325,7 +372,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 +404,88 @@ 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_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 +497,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 +518,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 +600,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 +643,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 +667,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 +679,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 +710,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 +751,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 +769,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 +800,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 +810,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 +820,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 +838,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 +866,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 +890,7 @@ rtadvd_input()
break;
}
rr_input(i, (struct icmp6_router_renum *)icp, pi, &rcvfrom,
- &dst);
+ &dst);
break;
default:
/*
@@ -806,17 +911,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 +929,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 +963,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 +973,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 +994,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 +1004,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 +1013,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 +1028,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 +1247,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 +1300,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 +1446,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 +1464,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 +1491,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 +1528,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 +1574,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));
+ 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));
- 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));
+ 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));
- 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 +1668,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 +1686,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;
+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 +1760,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 +1774,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 +1854,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 +1864,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..f65a837 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,150 @@
#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 *);
-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/Makefile b/usr.sbin/rtsold/Makefile
index efc322c..c7c93af 100644
--- a/usr.sbin/rtsold/Makefile
+++ b/usr.sbin/rtsold/Makefile
@@ -19,7 +19,6 @@ MAN= rtsold.8
MLINKS= rtsold.8 rtsol.8
SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
-WARNS?= 3
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H
DPADD= ${LIBKVM}
LDADD= -lkvm
diff --git a/usr.sbin/rtsold/dump.c b/usr.sbin/rtsold/dump.c
index 2756b87..2e6b4ca 100644
--- a/usr.sbin/rtsold/dump.c
+++ b/usr.sbin/rtsold/dump.c
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -58,41 +59,41 @@ static const char * const ifstatstr[] = {"IDLE", "DELAY", "PROBE", "DOWN", "TENT
static void
dump_interface_status(void)
{
- struct ifinfo *ifinfo;
+ struct ifinfo *ifi;
struct timeval now;
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.tv_sec - now.tv_sec));
}
- fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt);
+ fprintf(fp, " number of valid RAs: %d\n", ifi->racnt);
}
}
@@ -145,5 +146,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..afa935e 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,15 +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 *);
+#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 +120,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 +175,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 +188,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 +201,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 +212,50 @@ 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;
+ 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;
/* 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 +286,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 +365,157 @@ 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);
}
+ /* Initialize ra_opt per-interface structure. */
+ gettimeofday(&now, NULL);
+ if (!TAILQ_EMPTY(&ifi->ifi_ra_opt))
+ while ((rao = TAILQ_FIRST(&ifi->ifi_ra_opt)) != NULL) {
+ if (rao->rao_msg != NULL)
+ free(rao->rao_msg);
+ TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
+ free(rao);
+ }
+ else
+ TAILQ_INIT(&ifi->ifi_ra_opt);
+
+#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);
+
+ 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;
+ }
+ /* 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);
+
+ TAILQ_INSERT_TAIL(&ifi->ifi_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);
+
+ 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);
+ break;
+ }
+ /* 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);
+
+ TAILQ_INSERT_TAIL(&ifi->ifi_ra_opt, rao, rao_next);
+ p += len;
+ }
+ break;
+ default:
+ /* nothing to do for other options */
+ break;
+ }
+ raoptp = (char *)RA_OPT_NEXT_HDR(raoptp);
+ }
+ ra_opt_handler(ifi);
ifi->racnt++;
switch (ifi->state) {
@@ -371,23 +530,166 @@ 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 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);
+ TAILQ_FOREACH(rao, &ifi->ifi_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);
+
+ 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;
+ 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
+ CALL_SCRIPT(RESDEL, NULL);
+
+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);
+ }
+ }
+ return (0);
+}
+
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 +697,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 +710,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 +790,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..a8b7ca7 100644
--- a/usr.sbin/rtsold/rtsold.c
+++ b/usr.sbin/rtsold/rtsold.c
@@ -63,6 +63,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 +75,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 +89,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];
@@ -124,19 +125,15 @@ main(int argc, char **argv)
#endif
int rtsock;
- /*
- * Initialization
- */
- argv0 = argv[0];
-
- /* get option */
- if (argv0 && argv0[strlen(argv0) - 1] != 'd') {
- fflag = 1;
- once = 1;
- opts = "adDFO:";
- } else
- opts = "adDfFm1O:";
-
+#ifndef SMALL
+ /* rtsold */
+ opts = "adDfFm1O:P:R:";
+#else
+ /* rtsol */
+ opts = "adDFO:P:R:";
+ fflag = 1;
+ once = 1;
+#endif
while ((ch = getopt(argc, argv, opts)) != -1) {
switch (ch) {
case 'a':
@@ -163,17 +160,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 */
@@ -182,9 +185,9 @@ main(int argc, char **argv)
if (!fflag) {
char *ident;
- ident = strrchr(argv0, '/');
+ ident = strrchr(argv[0], '/');
if (!ident)
- ident = argv0;
+ ident = argv[0];
else
ident++;
openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
@@ -196,7 +199,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 +236,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 +251,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 +263,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 +277,6 @@ main(int argc, char **argv)
warnmsg(LOG_ERR, __func__,
"failed to initialize interfaces");
exit(1);
- /*NOTREACHED*/
}
if (aflag)
argv = autoifprobe();
@@ -278,7 +285,6 @@ main(int argc, char **argv)
warnmsg(LOG_ERR, __func__,
"failed to initialize %s", *argv);
exit(1);
- /*NOTREACHED*/
}
argv++;
}
@@ -291,7 +297,6 @@ main(int argc, char **argv)
/*NOTREACHED*/
}
-#if 1
/* dump the current pid */
if (!once) {
pid_t pid = getpid();
@@ -306,8 +311,6 @@ main(int argc, char **argv)
fclose(fp);
}
}
-#endif
-
#ifndef HAVE_POLL_H
memset(fdsetp, 0, fdmasks);
FD_SET(s, fdsetp);
@@ -337,7 +340,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 +376,97 @@ 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;
+ memset(ifi, 0, sizeof(*ifi));
+ ifi->sdl = sdl;
- strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname));
+ 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 +478,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,7 +492,8 @@ ifreconfig(char *ifname)
free(ifi->rs_data);
free(ifi->sdl);
free(ifi);
- return rv;
+
+ return (rv);
}
#endif
@@ -503,34 +502,35 @@ 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 +542,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 +552,64 @@ rtsol_check_timer(void)
{
static struct timeval returnval;
struct timeval now, rtsol_timer;
- struct ifinfo *ifinfo;
+ struct ifinfo *ifi;
+ 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, <=)) {
+ TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
+ if (timercmp(&ifi->expire, &now, <=)) {
if (dflag > 1)
warnmsg(LOG_DEBUG, __func__,
"timer expiration on %s, "
- "state = %d", ifinfo->ifname,
- ifinfo->state);
-
- switch (ifinfo->state) {
+ "state = %d", ifi->ifname,
+ ifi->state);
+
+ /* Remove all RA options. */
+ while ((rao = TAILQ_FIRST(&ifi->ifi_ra_opt)) != NULL) {
+ if (rao->rao_msg != NULL)
+ free(rao->rao_msg);
+ TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
+ free(rao);
+ }
+ 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,38 +617,58 @@ 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. */
+ struct ra_opt *rao_tmp;
+ int expire = 0;
- if (timercmp(&ifinfo->expire, &rtsol_timer, <))
- rtsol_timer = ifinfo->expire;
+ TAILQ_FOREACH_SAFE(rao, &ifi->ifi_ra_opt, rao_next, rao_tmp) {
+ warnmsg(LOG_DEBUG, __func__,
+ "RA expiration timer: "
+ "type=%d, msg=%s, timer=%ld:%08ld",
+ rao->rao_type, (char *)rao->rao_msg,
+ (long)rao->rao_expire.tv_sec,
+ (long)rao->rao_expire.tv_usec);
+ if (timercmp(&now, &rao->rao_expire, >=)) {
+ warnmsg(LOG_DEBUG, __func__,
+ "RA expiration timer: expired.");
+ TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
+ 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;
@@ -651,35 +679,35 @@ rtsol_check_timer(void)
warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld",
(long)returnval.tv_sec, (long)returnval.tv_usec);
- 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 +715,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 +729,30 @@ 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);
+ "set timer for %s to %d:%d", ifi->ifname,
+ (int)ifi->timer.tv_sec,
+ (int)ifi->timer.tv_usec);
}
#undef MILLION
@@ -742,28 +770,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 +828,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 +868,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 +880,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..1c395d0 100644
--- a/usr.sbin/rtsold/rtsold.h
+++ b/usr.sbin/rtsold/rtsold.h
@@ -31,8 +31,23 @@
* $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;
+};
+
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 */
@@ -54,6 +69,8 @@ struct ifinfo {
size_t rs_datalen;
u_char *rs_data;
+
+ TAILQ_HEAD(, ra_opt) ifi_ra_opt;
};
/* per interface status */
@@ -63,12 +80,41 @@ 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);
@@ -76,6 +122,7 @@ 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);
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>
OpenPOWER on IntegriCloud