summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile1
-rw-r--r--usr.sbin/rtadvctl/Makefile13
-rw-r--r--usr.sbin/rtadvctl/rtadvctl.892
-rw-r--r--usr.sbin/rtadvctl/rtadvctl.c833
-rw-r--r--usr.sbin/rtadvd/Makefile3
-rw-r--r--usr.sbin/rtadvd/config.c257
-rw-r--r--usr.sbin/rtadvd/config.h6
-rw-r--r--usr.sbin/rtadvd/control.c456
-rw-r--r--usr.sbin/rtadvd/control.h74
-rw-r--r--usr.sbin/rtadvd/control_client.c131
-rw-r--r--usr.sbin/rtadvd/control_client.h30
-rw-r--r--usr.sbin/rtadvd/control_server.c677
-rw-r--r--usr.sbin/rtadvd/control_server.h40
-rw-r--r--usr.sbin/rtadvd/dump.c321
-rw-r--r--usr.sbin/rtadvd/if.c671
-rw-r--r--usr.sbin/rtadvd/if.h35
-rw-r--r--usr.sbin/rtadvd/pathnames.h3
-rw-r--r--usr.sbin/rtadvd/rrenum.c20
-rw-r--r--usr.sbin/rtadvd/rtadvd.822
-rw-r--r--usr.sbin/rtadvd/rtadvd.c635
-rw-r--r--usr.sbin/rtadvd/rtadvd.h60
-rw-r--r--usr.sbin/rtadvd/timer.c123
-rw-r--r--usr.sbin/rtadvd/timer.h22
-rw-r--r--usr.sbin/rtadvd/timer_subr.c126
-rw-r--r--usr.sbin/rtadvd/timer_subr.h (renamed from usr.sbin/rtadvd/dump.h)28
25 files changed, 3497 insertions, 1182 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index 7fc531a..f738321 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -174,6 +174,7 @@ SUBDIR+= rip6query
SUBDIR+= route6d
SUBDIR+= rrenumd
SUBDIR+= rtadvd
+SUBDIR+= rtadvctl
SUBDIR+= rtsold
SUBDIR+= traceroute6
.endif
diff --git a/usr.sbin/rtadvctl/Makefile b/usr.sbin/rtadvctl/Makefile
new file mode 100644
index 0000000..3200288
--- /dev/null
+++ b/usr.sbin/rtadvctl/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+#
+.PATH: ${.CURDIR}/../rtadvd
+
+PROG= rtadvctl
+MAN= rtadvctl.8
+
+SRCS= rtadvctl.c control.c control_client.c if.c timer_subr.c
+
+CFLAGS+= -DROUTEINFO -I${.CURDIR} -I${.CURDIR}/../rtadvd
+WARNS?= 3
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rtadvctl/rtadvctl.8 b/usr.sbin/rtadvctl/rtadvctl.8
new file mode 100644
index 0000000..81cfa07
--- /dev/null
+++ b/usr.sbin/rtadvctl/rtadvctl.8
@@ -0,0 +1,92 @@
+.\" Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE 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 ARE DISCLAIMED. IN NO EVENT SHALL THE
+.\" PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 14, 2011
+.Dt RTADVCTL 8
+.Os
+.Sh NAME
+.Nm rtadvctl
+.Nd control program for
+.Xr rtadvd 8 daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl v
+.Ar subcommand
+.Op Ar interface ...
+.Sh DESCRIPTION
+.Nm
+is a utility that communicates
+.Xr rtadvd 8
+daemon and displays information on Router Advertisement messages being
+sent on each interfaces.
+.Pp
+This utility provides several options and subcommands.
+The options are as follows:
+.Bl -tag -width indent
+.\"
+.It Fl v
+Increase verbose level. When specified once, the
+.Nm
+utility shows additional information on prefixes, RDNSS, and DNSSL
+options.
+When twice, it shows information on inactive interfaces and
+some statistics.
+.El
+.Pp
+The subcommands are as follows:
+.Bl -tag -width indent
+.\"
+.It reload
+Specifies reloading the configuration file.
+.It shutdown
+Makes
+.Xr rtadvd 8
+daemon shut down immediately.
+.It show Op interfaces...
+Displays information on Router Advertisement messages being sent
+on each interfaces.
+.Sh SEE ALSO
+.Xr rtadv 8 ,
+.Xr rtadvd.conf 5
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Fx 9.0 .
+.Sh BUGS
+The
+.Xr rtadvd 8
+daemon stops responding to
+.Nm
+for a while just after reloading the configuration file by the reload
+subcommand.
+This is because in the current implementation it cannot communicate
+with
+.Nm
+during sending some additional RAs for graceful transition from one
+configuration to another.
+It will take at most nine seconds for each interface.
diff --git a/usr.sbin/rtadvctl/rtadvctl.c b/usr.sbin/rtadvctl/rtadvctl.c
new file mode 100644
index 0000000..e5be355
--- /dev/null
+++ b/usr.sbin/rtadvctl/rtadvctl.c
@@ -0,0 +1,833 @@
+/*-
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <err.h>
+
+#include "pathnames.h"
+#include "rtadvd.h"
+#include "if.h"
+#include "timer_subr.h"
+#include "control.h"
+#include "control_client.h"
+
+#define RA_IFSTATUS_INACTIVE 0
+#define RA_IFSTATUS_RA_RECV 1
+#define RA_IFSTATUS_RA_SEND 2
+
+static int vflag = LOG_ERR;
+
+static void usage(void);
+
+static int action_propset(char *);
+static int action_propget(char *, struct ctrl_msg_pl *);
+static int action_plgeneric(int, char *, char *);
+
+static int action_enable(int, char **);
+static int action_disable(int, char **);
+static int action_reload(int, char **);
+static int action_echo(int, char **);
+static int action_version(int, char **);
+static int action_shutdown(int, char **);
+
+static int action_show(int, char **);
+static int action_show_prefix(struct prefix *);
+#ifdef ROUTEINFO
+static int action_show_rtinfo(struct rtinfo *);
+#endif
+static int action_show_rdnss(void *);
+static int action_show_dnssl(void *);
+
+static int csock_client_open(struct sockinfo *);
+static size_t dname_labeldec(char *, size_t, const char *);
+static void mysyslog(int, const char *, ...);
+
+static const char *rtpref_str[] = {
+ "medium", /* 00 */
+ "high", /* 01 */
+ "rsv", /* 10 */
+ "low" /* 11 */
+};
+
+static struct dispatch_table {
+ const char *dt_comm;
+ int (*dt_act)(int, char **);
+} dtable[] = {
+ { "show", action_show },
+ { "reload", action_reload },
+ { "shutdown", action_shutdown },
+ { NULL, NULL },
+ { "enable", action_enable },
+ { "disable", action_disable },
+ { "echo", action_echo },
+ { "version", action_version },
+ { NULL, NULL },
+};
+
+static void
+mysyslog(int priority, const char * restrict fmt, ...)
+{
+ va_list ap;
+
+ if (vflag >= priority) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ }
+}
+
+static void
+usage(void)
+{
+ int i;
+
+ for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) {
+ if (dtable[i].dt_comm == NULL)
+ break;
+ printf("%s\n", dtable[i].dt_comm);
+ }
+
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ int ch;
+ int (*action)(int, char **) = NULL;
+ int error;
+
+ while ((ch = getopt(argc, argv, "Dv")) != -1) {
+ switch (ch) {
+ case 'D':
+ vflag = LOG_DEBUG;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) {
+ if (dtable[i].dt_comm == NULL ||
+ strcmp(dtable[i].dt_comm, argv[0]) == 0) {
+ action = dtable[i].dt_act;
+ break;
+ }
+ }
+
+ if (action != NULL) {
+ error = (dtable[i].dt_act)(--argc, ++argv);
+ if (error)
+ fprintf(stderr, "%s failed.\n", dtable[i].dt_comm);
+ } else
+ usage();
+
+ return (error);
+}
+
+static int
+csock_client_open(struct sockinfo *s)
+{
+ struct sockaddr_un sun;
+
+ if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
+ err(1, "cannot open control socket.");
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ sun.sun_len = sizeof(sun);
+ strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
+
+ if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
+ err(1, "connect: %s", s->si_name);
+
+ mysyslog(LOG_DEBUG,
+ "<%s> connected to %s", __func__, sun.sun_path);
+
+ return (0);
+}
+
+static int
+action_plgeneric(int action, char *plstr, char *buf)
+{
+ struct ctrl_msg_hdr *cm;
+ struct ctrl_msg_pl cp;
+ struct sockinfo *s;
+ char *msg;
+ char *p;
+ char *q;
+
+ s = &ctrlsock;
+ csock_client_open(s);
+
+ cm = (struct ctrl_msg_hdr *)buf;
+ msg = (char *)buf + sizeof(*cm);
+
+ cm->cm_version = CM_VERSION;
+ cm->cm_type = action;
+ cm->cm_len = sizeof(*cm);
+
+ if (plstr != NULL) {
+ memset(&cp, 0, sizeof(cp));
+ p = strchr(plstr, ':');
+ q = strchr(plstr, '=');
+ if (p != NULL && q != NULL && p > q)
+ return (1);
+
+ if (p == NULL) { /* No : */
+ cp.cp_ifname = NULL;
+ cp.cp_key = plstr;
+ } else if (p == plstr) { /* empty */
+ cp.cp_ifname = NULL;
+ cp.cp_key = plstr + 1;
+ } else {
+ *p++ = '\0';
+ cp.cp_ifname = plstr;
+ cp.cp_key = p;
+ }
+ if (q == NULL)
+ cp.cp_val = NULL;
+ else {
+ *q++ = '\0';
+ cp.cp_val = q;
+ }
+ cm->cm_len += cmsg_pl2bin(msg, &cp);
+
+ mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
+ __func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname);
+ }
+
+ return (cmsg_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf));
+}
+
+static int
+action_propget(char *argv, struct ctrl_msg_pl *cp)
+{
+ int error;
+ struct ctrl_msg_hdr *cm;
+ char buf[CM_MSG_MAXLEN];
+ char *msg;
+
+ memset(cp, 0, sizeof(*cp));
+ cm = (struct ctrl_msg_hdr *)buf;
+ msg = (char *)buf + sizeof(*cm);
+
+ error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf);
+ if (error || cm->cm_len <= sizeof(*cm))
+ return (1);
+
+ cmsg_bin2pl(msg, cp);
+ mysyslog(LOG_DEBUG, "<%s> type=%d, len=%d",
+ __func__, cm->cm_type, cm->cm_len);
+ mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
+ __func__,cp->cp_key, cp->cp_val_len, cp->cp_ifname);
+
+ return (0);
+}
+
+static int
+action_propset(char *argv)
+{
+ char buf[CM_MSG_MAXLEN];
+
+ return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf));
+}
+
+/* XXX */
+static int
+action_enable(int argc, char **argv)
+{
+ argc = argc;
+ argv = argv;
+
+ return (0);
+}
+
+/* XXX */
+static int
+action_disable(int argc, char **argv)
+{
+ argc = argc;
+ argv = argv;
+
+ return (0);
+}
+
+static int
+action_reload(int argc __unused, char **argv __unused)
+{
+ char *action_argv;
+
+ action_argv = strdup("reload");
+ return(action_propset(action_argv));
+}
+
+static int
+action_echo(int argc __unused, char **argv __unused)
+{
+ char *action_argv;
+
+ action_argv = strdup("echo");
+ return(action_propset(action_argv));
+}
+
+static int
+action_shutdown(int argc __unused, char **argv __unused)
+{
+ char *action_argv;
+
+ action_argv = strdup("shutdown");
+ return(action_propset(action_argv));
+}
+
+/* XXX */
+static int
+action_version(int argc __unused, char **argv __unused)
+{
+ char *action_argv;
+ struct ctrl_msg_pl cp;
+ int error;
+
+ action_argv = strdup(":version=");
+ error = action_propget(action_argv, &cp);
+ if (error)
+ return (error);
+
+ printf("version=%s\n", cp.cp_val);
+ return (0);
+}
+
+static int
+action_show(int argc, char **argv)
+{
+ char *action_argv;
+ char argv_ifilist[sizeof(":ifilist=")] = ":ifilist=";
+ char argv_ifi[IFNAMSIZ + sizeof(":ifi=")];
+ char argv_rai[IFNAMSIZ + sizeof(":rai=")];
+#ifdef ROUTEINFO
+ char argv_rti[IFNAMSIZ + sizeof(":rti=")];
+#endif
+ char argv_pfx[IFNAMSIZ + sizeof(":pfx=")];
+ char argv_rdnss[IFNAMSIZ + sizeof(":rdnss=")];
+ char argv_dnssl[IFNAMSIZ + sizeof(":dnssl=")];
+ char ssbuf[SSBUFLEN];
+
+ struct ctrl_msg_pl cp;
+ struct ifinfo *ifi;
+ TAILQ_HEAD(, ifinfo) ifl = TAILQ_HEAD_INITIALIZER(ifl);
+ char *endp;
+ char *p;
+ int error;
+ int i;
+ int len;
+
+ if (argc == 0) {
+ action_argv = argv_ifilist;
+ error = action_propget(action_argv, &cp);
+ if (error)
+ return (error);
+
+ p = cp.cp_val;
+ endp = p + cp.cp_val_len;
+ while (p < endp) {
+ ifi = malloc(sizeof(*ifi));
+ if (ifi == NULL)
+ exit(1);
+ memset(ifi, 0, sizeof(*ifi));
+
+ strcpy(ifi->ifi_ifname, p);
+ ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
+ TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
+ p += strlen(ifi->ifi_ifname) + 1;
+ }
+ } else {
+ for (i = 0; i < argc; i++) {
+ ifi = malloc(sizeof(*ifi));
+ if (ifi == NULL)
+ exit(1);
+ memset(ifi, 0, sizeof(*ifi));
+
+ strcpy(ifi->ifi_ifname, argv[i]);
+ ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
+ if (ifi->ifi_ifindex == 0)
+ exit(1);
+ TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
+ }
+ }
+
+ TAILQ_FOREACH(ifi, &ifl, ifi_next) {
+ struct ifinfo *ifi_s;
+ struct rainfo *rai;
+#ifdef ROUTEINFO
+ struct rtinfo *rti;
+#endif
+ struct prefix *pfx;
+ int c;
+ int ra_ifstatus;
+
+ sprintf(argv_ifi, "%s:ifi=", ifi->ifi_ifname);
+ action_argv = argv_ifi;
+ error = action_propget(action_argv, &cp);
+ if (error)
+ return (error);
+ ifi_s = (struct ifinfo *)cp.cp_val;
+
+ if (!(ifi_s->ifi_persist) && vflag < LOG_NOTICE)
+ continue;
+
+ printf("%s: flags=<", ifi->ifi_ifname);
+
+ /*
+ * RA_RECV = UP + CONFIGURED + ACCEPT_RTADV
+ * RA_SEND = UP + CONFIGURED + IPV6FORWARDING
+ */
+
+ c = 0;
+ if (ifi_s->ifi_ifindex == 0)
+ c += printf("NONEXISTENT");
+ else
+ c += printf("%s", (ifi_s->ifi_flags & IFF_UP) ?
+ "UP" : "DOWN");
+ if (ifi_s->ifi_state == IFI_STATE_CONFIGURED)
+ c += printf("%s%s", (c) ? "," : "", "CONFIGURED");
+
+ if (ifi_s->ifi_persist)
+ c += printf("%s%s", (c) ? "," : "", "PERSIST");
+ printf(">");
+
+ ra_ifstatus = RA_IFSTATUS_INACTIVE;
+ if ((ifi_s->ifi_flags & IFF_UP) &&
+ (ifi_s->ifi_state == IFI_STATE_CONFIGURED)) {
+ if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV)
+ ra_ifstatus = RA_IFSTATUS_RA_RECV;
+ else if (getinet6sysctl(IPV6CTL_FORWARDING))
+ ra_ifstatus = RA_IFSTATUS_RA_SEND;
+ else
+ ra_ifstatus = RA_IFSTATUS_INACTIVE;
+ }
+
+ c = 0;
+ printf(" status=<");
+ if (ra_ifstatus == RA_IFSTATUS_INACTIVE)
+ printf("%s%s", (c) ? "," : "", "INACTIVE");
+ else if (ra_ifstatus == RA_IFSTATUS_RA_RECV)
+ printf("%s%s", (c) ? "," : "", "RA_RECV");
+ else if (ra_ifstatus == RA_IFSTATUS_RA_SEND)
+ printf("%s%s", (c) ? "," : "", "RA_SEND");
+ printf("> ");
+
+ if (ifi_s->ifi_state != IFI_STATE_CONFIGURED) {
+ printf("\n");
+ continue;
+ }
+
+ printf("mtu %d\n", ifi_s->ifi_phymtu);
+
+ sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname);
+ action_argv = argv_rai;
+
+ error = action_propget(action_argv, &cp);
+ if (error)
+ continue;
+
+ rai = (struct rainfo *)cp.cp_val;
+
+ printf("\tDefaultLifetime: %s",
+ sec2str(rai->rai_lifetime, ssbuf));
+ if (ra_ifstatus != RA_IFSTATUS_RA_SEND &&
+ rai->rai_lifetime == 0)
+ printf(" (RAs will be sent with zero lifetime)");
+
+ printf("\n");
+
+ printf("\tMinAdvInterval/MaxAdvInterval: %s/%s\n",
+ sec2str(rai->rai_mininterval, ssbuf),
+ sec2str(rai->rai_maxinterval, ssbuf));
+ if (rai->rai_linkmtu)
+ printf("\tAdvLinkMTU: %d", rai->rai_linkmtu);
+ else
+ printf("\tAdvLinkMTU: <none>");
+
+ printf(", ");
+
+ printf("Flags: ");
+ if (rai->rai_managedflg || rai->rai_otherflg) {
+ printf("%s", rai->rai_managedflg ? "M" : "");
+ printf("%s", rai->rai_otherflg ? "O" : "");
+ } else
+ printf("<none>");
+
+ printf(", ");
+
+ printf("Preference: %s\n",
+ rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
+
+ printf("\t"
+ "ReachableTime: %s, "
+ "RetransTimer: %s, "
+ "CurHopLimit: %d\n",
+ sec2str(rai->rai_reachabletime, ssbuf),
+ sec2str(rai->rai_retranstimer, ssbuf),
+ rai->rai_hoplimit);
+ printf("\tAdvIfPrefixes: %s\n",
+ rai->rai_advifprefix ? "yes" : "no");
+ if (rai->rai_clockskew)
+ printf("\tClock skew: %ldsec\n",
+ rai->rai_clockskew);
+
+ if (vflag < LOG_WARNING)
+ continue;
+
+#ifdef ROUTEINFO
+ /* route information */
+ sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname);
+ action_argv = argv_rti;
+ error = action_propget(action_argv, &cp);
+ if (error)
+ return (error);
+
+ rti = (struct rtinfo *)cp.cp_val;
+ len = cp.cp_val_len / sizeof(*rti);
+ if (len > 0) {
+ printf("\tRoute Info:\n");
+
+ for (i = 0; i < len; i++)
+ action_show_rtinfo(&rti[i]);
+ }
+#endif
+ /* prefix information */
+ sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname);
+ action_argv = argv_pfx;
+
+ error = action_propget(action_argv, &cp);
+ if (error)
+ continue;
+
+ pfx = (struct prefix *)cp.cp_val;
+ len = cp.cp_val_len / sizeof(*pfx);
+
+ if (len > 0) {
+ printf("\tPrefixes (%d):\n", len);
+
+ for (i = 0; i < len; i++)
+ action_show_prefix(&pfx[i]);
+ }
+
+ /* RDNSS information */
+ sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname);
+ action_argv = argv_rdnss;
+
+ error = action_propget(action_argv, &cp);
+ if (error)
+ continue;
+
+ len = *((u_int16_t *)cp.cp_val);
+
+ if (len > 0) {
+ printf("\tRDNSS entries:\n");
+ action_show_rdnss(cp.cp_val);
+ }
+
+ /* DNSSL information */
+ sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname);
+ action_argv = argv_dnssl;
+
+ error = action_propget(action_argv, &cp);
+ if (error)
+ continue;
+
+ len = *((u_int16_t *)cp.cp_val);
+
+ if (len > 0) {
+ printf("\tDNSSL entries:\n");
+ action_show_dnssl(cp.cp_val);
+ }
+
+ if (vflag < LOG_NOTICE)
+ continue;
+
+ printf("\n");
+
+ printf("\tLast RA sent: %s",
+ (rai->rai_lastsent.tv_sec == 0) ? "never\n" :
+ ctime((time_t *)&rai->rai_lastsent.tv_sec));
+ printf("\tRA initcounts/waits: %d/%d\n",
+ rai->rai_initcounter,
+ rai->rai_waiting);
+ printf("\tRA out/in/inconsistent: %llu/%llu/%llu\n",
+ ifi_s->ifi_raoutput,
+ ifi_s->ifi_rainput,
+ ifi_s->ifi_rainconsistent);
+ printf("\tRS in: %llu\n",
+ ifi_s->ifi_rsinput);
+
+ printf("\n");
+
+ printf("\tReceived RAs:\n");
+ }
+
+ return (0);
+}
+
+#ifdef ROUTEINFO
+static int
+action_show_rtinfo(struct rtinfo *rti)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+ char ssbuf[SSBUFLEN];
+
+ printf("\t %s/%d (pref: %s, ltime: %s)\n",
+ inet_ntop(AF_INET6, &rti->rti_prefix,
+ ntopbuf, sizeof(ntopbuf)),
+ rti->rti_prefixlen,
+ rtpref_str[0xff & (rti->rti_rtpref >> 3)],
+ (rti->rti_ltime == ND6_INFINITE_LIFETIME) ?
+ "infinity" : sec2str(rti->rti_ltime, ssbuf));
+
+ return (0);
+}
+#endif
+
+static int
+action_show_prefix(struct prefix *pfx)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+ char ssbuf[SSBUFLEN];
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ printf("\t %s/%d", inet_ntop(AF_INET6, &pfx->pfx_prefix,
+ ntopbuf, sizeof(ntopbuf)), pfx->pfx_prefixlen);
+
+ printf(" (");
+ switch (pfx->pfx_origin) {
+ case PREFIX_FROM_KERNEL:
+ printf("KERNEL");
+ break;
+ case PREFIX_FROM_CONFIG:
+ printf("CONFIG");
+ break;
+ case PREFIX_FROM_DYNAMIC:
+ printf("DYNAMIC");
+ break;
+ }
+
+ printf(",");
+
+ printf(" vltime=%s",
+ (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ?
+ "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf));
+
+ if (pfx->pfx_vltimeexpire > 0)
+ printf("(expire: %s)",
+ ((long)pfx->pfx_vltimeexpire > now.tv_sec) ?
+ sec2str(pfx->pfx_vltimeexpire - now.tv_sec, ssbuf) :
+ "0");
+
+ printf(",");
+
+ printf(" pltime=%s",
+ (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ?
+ "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf));
+
+ if (pfx->pfx_pltimeexpire > 0)
+ printf("(expire %s)",
+ ((long)pfx->pfx_pltimeexpire > now.tv_sec) ?
+ sec2str(pfx->pfx_pltimeexpire - now.tv_sec, ssbuf) :
+ "0");
+
+ printf(",");
+
+ printf(" flags=");
+ if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
+ printf("%s", pfx->pfx_onlinkflg ? "L" : "");
+ printf("%s", pfx->pfx_autoconfflg ? "A" : "");
+ } else
+ printf("<none>");
+
+ if (pfx->pfx_timer) {
+ struct timeval *rest;
+
+ rest = rtadvd_timer_rest(pfx->pfx_timer);
+ if (rest) { /* XXX: what if not? */
+ printf(" expire=%s", sec2str(rest->tv_sec, ssbuf));
+ }
+ }
+
+ printf(")\n");
+
+ return (0);
+}
+
+static int
+action_show_rdnss(void *msg)
+{
+ struct rdnss *rdn;
+ struct rdnss_addr *rda;
+ u_int16_t *rdn_cnt;
+ u_int16_t *rda_cnt;
+ int i;
+ int j;
+ char *p;
+ u_int32_t ltime;
+ char ntopbuf[INET6_ADDRSTRLEN];
+ char ssbuf[SSBUFLEN];
+
+ p = msg;
+ rdn_cnt = (u_int16_t *)p;
+ p += sizeof(*rdn_cnt);
+
+ if (*rdn_cnt > 0) {
+ for (i = 0; i < *rdn_cnt; i++) {
+ rdn = (struct rdnss *)p;
+ ltime = rdn->rd_ltime;
+ p += sizeof(*rdn);
+
+ rda_cnt = (u_int16_t *)p;
+ p += sizeof(*rda_cnt);
+ if (*rda_cnt > 0)
+ for (j = 0; j < *rda_cnt; j++) {
+ rda = (struct rdnss_addr *)p;
+ printf("\t %s (ltime=%s)\n",
+ inet_ntop(AF_INET6,
+ &rda->ra_dns,
+ ntopbuf,
+ sizeof(ntopbuf)),
+ sec2str(ltime, ssbuf));
+ p += sizeof(*rda);
+ }
+ }
+ }
+
+ return (0);
+}
+
+static int
+action_show_dnssl(void *msg)
+{
+ struct dnssl *dns;
+ struct dnssl_addr *dna;
+ u_int16_t *dns_cnt;
+ u_int16_t *dna_cnt;
+ int i;
+ int j;
+ char *p;
+ u_int32_t ltime;
+ char hbuf[NI_MAXHOST];
+ char ssbuf[SSBUFLEN];
+
+ p = msg;
+ dns_cnt = (u_int16_t *)p;
+ p += sizeof(*dns_cnt);
+
+ if (*dns_cnt > 0) {
+ for (i = 0; i < *dns_cnt; i++) {
+ dns = (struct dnssl *)p;
+ ltime = dns->dn_ltime;
+ p += sizeof(*dns);
+
+ dna_cnt = (u_int16_t *)p;
+ p += sizeof(*dna_cnt);
+ if (*dna_cnt > 0)
+ for (j = 0; j < *dna_cnt; j++) {
+ dna = (struct dnssl_addr *)p;
+ dname_labeldec(hbuf, sizeof(hbuf),
+ dna->da_dom);
+ printf("\t %s (ltime=%s)\n",
+ hbuf, sec2str(ltime, ssbuf));
+ p += sizeof(*dna);
+ }
+ }
+ }
+
+ 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++ = '.';
+ mysyslog(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/Makefile b/usr.sbin/rtadvd/Makefile
index 5afb3bf..c2a7aff 100644
--- a/usr.sbin/rtadvd/Makefile
+++ b/usr.sbin/rtadvd/Makefile
@@ -16,7 +16,8 @@
PROG= rtadvd
MAN= rtadvd.conf.5 rtadvd.8
-SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c dump.c
+SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c timer_subr.c \
+ control.c control_server.c
DPADD= ${LIBUTIL}
LDADD= -lutil
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index c0e442b..a667819 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -3,6 +3,7 @@
/*
* Copyright (C) 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -130,41 +131,65 @@ dname_labelenc(char *dst, const char *src)
var = def; \
} while (0)
-#define ELM_MALLOC(p,error_action) \
- do { \
- p = malloc(sizeof(*p)); \
- if (p == NULL) { \
- syslog(LOG_ERR, "<%s> malloc failed: %s", \
- __func__, strerror(errno)); \
- error_action; \
- } \
- memset(p, 0, sizeof(*p)); \
- } while(0)
+int
+loadconfig_index(int idx)
+{
+ char ifname[IFNAMSIZ];
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (if_indextoname(idx, ifname) != NULL)
+ return (loadconfig_ifname(ifname));
+ else
+ return (1);
+}
int
-loadconfig(char *ifl_names[], const int ifl_len)
+loadconfig_ifname(char *ifname)
{
- int i;
- int idx;
+ struct ifinfo *ifi;
int error;
- for (i = 0; i < ifl_len; i++) {
- idx = if_nametoindex(ifl_names[i]);
- if (idx == 0) {
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ update_ifinfo(&ifilist, UPDATE_IFINFO_ALL);
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ /* NULL means all IFs will be processed. */
+ if (ifname != NULL &&
+ strcmp(ifi->ifi_ifname, ifname) != 0)
+ continue;
+
+ if (!ifi->ifi_persist) {
+ syslog(LOG_INFO,
+ "<%s> %s is not a target interface. "
+ "Ignored at this moment.", __func__,
+ ifi->ifi_ifname);
+ continue;
+
+ }
+ if (ifi->ifi_ifindex == 0) {
syslog(LOG_ERR,
- "<%s> interface %s not found. "
- "Ignored at this moment.", __func__, ifl_names[i]);
+ "<%s> %s not found. "
+ "Ignored at this moment.", __func__,
+ ifi->ifi_ifname);
continue;
}
- syslog(LOG_INFO,
- "<%s> loading config for %s.", __func__, ifl_names[i]);
- error = getconfig(idx);
- if (error)
+ if (getconfig(ifi->ifi_ifindex) == NULL) {
syslog(LOG_ERR,
"<%s> invalid configuration for %s. "
- "Ignored at this moment.", __func__, ifl_names[i]);
- }
+ "Ignored at this moment.", __func__,
+ ifi->ifi_ifname);
+ continue;
+ }
+ ifi->ifi_state = IFI_STATE_CONFIGURED;
+ syslog(LOG_DEBUG,
+ "<%s> ifname=%s marked as configured.",
+ __func__, ifi->ifi_ifname);
+ error = sock_mc_join(&sock, ifi->ifi_ifindex);
+ if (error)
+ exit(1);
+ }
return (0);
}
@@ -178,13 +203,43 @@ rmconfig(int idx)
struct rdnss_addr *rdna;
struct dnssl *dns;
struct rtinfo *rti;
+ struct ifinfo *ifi;
+ int error;
- rai = if_indextorainfo(idx);
- if (rai == NULL) {
- syslog(LOG_ERR, "<%s>: rainfo not found (idx=%d)",
+ ifi = if_indextoifinfo(idx);
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s>: ifinfo not found (idx=%d)",
__func__, idx);
return (-1);
}
+ rai = ifi->ifi_rainfo;
+
+ if (ifi->ifi_state == IFI_STATE_CONFIGURED) {
+ ifi->ifi_state = IFI_STATE_UNCONFIGURED;
+ syslog(LOG_DEBUG,
+ "<%s> ifname=%s marked as unconfigured.",
+ __func__, ifi->ifi_ifname);
+
+ error = sock_mc_leave(&sock, ifi->ifi_ifindex);
+ if (error)
+ exit(1);
+ }
+
+ /* clean up ifi */
+ if (!ifi->ifi_persist) {
+ TAILQ_REMOVE(&ifilist, ifi, ifi_next);
+ syslog(LOG_DEBUG, "<%s>: ifinfo (idx=%d) removed.",
+ __func__, idx);
+ free(ifi);
+ } else {
+ /* recreate an empty entry */
+ update_persist_ifinfo(&ifilist, ifi->ifi_ifname);
+ syslog(LOG_DEBUG, "<%s>: ifname=%s is persistent.",
+ __func__, ifi->ifi_ifname);
+ }
+ /* clean up rai if any */
+ if (rai == NULL)
+ return (0);
TAILQ_REMOVE(&railist, rai, rai_next);
syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.",
@@ -196,9 +251,6 @@ rmconfig(int idx)
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);
@@ -224,41 +276,42 @@ rmconfig(int idx)
free(rti);
}
free(rai);
-
+
return (0);
}
-int
+struct ifinfo *
getconfig(int idx)
{
int stat, i;
char tbuf[BUFSIZ];
struct rainfo *rai;
struct rainfo *rai_old;
+ struct ifinfo *ifi;
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 (idx == 0)
+ return (NULL);
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (ifi->ifi_ifindex == idx)
+ break;
}
+ if (ifi == NULL) /* if does not exist */
+ return (NULL);
- TAILQ_FOREACH(rai_old, &railist, rai_next)
- if (idx == rai_old->rai_ifindex)
- break;
+ rai_old = ifi->ifi_rainfo;
- if ((stat = agetent(tbuf, intface)) <= 0) {
+ if ((stat = agetent(tbuf, ifi->ifi_ifname)) <= 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);
+ __func__, ifi->ifi_ifname);
}
ELM_MALLOC(rai, exit(1));
@@ -269,6 +322,7 @@ getconfig(int idx)
TAILQ_INIT(&rai->rai_rdnss);
TAILQ_INIT(&rai->rai_dnssl);
TAILQ_INIT(&rai->rai_soliciter);
+ rai->rai_ifinfo = ifi;
/* gather on-link prefixes from the network interfaces. */
if (agetflag("noifprefix"))
@@ -282,25 +336,12 @@ getconfig(int idx)
else
rai->rai_advlinkopt = 1;
if (rai->rai_advlinkopt) {
- if ((rai->rai_sdl = if_nametosdl(intface)) == NULL) {
+ if (ifi->ifi_sdl.sdl_type == 0) {
syslog(LOG_ERR,
"<%s> can't get information of %s",
- __func__, intface);
+ __func__, ifi->ifi_ifname);
goto getconfig_free_rai;
}
- rai->rai_ifindex = rai->rai_sdl->sdl_index;
- } else
- 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);
}
/*
@@ -311,7 +352,7 @@ getconfig(int idx)
syslog(LOG_ERR,
"<%s> maxinterval (%ld) on %s is invalid "
"(must be between %u and %u)", __func__, val,
- intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
+ ifi->ifi_ifname, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
goto getconfig_free_rai;
}
rai->rai_maxinterval = (u_int)val;
@@ -322,7 +363,7 @@ getconfig(int idx)
syslog(LOG_ERR,
"<%s> mininterval (%ld) on %s is invalid "
"(must be between %d and %d)",
- __func__, val, intface, MIN_MININTERVAL,
+ __func__, val, ifi->ifi_ifname, MIN_MININTERVAL,
(rai->rai_maxinterval * 3) / 4);
goto getconfig_free_rai;
}
@@ -359,7 +400,7 @@ getconfig(int idx)
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__, rai->rai_rtpref, intface);
+ __func__, rai->rai_rtpref, ifi->ifi_ifname);
goto getconfig_free_rai;
}
@@ -369,7 +410,7 @@ getconfig(int idx)
syslog(LOG_ERR,
"<%s> router lifetime (%ld) on %s is invalid "
"(must be 0 or between %d and %d)",
- __func__, val, intface, rai->rai_maxinterval,
+ __func__, val, ifi->ifi_ifname, rai->rai_maxinterval,
MAXROUTERLIFETIME);
goto getconfig_free_rai;
}
@@ -380,7 +421,7 @@ getconfig(int idx)
syslog(LOG_ERR,
"<%s> reachable time (%ld) on %s is invalid "
"(must be no greater than %d)",
- __func__, val, intface, MAXREACHABLETIME);
+ __func__, val, ifi->ifi_ifname, MAXREACHABLETIME);
goto getconfig_free_rai;
}
rai->rai_reachabletime = (u_int32_t)val;
@@ -388,7 +429,7 @@ getconfig(int idx)
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);
+ __func__, (long long)val64, ifi->ifi_ifname);
goto getconfig_free_rai;
}
rai->rai_retranstimer = (u_int32_t)val64;
@@ -433,21 +474,21 @@ getconfig(int idx)
syslog(LOG_ERR,
"<%s> multicast prefix (%s) must "
"not be advertised on %s",
- __func__, addr, intface);
+ __func__, addr, ifi->ifi_ifname);
goto getconfig_free_pfx;
}
if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix))
syslog(LOG_NOTICE,
"<%s> link-local prefix (%s) will be"
" advertised on %s",
- __func__, addr, intface);
+ __func__, addr, ifi->ifi_ifname);
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);
+ __func__, val, addr, ifi->ifi_ifname);
goto getconfig_free_pfx;
}
pfx->pfx_prefixlen = (int)val;
@@ -472,7 +513,7 @@ getconfig(int idx)
syslog(LOG_ERR, "<%s> vltime (%lld) for "
"%s/%d on %s is out of range",
__func__, (long long)val64,
- addr, pfx->pfx_prefixlen, intface);
+ addr, pfx->pfx_prefixlen, ifi->ifi_ifname);
goto getconfig_free_pfx;
}
pfx->pfx_validlifetime = (u_int32_t)val64;
@@ -492,7 +533,7 @@ getconfig(int idx)
"<%s> pltime (%lld) for %s/%d on %s "
"is out of range",
__func__, (long long)val64,
- addr, pfx->pfx_prefixlen, intface);
+ addr, pfx->pfx_prefixlen, ifi->ifi_ifname);
goto getconfig_free_pfx;
}
pfx->pfx_preflifetime = (u_int32_t)val64;
@@ -518,7 +559,7 @@ getconfig_free_pfx:
if (val < 0 || (u_int)val > 0xffffffff) {
syslog(LOG_ERR,
"<%s> mtu (%ld) on %s out of range",
- __func__, val, intface);
+ __func__, val, ifi->ifi_ifname);
goto getconfig_free_rai;
}
rai->rai_linkmtu = (u_int32_t)val;
@@ -527,15 +568,15 @@ getconfig_free_pfx:
if ((mtustr = (char *)agetstr("mtu", &bp)) &&
strcmp(mtustr, "auto") == 0)
- rai->rai_linkmtu = rai->rai_phymtu;
+ rai->rai_linkmtu = ifi->ifi_phymtu;
}
else if (rai->rai_linkmtu < IPV6_MMTU ||
- rai->rai_linkmtu > rai->rai_phymtu) {
+ rai->rai_linkmtu > ifi->ifi_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)rai->rai_linkmtu, intface,
- IPV6_MMTU, rai->rai_phymtu);
+ __func__, (unsigned long)rai->rai_linkmtu, ifi->ifi_ifname,
+ IPV6_MMTU, ifi->ifi_phymtu);
goto getconfig_free_rai;
}
@@ -550,10 +591,10 @@ getconfig_free_pfx:
exit(1);
}
memset(&ndi, 0, sizeof(ndi));
- strncpy(ndi.ifname, intface, IFNAMSIZ);
+ strncpy(ndi.ifname, ifi->ifi_ifname, sizeof(ndi.ifname));
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0)
syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
- __func__, intface, strerror(errno));
+ __func__, ifi->ifi_ifname, strerror(errno));
/* reflect the RA info to the host variables in kernel */
ndi.ndi.chlim = rai->rai_hoplimit;
@@ -561,7 +602,7 @@ getconfig_free_pfx:
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__, ifi->ifi_ifname, strerror(errno));
close(s);
}
@@ -605,14 +646,14 @@ getconfig_free_pfx:
syslog(LOG_ERR,
"<%s> multicast route (%s) must "
"not be advertised on %s",
- __func__, addr, intface);
+ __func__, addr, ifi->ifi_ifname);
goto getconfig_free_rti;
}
if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
syslog(LOG_NOTICE,
"<%s> link-local route (%s) will "
"be advertised on %s",
- __func__, addr, intface);
+ __func__, addr, ifi->ifi_ifname);
goto getconfig_free_rti;
}
#endif
@@ -632,7 +673,7 @@ getconfig_free_pfx:
if (val < 0 || val > 128) {
syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s "
"out of range",
- __func__, val, addr, intface);
+ __func__, val, addr, ifi->ifi_ifname);
goto getconfig_free_rti;
}
rti->rti_prefixlen = (int)val;
@@ -668,7 +709,7 @@ getconfig_free_pfx:
syslog(LOG_ERR, "<%s> invalid route preference (%02x) "
"for %s/%d on %s",
__func__, rti->rti_rtpref, addr,
- rti->rti_prefixlen, intface);
+ rti->rti_prefixlen, ifi->ifi_ifname);
goto getconfig_free_rti;
}
@@ -688,14 +729,16 @@ getconfig_free_pfx:
oentbuf, entbuf);
else {
fprintf(stderr, "%s should be specified "
- "for interface %s.\n", entbuf, intface);
+ "for interface %s.\n", entbuf,
+ ifi->ifi_ifname);
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->rti_prefixlen, intface);
+ (long long)val64, addr, rti->rti_prefixlen,
+ ifi->ifi_ifname);
goto getconfig_free_rti;
}
rti->rti_ltime = (u_int32_t)val64;
@@ -743,7 +786,7 @@ getconfig_free_rti:
(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,
+ entbuf, val, ifi->ifi_ifname, rai->rai_maxinterval,
rai->rai_maxinterval * 2);
goto getconfig_free_rdn;
}
@@ -792,7 +835,7 @@ getconfig_free_rdn:
(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,
+ entbuf, val, ifi->ifi_ifname, rai->rai_maxinterval,
rai->rai_maxinterval * 2);
goto getconfig_free_dns;
}
@@ -834,18 +877,14 @@ getconfig_free_dns:
}
rmconfig(idx);
}
+ ifi->ifi_rainfo = rai;
TAILQ_INSERT_TAIL(&railist, rai, rai_next);
- /* set 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 (ifi);
- return (0);
getconfig_free_rai:
free(rai);
- return (-1);
+ return (NULL);
}
void
@@ -854,6 +893,7 @@ get_prefix(struct rainfo *rai)
struct ifaddrs *ifap, *ifa;
struct prefix *pfx;
struct in6_addr *a;
+ struct ifinfo *ifi;
u_char *p, *ep, *m, *lim;
u_char ntopbuf[INET6_ADDRSTRLEN];
@@ -863,11 +903,12 @@ get_prefix(struct rainfo *rai)
__func__);
exit(1);
}
+ ifi = rai->rai_ifinfo;
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
int plen;
- if (strcmp(ifa->ifa_name, rai->rai_ifname) != 0)
+ if (strcmp(ifa->ifa_name, ifi->ifi_ifname) != 0)
continue;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -910,7 +951,7 @@ get_prefix(struct rainfo *rai)
}
syslog(LOG_DEBUG,
"<%s> add %s/%d to prefix list on %s",
- __func__, ntopbuf, pfx->pfx_prefixlen, rai->rai_ifname);
+ __func__, ntopbuf, pfx->pfx_prefixlen, ifi->ifi_ifname);
/* set other fields with protocol defaults */
pfx->pfx_validlifetime = DEF_ADVVALIDLIFETIME;
@@ -951,8 +992,10 @@ static void
add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
{
struct prefix *pfx;
+ struct ifinfo *ifi;
u_char ntopbuf[INET6_ADDRSTRLEN];
+ ifi = rai->rai_ifinfo;
ELM_MALLOC(pfx, return);
pfx->pfx_prefix = ipr->ipr_prefix.sin6_addr;
pfx->pfx_prefixlen = ipr->ipr_plen;
@@ -968,7 +1011,7 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
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);
+ sizeof(ntopbuf)), ipr->ipr_plen, ifi->ifi_ifname);
/* reconstruct the packet */
rai->rai_pfxs++;
@@ -983,15 +1026,17 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
void
delete_prefix(struct prefix *pfx)
{
- u_char ntopbuf[INET6_ADDRSTRLEN];
struct rainfo *rai;
+ struct ifinfo *ifi;
+ u_char ntopbuf[INET6_ADDRSTRLEN];
rai = pfx->pfx_rainfo;
+ ifi = rai->rai_ifinfo;
TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next);
syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
__func__,
inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf,
- sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname);
+ sizeof(ntopbuf)), pfx->pfx_prefixlen, ifi->ifi_ifname);
if (pfx->pfx_timer)
rtadvd_remove_timer(pfx->pfx_timer);
free(pfx);
@@ -1002,11 +1047,13 @@ delete_prefix(struct prefix *pfx)
void
invalidate_prefix(struct prefix *pfx)
{
- u_char ntopbuf[INET6_ADDRSTRLEN];
struct timeval timo;
struct rainfo *rai;
+ struct ifinfo *ifi;
+ u_char ntopbuf[INET6_ADDRSTRLEN];
rai = pfx->pfx_rainfo;
+ ifi = rai->rai_ifinfo;
if (pfx->pfx_timer) { /* sanity check */
syslog(LOG_ERR,
"<%s> assumption failure: timer already exists",
@@ -1017,7 +1064,7 @@ invalidate_prefix(struct prefix *pfx)
syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, "
"will expire in %ld seconds", __func__,
inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, sizeof(ntopbuf)),
- pfx->pfx_prefixlen, rai->rai_ifname, (long)prefix_timo);
+ pfx->pfx_prefixlen, ifi->ifi_ifname, (long)prefix_timo);
/* set the expiration timer */
pfx->pfx_timer = rtadvd_add_timer(prefix_timeout, NULL, pfx, NULL);
@@ -1043,10 +1090,12 @@ prefix_timeout(void *arg)
void
update_prefix(struct prefix *pfx)
{
- u_char ntopbuf[INET6_ADDRSTRLEN];
struct rainfo *rai;
+ struct ifinfo *ifi;
+ u_char ntopbuf[INET6_ADDRSTRLEN];
rai = pfx->pfx_rainfo;
+ ifi = rai->rai_ifinfo;
if (pfx->pfx_timer == NULL) { /* sanity check */
syslog(LOG_ERR,
"<%s> assumption failure: timer does not exist",
@@ -1056,7 +1105,7 @@ update_prefix(struct prefix *pfx)
syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s",
__func__, inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf,
- sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname);
+ sizeof(ntopbuf)), pfx->pfx_prefixlen, ifi->ifi_ifname);
/* stop the expiration timer */
rtadvd_remove_timer(pfx->pfx_timer);
@@ -1153,15 +1202,17 @@ make_packet(struct rainfo *rai)
struct dnssl *dns;
size_t len;
struct prefix *pfx;
+ struct ifinfo *ifi;
+ ifi = rai->rai_ifinfo;
/* calculate total length */
packlen = sizeof(struct nd_router_advert);
if (rai->rai_advlinkopt) {
- if ((lladdroptlen = lladdropt_length(rai->rai_sdl)) == 0) {
+ if ((lladdroptlen = lladdropt_length(&ifi->ifi_sdl)) == 0) {
syslog(LOG_INFO,
"<%s> link-layer address option has"
" null length on %s. Treat as not included.",
- __func__, rai->rai_ifname);
+ __func__, ifi->ifi_ifname);
rai->rai_advlinkopt = 0;
}
packlen += lladdroptlen;
@@ -1234,7 +1285,7 @@ make_packet(struct rainfo *rai)
buf += sizeof(*ra);
if (rai->rai_advlinkopt) {
- lladdropt_fill(rai->rai_sdl, (struct nd_opt_hdr *)buf);
+ lladdropt_fill(&ifi->ifi_sdl, (struct nd_opt_hdr *)buf);
buf += lladdroptlen;
}
diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h
index 01886a6..4d35d2f 100644
--- a/usr.sbin/rtadvd/config.h
+++ b/usr.sbin/rtadvd/config.h
@@ -30,9 +30,10 @@
* SUCH DAMAGE.
*/
-extern int getconfig(int);
+extern struct ifinfo *getconfig(int);
extern int rmconfig(int);
-extern int loadconfig(char *[], const int);
+extern int loadconfig_ifname(char *);
+extern int loadconfig_index(int);
extern void delete_prefix(struct prefix *);
extern void invalidate_prefix(struct prefix *);
extern void update_prefix(struct prefix *);
@@ -40,7 +41,6 @@ extern void make_prefix(struct rainfo *, int, struct in6_addr *, int);
extern void make_packet(struct rainfo *);
extern void get_prefix(struct rainfo *);
-
/*
* it is highly unlikely to have 100 prefix information options,
* so it should be okay to limit it
diff --git a/usr.sbin/rtadvd/control.c b/usr.sbin/rtadvd/control.c
new file mode 100644
index 0000000..a61240e
--- /dev/null
+++ b/usr.sbin/rtadvd/control.c
@@ -0,0 +1,456 @@
+/*-
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include "rtadvd.h"
+#include "if.h"
+#include "pathnames.h"
+#include "control.h"
+
+int
+cmsg_recv(int fd, char *buf)
+{
+ int n;
+ struct ctrl_msg_hdr *cm;
+ char *msg;
+
+ syslog(LOG_DEBUG, "<%s> enter, fd=%d", __func__, fd);
+
+ memset(buf, 0, CM_MSG_MAXLEN);
+ cm = (struct ctrl_msg_hdr *)buf;
+ msg = (char *)buf + sizeof(*cm);
+
+ for (;;) {
+ n = read(fd, cm, sizeof(*cm));
+ if (n < 0 && errno == EAGAIN) {
+ syslog(LOG_DEBUG,
+ "<%s> waiting...", __func__);
+ continue;
+ }
+ break;
+ }
+
+ if (n != sizeof(*cm)) {
+ syslog(LOG_WARNING,
+ "<%s> received a too small message.", __func__);
+ goto cmsg_recv_err;
+ }
+ if (cm->cm_len > CM_MSG_MAXLEN) {
+ syslog(LOG_WARNING,
+ "<%s> received a too large message.", __func__);
+ goto cmsg_recv_err;
+ }
+ if (cm->cm_version != CM_VERSION) {
+ syslog(LOG_WARNING,
+ "<%s> version mismatch", __func__);
+ goto cmsg_recv_err;
+ }
+ if (cm->cm_type >= CM_TYPE_MAX) {
+ syslog(LOG_WARNING,
+ "<%s> invalid msg type.", __func__);
+ goto cmsg_recv_err;
+ }
+
+ syslog(LOG_DEBUG,
+ "<%s> ctrl msg received: type=%d", __func__,
+ cm->cm_type);
+
+ if (cm->cm_len > sizeof(cm)) {
+ int msglen = cm->cm_len - sizeof(*cm);
+
+ syslog(LOG_DEBUG,
+ "<%s> ctrl msg has payload (len=%d)", __func__,
+ msglen);
+
+ for (;;) {
+ n = read(fd, msg, msglen);
+ if (n < 0 && errno == EAGAIN) {
+ syslog(LOG_DEBUG,
+ "<%s> waiting...", __func__);
+ continue;
+ }
+ break;
+ }
+ if (n != msglen) {
+ syslog(LOG_WARNING,
+ "<%s> payload size mismatch.", __func__);
+ goto cmsg_recv_err;
+ }
+ buf[CM_MSG_MAXLEN - 1] = '\0';
+ }
+
+ return (0);
+
+cmsg_recv_err:
+ close(fd);
+ return (-1);
+}
+
+int
+cmsg_send(int fd, char *buf)
+{
+ struct iovec iov[2];
+ int iovcnt;
+ ssize_t len;
+ ssize_t iov_len_total;
+ struct ctrl_msg_hdr *cm;
+ char *msg;
+
+ cm = (struct ctrl_msg_hdr *)buf;
+ msg = (char *)buf + sizeof(*cm);
+
+ iovcnt = 1;
+ iov[0].iov_base = cm;
+ iov[0].iov_len = sizeof(*cm);
+ iov_len_total = iov[0].iov_len;
+ if (cm->cm_len > sizeof(*cm)) {
+ iovcnt++;
+ iov[1].iov_base = msg;
+ iov[1].iov_len = cm->cm_len - iov[0].iov_len;
+ iov_len_total += iov[1].iov_len;
+ }
+
+ syslog(LOG_DEBUG,
+ "<%s> ctrl msg send: type=%d, count=%d, total_len=%d", __func__,
+ cm->cm_type, iovcnt, iov_len_total);
+
+ len = writev(fd, iov, iovcnt);
+ syslog(LOG_DEBUG,
+ "<%s> ctrl msg send: length=%d", __func__, len);
+
+ if (len == -1) {
+ syslog(LOG_DEBUG,
+ "<%s> write failed: (%d)%s", __func__, errno,
+ strerror(errno));
+ close(fd);
+ return (-1);
+ }
+
+ syslog(LOG_DEBUG,
+ "<%s> write length = %d (actual)", __func__, len);
+ syslog(LOG_DEBUG,
+ "<%s> write length = %d (expected)", __func__, iov_len_total);
+
+ if (len != iov_len_total) {
+ close(fd);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+csock_accept(struct sockinfo *s)
+{
+ struct sockaddr_un sun;
+ int flags;
+ int fd;
+
+ sun.sun_len = sizeof(sun);
+ if ((fd = accept(s->si_fd, (struct sockaddr *)&sun,
+ (socklen_t *)&sun.sun_len)) == -1) {
+ if (errno != EWOULDBLOCK && errno != EINTR)
+ syslog(LOG_WARNING, "<%s> accept ", __func__);
+ syslog(LOG_WARNING, "<%s> Xaccept: %s", __func__, strerror(errno));
+ return (-1);
+ }
+ if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
+ syslog(LOG_WARNING, "<%s> fcntl F_GETFL", __func__);
+ close(s->si_fd);
+ return (-1);
+ }
+ if ((flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
+ syslog(LOG_WARNING, "<%s> fcntl F_SETFL", __func__);
+ return (-1);
+ }
+ syslog(LOG_DEBUG, "<%s> accept connfd=%d, listenfd=%d", __func__,
+ fd, s->si_fd);
+
+ return (fd);
+}
+
+int
+csock_close(struct sockinfo *s)
+{
+ close(s->si_fd);
+ unlink(s->si_name);
+ syslog(LOG_DEBUG, "<%s> remove %s", __func__, s->si_name);
+ return (0);
+}
+
+int
+csock_listen(struct sockinfo *s)
+{
+ if (s->si_fd == -1) {
+ syslog(LOG_ERR, "<%s> listen failed", __func__);
+ return (-1);
+ }
+ if (listen(s->si_fd, SOCK_BACKLOG) == -1) {
+ syslog(LOG_ERR, "<%s> listen failed", __func__);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+csock_open(struct sockinfo *s, mode_t mode)
+{
+ int flags;
+ struct sockaddr_un sun;
+ mode_t old_umask;
+
+ if (s == NULL) {
+ syslog(LOG_ERR, "<%s> internal error.", __func__);
+ exit(1);
+ }
+ if (s->si_name == NULL)
+ s->si_name = _PATH_CTRL_SOCK;
+
+ if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
+ syslog(LOG_ERR,
+ "<%s> cannot open control socket", __func__);
+ return (-1);
+ }
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ sun.sun_len = sizeof(sun);
+ strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
+
+ if (unlink(s->si_name) == -1)
+ if (errno != ENOENT) {
+ syslog(LOG_ERR,
+ "<%s> unlink %s", __func__, s->si_name);
+ close(s->si_fd);
+ return (-1);
+ }
+ old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
+ if (bind(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+ syslog(LOG_ERR,
+ "<%s> bind failed: %s", __func__, s->si_name);
+ close(s->si_fd);
+ umask(old_umask);
+ return (-1);
+ }
+ umask(old_umask);
+ if (chmod(s->si_name, mode) == -1) {
+ syslog(LOG_ERR,
+ "<%s> chmod failed: %s", __func__, s->si_name);
+ goto csock_open_err;
+ }
+ if ((flags = fcntl(s->si_fd, F_GETFL, 0)) == -1) {
+ syslog(LOG_ERR,
+ "<%s> fcntl F_GETFL failed: %s", __func__, s->si_name);
+ goto csock_open_err;
+ }
+ if ((flags = fcntl(s->si_fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
+ syslog(LOG_ERR,
+ "<%s> fcntl F_SETFL failed: %s", __func__, s->si_name);
+ goto csock_open_err;
+ }
+
+ return (s->si_fd);
+
+csock_open_err:
+ close(s->si_fd);
+ unlink(s->si_name);
+ return (-1);
+}
+
+struct ctrl_msg_pl *
+cmsg_bin2pl(char *str, struct ctrl_msg_pl *cp)
+{
+ size_t len;
+ size_t *lenp;
+ char *p;
+
+ memset(cp, 0, sizeof(*cp));
+
+ p = str;
+
+ lenp = (size_t *)p;
+ len = *lenp++;
+ p = (char *)lenp;
+ syslog(LOG_DEBUG, "<%s> len(ifname) = %d", __func__, len);
+ if (len > 0) {
+ cp->cp_ifname = malloc(len + 1);
+ if (cp->cp_ifname == NULL) {
+ syslog(LOG_ERR, "<%s> malloc", __func__);
+ exit(1);
+ }
+ memcpy(cp->cp_ifname, p, len);
+ cp->cp_ifname[len] = '\0';
+ p += len;
+ }
+
+ lenp = (size_t *)p;
+ len = *lenp++;
+ p = (char *)lenp;
+ syslog(LOG_DEBUG, "<%s> len(key) = %d", __func__, len);
+ if (len > 0) {
+ cp->cp_key = malloc(len + 1);
+ if (cp->cp_key == NULL) {
+ syslog(LOG_ERR, "<%s> malloc", __func__);
+ exit(1);
+ }
+ memcpy(cp->cp_key, p, len);
+ cp->cp_key[len] = '\0';
+ p += len;
+ }
+
+ lenp = (size_t *)p;
+ len = *lenp++;
+ p = (char *)lenp;
+ syslog(LOG_DEBUG, "<%s> len(val) = %d", __func__, len);
+ if (len > 0) {
+ cp->cp_val = malloc(len + 1);
+ if (cp->cp_val == NULL) {
+ syslog(LOG_ERR, "<%s> malloc", __func__);
+ exit(1);
+ }
+ memcpy(cp->cp_val, p, len);
+ cp->cp_val[len] = '\0';
+ cp->cp_val_len = len;
+ } else
+ cp->cp_val_len = 0;
+
+ return (cp);
+}
+
+size_t
+cmsg_pl2bin(char *str, struct ctrl_msg_pl *cp)
+{
+ size_t len;
+ size_t *lenp;
+ char *p;
+ struct ctrl_msg_hdr *cm;
+
+ len = sizeof(size_t);
+ if (cp->cp_ifname != NULL)
+ len += strlen(cp->cp_ifname);
+ len += sizeof(size_t);
+ if (cp->cp_key != NULL)
+ len += strlen(cp->cp_key);
+ len += sizeof(size_t);
+ if (cp->cp_val != NULL && cp->cp_val_len > 0)
+ len += cp->cp_val_len;
+
+ if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
+ syslog(LOG_DEBUG, "<%s> msg too long (len=%d)",
+ __func__, len);
+ return (0);
+ }
+ syslog(LOG_DEBUG, "<%s> msglen=%d", __func__, len);
+ memset(str, 0, len);
+ p = str;
+ lenp = (size_t *)p;
+
+ if (cp->cp_ifname != NULL) {
+ *lenp++ = strlen(cp->cp_ifname);
+ p = (char *)lenp;
+ memcpy(p, cp->cp_ifname, strlen(cp->cp_ifname));
+ p += strlen(cp->cp_ifname);
+ } else {
+ *lenp++ = '\0';
+ p = (char *)lenp;
+ }
+
+ lenp = (size_t *)p;
+ if (cp->cp_key != NULL) {
+ *lenp++ = strlen(cp->cp_key);
+ p = (char *)lenp;
+ memcpy(p, cp->cp_key, strlen(cp->cp_key));
+ p += strlen(cp->cp_key);
+ } else {
+ *lenp++ = '\0';
+ p = (char *)lenp;
+ }
+
+ lenp = (size_t *)p;
+ if (cp->cp_val != NULL && cp->cp_val_len > 0) {
+ *lenp++ = cp->cp_val_len;
+ p = (char *)lenp;
+ memcpy(p, cp->cp_val, cp->cp_val_len);
+ p += cp->cp_val_len;
+ } else {
+ *lenp++ = '\0';
+ p = (char *)lenp;
+ }
+
+ return (len);
+}
+
+size_t
+cmsg_str2bin(char *bin, void *str, size_t len)
+{
+ struct ctrl_msg_hdr *cm;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
+ syslog(LOG_DEBUG, "<%s> msg too long (len=%d)",
+ __func__, len);
+ return (0);
+ }
+ syslog(LOG_DEBUG, "<%s> msglen=%d", __func__, len);
+ memcpy(bin, (char *)str, len);
+
+ return (len);
+}
+
+void *
+cmsg_bin2str(char *bin, void *str, size_t len)
+{
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ memcpy((char *)str, bin, len);
+
+ return (str);
+}
diff --git a/usr.sbin/rtadvd/control.h b/usr.sbin/rtadvd/control.h
new file mode 100644
index 0000000..a7de2ce
--- /dev/null
+++ b/usr.sbin/rtadvd/control.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#define SOCK_BACKLOG 5
+
+#define CM_MSG_MAXLEN 8192
+#define CM_VERSION 1
+#define CM_VERSION_STR "1.0"
+
+#define CM_TYPE_EOM 0
+#define CM_TYPE_ACK 1
+#define CM_TYPE_ERR 2
+#define CM_TYPE_NUL 3
+#define CM_TYPE_REQ_SET_PROP 4
+#define CM_TYPE_REQ_GET_PROP 5
+#define CM_TYPE_MAX 6
+
+#define CM_STATE_EOM 0
+#define CM_STATE_INIT 1
+#define CM_STATE_MSG_DISPATCH 2
+#define CM_STATE_MSG_RECV 3
+#define CM_STATE_ACK_WAIT 4
+
+struct ctrl_msg_hdr {
+ int cm_version;
+ size_t cm_len;
+ int cm_type;
+};
+
+struct ctrl_msg_pl {
+ char *cp_ifname;
+ char *cp_key;
+
+ size_t cp_val_len;
+ char *cp_val;
+};
+
+int csock_open(struct sockinfo *, mode_t);
+int csock_close(struct sockinfo *);
+int csock_listen(struct sockinfo *);
+int csock_accept(struct sockinfo *);
+int cmsg_send(int, char *);
+int cmsg_recv(int, char *);
+
+size_t cmsg_pl2bin(char *, struct ctrl_msg_pl *);
+struct ctrl_msg_pl *cmsg_bin2pl(char *, struct ctrl_msg_pl *);
+size_t cmsg_str2bin(char *, void *, size_t);
+void *cmsg_bin2str(char *, void *, size_t);
diff --git a/usr.sbin/rtadvd/control_client.c b/usr.sbin/rtadvd/control_client.c
new file mode 100644
index 0000000..a78bcc9
--- /dev/null
+++ b/usr.sbin/rtadvd/control_client.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include "pathnames.h"
+#include "rtadvd.h"
+#include "if.h"
+#include "control.h"
+#include "control_client.h"
+
+int
+cmsg_handler_client(int fd, int state, char *buf_orig)
+{
+ char buf[CM_MSG_MAXLEN];
+ struct ctrl_msg_hdr *cm;
+ struct ctrl_msg_hdr *cm_orig;
+ int error;
+ char *msg;
+ char *msg_orig;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ memset(buf, 0, sizeof(buf));
+ cm = (struct ctrl_msg_hdr *)buf;
+ cm_orig = (struct ctrl_msg_hdr *)buf_orig;
+ msg = (char *)buf + sizeof(*cm);
+ msg_orig = (char *)buf_orig + sizeof(*cm_orig);
+
+ if (cm_orig->cm_len > CM_MSG_MAXLEN) {
+ syslog(LOG_DEBUG, "<%s> msg too long", __func__);
+ close(fd);
+ return (-1);
+ }
+ cm->cm_type = cm_orig->cm_type;
+ if (cm_orig->cm_len > sizeof(*cm_orig)) {
+ memcpy(msg, msg_orig, cm_orig->cm_len - sizeof(*cm));
+ cm->cm_len = cm_orig->cm_len;
+ }
+ while (state != CM_STATE_EOM) {
+ syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
+
+ switch (state) {
+ case CM_STATE_INIT:
+ state = CM_STATE_EOM;
+ break;
+ case CM_STATE_MSG_DISPATCH:
+ cm->cm_version = CM_VERSION;
+ error = cmsg_send(fd, buf);
+ if (error)
+ syslog(LOG_WARNING,
+ "<%s> cmsg_send()", __func__);
+ state = CM_STATE_ACK_WAIT;
+ break;
+ case CM_STATE_ACK_WAIT:
+ error = cmsg_recv(fd, buf);
+ if (error) {
+ syslog(LOG_ERR,
+ "<%s> cmsg_recv()", __func__);
+ close(fd);
+ return (-1);
+ }
+ switch (cm->cm_type) {
+ case CM_TYPE_ACK:
+ syslog(LOG_DEBUG,
+ "<%s> CM_TYPE_ACK", __func__);
+ break;
+ case CM_TYPE_ERR:
+ syslog(LOG_DEBUG,
+ "<%s> CM_TYPE_ERR", __func__);
+ close(fd);
+ return (-1);
+ default:
+ syslog(LOG_DEBUG,
+ "<%s> unknown status", __func__);
+ close(fd);
+ return (-1);
+ }
+ memcpy(buf_orig, buf, cm->cm_len);
+ state = CM_STATE_EOM;
+ break;
+ }
+ }
+ close(fd);
+ return (0);
+}
diff --git a/usr.sbin/rtadvd/control_client.h b/usr.sbin/rtadvd/control_client.h
new file mode 100644
index 0000000..89a7d80
--- /dev/null
+++ b/usr.sbin/rtadvd/control_client.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+int cmsg_handler_client(int, int, char *);
diff --git a/usr.sbin/rtadvd/control_server.c b/usr.sbin/rtadvd/control_server.c
new file mode 100644
index 0000000..4432994
--- /dev/null
+++ b/usr.sbin/rtadvd/control_server.c
@@ -0,0 +1,677 @@
+/*-
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include "pathnames.h"
+#include "rtadvd.h"
+#include "if.h"
+#include "control.h"
+#include "control_server.h"
+#include "timer.h"
+
+static sig_atomic_t p_do_reload;
+static sig_atomic_t p_do_die;
+
+void set_do_reload(int sig __unused) { p_do_reload = 1; }
+void set_do_die(int sig __unused) { p_do_die = 1; }
+void reset_do_reload(void) { p_do_reload = 0; }
+void reset_do_die(void) { p_do_die = 0; }
+int do_reload(void) { return (p_do_reload); }
+int do_die(void) { return (p_do_die); }
+
+#define DEF_PL_HANDLER(key) { #key, cmsg_getprop_##key }
+
+static int cmsg_getprop_echo(struct ctrl_msg_pl *);
+static int cmsg_getprop_version(struct ctrl_msg_pl *);
+static int cmsg_getprop_ifilist(struct ctrl_msg_pl *);
+static int cmsg_getprop_ifi(struct ctrl_msg_pl *);
+static int cmsg_getprop_rai(struct ctrl_msg_pl *);
+static int cmsg_getprop_rai_timer(struct ctrl_msg_pl *);
+static int cmsg_getprop_pfx(struct ctrl_msg_pl *);
+static int cmsg_getprop_rdnss(struct ctrl_msg_pl *);
+static int cmsg_getprop_dnssl(struct ctrl_msg_pl *);
+#ifdef ROUTEINFO
+static int cmsg_getprop_rti(struct ctrl_msg_pl *);
+#endif
+
+static struct dispatch_table {
+ const char *dt_comm;
+ int (*dt_act)(struct ctrl_msg_pl *cp);
+} getprop_dtable[] = {
+ { "", cmsg_getprop_echo },
+ DEF_PL_HANDLER(echo),
+ DEF_PL_HANDLER(version),
+ DEF_PL_HANDLER(ifilist),
+ DEF_PL_HANDLER(ifi),
+ DEF_PL_HANDLER(rai),
+ DEF_PL_HANDLER(rai_timer),
+#ifdef ROUTEINFO
+ DEF_PL_HANDLER(rti),
+#endif
+ DEF_PL_HANDLER(pfx),
+ DEF_PL_HANDLER(rdnss),
+ DEF_PL_HANDLER(dnssl),
+};
+
+static int
+cmsg_getprop_echo(struct ctrl_msg_pl *cp)
+{
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+ cp->cp_val = strdup("");
+ cp->cp_val_len = strlen(cp->cp_val) + 1;
+
+ return (0);
+}
+
+static int
+cmsg_getprop_version(struct ctrl_msg_pl *cp)
+{
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+ cp->cp_val = strdup(CM_VERSION_STR);
+ cp->cp_val_len = strlen(cp->cp_val) + 1;
+
+ return (0);
+}
+
+static int
+cmsg_getprop_ifilist(struct ctrl_msg_pl *cp)
+{
+ struct ifinfo *ifi;
+ char *p;
+ size_t len;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ len = 0;
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ len += strlen(ifi->ifi_ifname) + 1;
+ }
+
+ syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
+
+ p = malloc(len);
+ if (p == NULL)
+ exit(1);
+ memset(p, 0, len);
+ cp->cp_val = p;
+
+ if (len > 0)
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ syslog(LOG_DEBUG, "<%s> add ifname=%s(%d)",
+ __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
+ strcpy(p, ifi->ifi_ifname);
+ p += strlen(ifi->ifi_ifname) + 1;
+ }
+ cp->cp_val_len = p - cp->cp_val;
+
+ return (0);
+}
+
+static int
+cmsg_getprop_ifi(struct ctrl_msg_pl *cp)
+{
+ struct ifinfo *ifi;
+ char *p;
+ size_t len;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
+ break;
+ }
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s> %s not found", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+
+ p = malloc(sizeof(*ifi));
+ if (p == NULL)
+ exit(1);
+ len = cmsg_str2bin(p, ifi, sizeof(*ifi));
+
+ syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
+
+ if (len == 0)
+ return (1);
+
+ cp->cp_val = p;
+ cp->cp_val_len = len;
+
+ return (0);
+}
+
+static int
+cmsg_getprop_rai(struct ctrl_msg_pl *cp)
+{
+ struct ifinfo *ifi;
+ struct rainfo *rai;
+ char *p;
+ size_t len;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
+ break;
+ }
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s> %s not found", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ if ((rai = ifi->ifi_rainfo) == NULL) {
+ syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+
+ p = malloc(sizeof(*rai));
+ if (p == NULL)
+ exit(1);
+ len = cmsg_str2bin(p, rai, sizeof(*rai));
+
+ syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
+
+ if (len == 0)
+ return (1);
+
+ cp->cp_val = p;
+ cp->cp_val_len = len;
+
+ return (0);
+}
+
+static int
+cmsg_getprop_rai_timer(struct ctrl_msg_pl *cp)
+{
+ struct ifinfo *ifi;
+ struct rainfo *rai;
+ struct rtadvd_timer *rtimer;
+ char *p;
+ size_t len;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
+ break;
+ }
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s> %s not found", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ if ((rai = ifi->ifi_rainfo) == NULL) {
+ syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ if ((rtimer = rai->rai_timer) == NULL) {
+ syslog(LOG_ERR, "<%s> %s has no rai_timer", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ p = malloc(sizeof(*rtimer));
+ if (p == NULL)
+ exit(1);
+ len = cmsg_str2bin(p, rtimer, sizeof(*rtimer));
+
+ syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
+
+ if (len == 0)
+ return (1);
+
+ cp->cp_val = p;
+ cp->cp_val_len = len;
+
+ return (0);
+}
+
+#ifdef ROUTEINFO
+static int
+cmsg_getprop_rti(struct ctrl_msg_pl *cp)
+{
+ struct ifinfo *ifi;
+ struct rainfo *rai;
+ struct rtinfo *rti;
+ char *p;
+ size_t len;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ len = 0;
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
+ break;
+ }
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s> %s not found", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ if (ifi->ifi_rainfo == NULL) {
+ syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ rai = ifi->ifi_rainfo;
+ TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
+ len += sizeof(*rti);
+ }
+
+ syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
+
+ p = malloc(len);
+ if (p == NULL)
+ exit(1);
+ memset(p, 0, len);
+ cp->cp_val = p;
+
+ if (len > 0)
+ TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
+ memcpy(p, rti, sizeof(*rti));
+ p += sizeof(*rti);
+ }
+ cp->cp_val_len = p - cp->cp_val;
+
+ return (0);
+}
+#endif
+
+static int
+cmsg_getprop_pfx(struct ctrl_msg_pl *cp)
+{
+ struct ifinfo *ifi;
+ struct rainfo *rai;
+ struct prefix *pfx;
+ char *p;
+ size_t len;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ len = 0;
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
+ break;
+ }
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s> %s not found", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ if (ifi->ifi_rainfo == NULL) {
+ syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ rai = ifi->ifi_rainfo;
+ TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
+ len += sizeof(*pfx);
+ }
+
+ syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
+
+ p = malloc(len);
+ if (p == NULL)
+ exit(1);
+ memset(p, 0, len);
+ cp->cp_val = p;
+
+ if (len > 0)
+ TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
+ memcpy(p, pfx, sizeof(*pfx));
+ p += sizeof(*pfx);
+ }
+ cp->cp_val_len = p - cp->cp_val;
+
+ return (0);
+}
+
+static int
+cmsg_getprop_rdnss(struct ctrl_msg_pl *cp)
+{
+ struct ifinfo *ifi;
+ struct rainfo *rai;
+ struct rdnss *rdn;
+ struct rdnss_addr *rda;
+ char *p;
+ size_t len;
+ u_int16_t *rdn_cnt;
+ u_int16_t *rda_cnt;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ len = 0;
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
+ break;
+ }
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s> %s not found", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ if (ifi->ifi_rainfo == NULL) {
+ syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ rai = ifi->ifi_rainfo;
+
+ len = sizeof(*rdn_cnt);
+ TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
+ len += sizeof(*rdn);
+ len += sizeof(*rda_cnt);
+ TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
+ len += sizeof(*rda);
+ }
+ }
+
+ syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
+
+ p = malloc(len);
+ if (p == NULL)
+ exit(1);
+ memset(p, 0, len);
+ cp->cp_val = p;
+
+ rdn_cnt = (u_int16_t *)p;
+ p += sizeof(*rdn_cnt);
+ TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
+ *rdn_cnt += 1;
+ memcpy(p, rdn, sizeof(*rdn));
+ p += sizeof(*rdn);
+
+ rda_cnt = (u_int16_t *)p;
+ p += sizeof(*rda_cnt);
+ TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
+ *rda_cnt += 1;
+ memcpy(p, rda, sizeof(*rda));
+ p += sizeof(*rda);
+ }
+ }
+ syslog(LOG_DEBUG, "<%s> rdn_cnt = %d", __func__, *rdn_cnt);
+ cp->cp_val_len = p - cp->cp_val;
+
+ return (0);
+}
+
+static int
+cmsg_getprop_dnssl(struct ctrl_msg_pl *cp)
+{
+ struct ifinfo *ifi;
+ struct rainfo *rai;
+ struct dnssl *dns;
+ struct dnssl_addr *dna;
+ char *p;
+ size_t len;
+ u_int16_t *dns_cnt;
+ u_int16_t *dna_cnt;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ len = 0;
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
+ break;
+ }
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s> %s not found", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ if (ifi->ifi_rainfo == NULL) {
+ syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
+ cp->cp_ifname);
+ return (1);
+ }
+ rai = ifi->ifi_rainfo;
+
+ len = sizeof(*dns_cnt);
+ TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
+ len += sizeof(*dns);
+ len += sizeof(*dna_cnt);
+ TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
+ len += sizeof(*dna);
+ }
+ }
+
+ syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
+
+ p = malloc(len);
+ if (p == NULL)
+ exit(1);
+ memset(p, 0, len);
+ cp->cp_val = p;
+
+ dns_cnt = (u_int16_t *)cp->cp_val;
+ p += sizeof(*dns_cnt);
+ TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
+ (*dns_cnt)++;
+ memcpy(p, dns, sizeof(*dns));
+ p += sizeof(*dns);
+
+ dna_cnt = (u_int16_t *)p;
+ p += sizeof(*dna_cnt);
+ TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
+ (*dna_cnt)++;
+ memcpy(p, dna, sizeof(*dna));
+ p += sizeof(*dna);
+ }
+ }
+ cp->cp_val_len = p - cp->cp_val;
+
+ return (0);
+}
+
+int
+cmsg_getprop(struct ctrl_msg_pl *cp)
+{
+ size_t i;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (cp == NULL)
+ return (1);
+
+ for (i = 0;
+ i < sizeof(getprop_dtable) / sizeof(getprop_dtable[0]);
+ i++) {
+ if (strcmp(cp->cp_key, getprop_dtable[i].dt_comm) == 0)
+ return (getprop_dtable[i].dt_act(cp));
+ }
+ return (1);
+}
+
+int
+cmsg_setprop(struct ctrl_msg_pl *cp)
+{
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (cp == NULL || cp->cp_key == NULL)
+ return (1);
+
+ if (strncmp(cp->cp_key, "reload", 8) == 0)
+ set_do_reload(0);
+ else if (strncmp(cp->cp_key, "shutdown", 8) == 0)
+ set_do_die(0);
+ else if (strncmp(cp->cp_key, "echo", 8) == 0)
+ ; /* do nothing */
+ else
+ return (1);
+
+ return (0);
+}
+
+int
+cmsg_handler_server(int fd)
+{
+ int state;
+ char *msg;
+ struct ctrl_msg_hdr *cm;
+ struct ctrl_msg_pl cp;
+ char buf[CM_MSG_MAXLEN];
+ char pbuf[CM_MSG_MAXLEN];
+ int error;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ memset(buf, 0, sizeof(buf));
+ memset(pbuf, 0, sizeof(pbuf));
+ cm = (struct ctrl_msg_hdr *)buf;
+ msg = (char *)buf + sizeof(*cm);
+
+ state = CM_STATE_INIT;
+ while (state != CM_STATE_EOM) {
+ syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
+
+ switch (state) {
+ case CM_STATE_INIT:
+ state = CM_STATE_MSG_RECV;
+ break;
+ case CM_STATE_MSG_DISPATCH:
+ cm->cm_version = CM_VERSION;
+ error = cmsg_send(fd, buf);
+ if (error)
+ syslog(LOG_WARNING,
+ "<%s> cmsg_send()", __func__);
+ state = CM_STATE_EOM;
+ break;
+ case CM_STATE_ACK_WAIT:
+ error = cmsg_recv(fd, buf);
+ if (error) {
+ syslog(LOG_ERR,
+ "<%s> cmsg_recv()", __func__);
+ close(fd);
+ return (-1);
+ }
+
+ switch (cm->cm_type) {
+ case CM_TYPE_ACK:
+ break;
+ case CM_TYPE_ERR:
+ syslog(LOG_DEBUG,
+ "<%s> CM_TYPE_ERR", __func__);
+ close(fd);
+ return (-1);
+ default:
+ syslog(LOG_DEBUG,
+ "<%s> unknown status", __func__);
+ close(fd);
+ return (-1);
+ }
+ state = CM_STATE_EOM;
+ break;
+ case CM_STATE_MSG_RECV:
+ error = cmsg_recv(fd, buf);
+
+ if (error) {
+ syslog(LOG_ERR,
+ "<%s> cmsg_recv()", __func__);
+ close(fd);
+ return (-1);
+ }
+ memset(&cp, 0, sizeof(cp));
+
+ syslog(LOG_DEBUG,
+ "<%s> cm->cm_type = %d", __func__, cm->cm_type);
+ syslog(LOG_DEBUG,
+ "<%s> cm->cm_len = %d", __func__, cm->cm_len);
+
+ switch (cm->cm_type) {
+ case CM_TYPE_EOM:
+ state = CM_STATE_EOM;
+ case CM_TYPE_NUL:
+ cm->cm_type = CM_TYPE_ACK;
+ cm->cm_len = sizeof(*cm);
+ break;
+ case CM_TYPE_REQ_GET_PROP:
+ cmsg_bin2pl(msg, &cp);
+ error = cmsg_getprop(&cp);
+ if (error) {
+ cm->cm_type = CM_TYPE_ERR;
+ cm->cm_len = sizeof(*cm);
+ } else {
+ cm->cm_type = CM_TYPE_ACK;
+ cm->cm_len = sizeof(*cm);
+ cm->cm_len += cmsg_pl2bin(msg, &cp);
+ }
+ break;
+ case CM_TYPE_REQ_SET_PROP:
+ cmsg_bin2pl(msg, &cp);
+ error = cmsg_setprop(&cp);
+ if (error) {
+ cm->cm_type = CM_TYPE_ERR;
+ cm->cm_len = sizeof(*cm);
+ } else {
+ cm->cm_type = CM_TYPE_ACK;
+ cm->cm_len = sizeof(*cm);
+ }
+ break;
+ default:
+ cm->cm_type = CM_TYPE_ERR;
+ cm->cm_len = sizeof(*cm);
+ }
+
+ switch (cm->cm_type) {
+ case CM_TYPE_ERR:
+ case CM_TYPE_ACK:
+ state = CM_STATE_MSG_DISPATCH;
+ break;
+ }
+ }
+ }
+ syslog(LOG_DEBUG, "<%s> leave", __func__);
+
+ return (0);
+}
diff --git a/usr.sbin/rtadvd/control_server.h b/usr.sbin/rtadvd/control_server.h
new file mode 100644
index 0000000..848e59e
--- /dev/null
+++ b/usr.sbin/rtadvd/control_server.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+int cmsg_getprop(struct ctrl_msg_pl *);
+int cmsg_setprop(struct ctrl_msg_pl *);
+
+int cmsg_handler_server(int);
+
+void set_do_reload(int);
+void set_do_die(int);
+void reset_do_reload(void);
+void reset_do_die(void);
+int do_reload(void);
+int do_die(void);
diff --git a/usr.sbin/rtadvd/dump.c b/usr.sbin/rtadvd/dump.c
deleted file mode 100644
index fac3fb2..0000000
--- a/usr.sbin/rtadvd/dump.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: dump.c,v 1.32 2003/05/19 09:46:50 keiichi Exp $ */
-
-/*
- * 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:
- * 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.
- * 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
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT 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/types.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/if_dl.h>
-
-#include <netinet/in.h>
-
-/* XXX: the following two are non-standard include files */
-#include <netinet6/in6_var.h>
-#include <netinet6/nd6.h>
-
-#include <arpa/inet.h>
-
-#include <netdb.h>
-#include <time.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <string.h>
-#include <errno.h>
-
-#include "rtadvd.h"
-#include "timer.h"
-#include "if.h"
-#include "dump.h"
-
-static FILE *fp;
-
-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 const char *rtpref_str[] = {
- "medium", /* 00 */
- "high", /* 01 */
- "rsv", /* 10 */
- "low" /* 11 */
-};
-
-static char *
-ether_str(struct sockaddr_dl *sdl)
-{
- static char hbuf[32];
- u_char *cp;
-
- if (sdl->sdl_alen && sdl->sdl_alen > 5) {
- cp = (u_char *)LLADDR(sdl);
- snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x",
- cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
- } else
- snprintf(hbuf, sizeof(hbuf), "NONE");
-
- return (hbuf);
-}
-
-static void
-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];
- struct timeval now;
-
- gettimeofday(&now, NULL); /* XXX: unused in most cases */
- TAILQ_FOREACH(rai, &railist, rai_next) {
- fprintf(fp, "%s:\n", rai->rai_ifname);
-
- fprintf(fp, " Status: %s\n",
- (iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) ? "UP" :
- "DOWN");
-
- /* control information */
- if (rai->rai_lastsent.tv_sec) {
- /* note that ctime() appends CR by itself */
- fprintf(fp, " Last RA sent: %s",
- ctime((time_t *)&rai->rai_lastsent.tv_sec));
- }
- if (rai->rai_timer)
- fprintf(fp, " Next RA will be sent: %s",
- 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->rai_waiting, rai->rai_initcounter);
-
- /* statistics */
- fprintf(fp, " statistics: RA(out/in/inconsistent): "
- "%llu/%llu/%llu, ",
- (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->rai_rsinput);
-
- /* interface information */
- if (rai->rai_advlinkopt)
- fprintf(fp, " Link-layer address: %s\n",
- 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->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->rai_rtpref >> 3) & 0xff]);
- fprintf(fp, "MTU: %d\n", rai->rai_linkmtu);
- fprintf(fp, " ReachableTime: %d, RetransTimer: %d, "
- "CurHopLimit: %d\n", rai->rai_reachabletime,
- rai->rai_retranstimer, rai->rai_hoplimit);
- if (rai->rai_clockskew)
- fprintf(fp, " Clock skew: %ldsec\n",
- rai->rai_clockskew);
- TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
- if (pfx == TAILQ_FIRST(&rai->rai_prefix))
- fprintf(fp, " Prefixes:\n");
- fprintf(fp, " %s/%d(",
- 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;
- case PREFIX_FROM_CONFIG:
- fprintf(fp, "CONFIG, ");
- break;
- case PREFIX_FROM_DYNAMIC:
- fprintf(fp, "DYNAMIC, ");
- break;
- }
- if (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME)
- fprintf(fp, "vltime: infinity");
- else
- fprintf(fp, "vltime: %ld",
- (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->pfx_preflifetime == ND6_INFINITE_LIFETIME)
- fprintf(fp, "pltime: infinity");
- else
- fprintf(fp, "pltime: %ld",
- (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: ");
- 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->pfx_timer);
- if (rest) { /* XXX: what if not? */
- fprintf(fp, ", expire in: %ld",
- (long)rest->tv_sec);
- }
- }
- fprintf(fp, ")\n");
- }
-#ifdef ROUTEINFO
- TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
- if (rti == TAILQ_FIRST(&rai->rai_route))
- fprintf(fp, " Route Information:\n");
- fprintf(fp, " %s/%d (",
- inet_ntop(AF_INET6, &rti->rti_prefix,
- prefixbuf, sizeof(prefixbuf)),
- rti->rti_prefixlen);
- fprintf(fp, "preference: %s, ",
- 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->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(const char *dumpfile)
-{
- syslog(LOG_DEBUG, "<%s> dump current status to %s", __func__,
- dumpfile);
-
- if ((fp = fopen(dumpfile, "w")) == NULL) {
- syslog(LOG_WARNING, "<%s> open a dump file(%s)",
- __func__, dumpfile);
- return;
- }
-
- if_dump();
-
- 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/if.c b/usr.sbin/rtadvd/if.c
index 8722a05..ad42d29 100644
--- a/usr.sbin/rtadvd/if.c
+++ b/usr.sbin/rtadvd/if.c
@@ -3,6 +3,7 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,19 +36,24 @@
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <net/if_types.h>
+#include <net/if_var.h>
#include <net/ethernet.h>
-#include <ifaddrs.h>
#include <net/route.h>
-#include <net/if_dl.h>
#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/ip6.h>
#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
+
+#include "pathnames.h"
#include "rtadvd.h"
#include "if.h"
@@ -59,14 +65,34 @@
((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;
+struct sockaddr_in6 sin6_linklocal_allnodes = {
+ .sin6_len = sizeof(sin6_linklocal_allnodes),
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
+};
+
+struct sockaddr_in6 sin6_linklocal_allrouters = {
+ .sin6_len = sizeof(sin6_linklocal_allrouters),
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
+};
+
+struct sockaddr_in6 sin6_sitelocal_allrouters = {
+ .sin6_len = sizeof(sin6_sitelocal_allrouters),
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT,
+};
+
+struct sockinfo sock = { .si_fd = -1, .si_name = NULL };
+struct sockinfo rtsock = { .si_fd = -1, .si_name = NULL };
+struct sockinfo ctrlsock = { .si_fd = -1, .si_name = _PATH_CTRL_SOCK };
+
+char *mcastif;
-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, struct sockaddr *,
+ struct sockaddr **);
+static struct if_msghdr *get_next_msghdr(struct if_msghdr *,
+ struct if_msghdr *);
static void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
@@ -83,133 +109,6 @@ get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
}
}
-struct sockaddr_dl *
-if_nametosdl(char *name)
-{
- int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
- char *buf, *next, *lim;
- size_t len;
- struct if_msghdr *ifm;
- struct sockaddr *sa, *rti_info[RTAX_MAX];
- struct sockaddr_dl *sdl = NULL, *ret_sdl;
-
- if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
- return (NULL);
- if ((buf = malloc(len)) == NULL)
- return (NULL);
- if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
- free(buf);
- return (NULL);
- }
-
- lim = buf + len;
- for (next = buf; next < lim; next += ifm->ifm_msglen) {
- ifm = (struct if_msghdr *)next;
- if (ifm->ifm_version != RTM_VERSION) {
- syslog(LOG_ERR,
- "<%s> RTM_VERSION mismatch (%d != %d).",
- __func__, ifm->ifm_version, RTM_VERSION);
- continue;
- }
- if (ifm->ifm_type == RTM_IFINFO) {
- sa = (struct sockaddr *)(ifm + 1);
- get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
- if ((sa = rti_info[RTAX_IFP]) != NULL) {
- if (sa->sa_family == AF_LINK) {
- sdl = (struct sockaddr_dl *)sa;
- if (strlen(name) != sdl->sdl_nlen)
- continue; /* not same len */
- if (strncmp(&sdl->sdl_data[0],
- name,
- sdl->sdl_nlen) == 0) {
- break;
- }
- }
- }
- }
- }
- if (next == lim) {
- /* search failed */
- free(buf);
- return (NULL);
- }
-
- if ((ret_sdl = malloc(sdl->sdl_len)) == NULL)
- goto end;
- memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
-
-end:
- free(buf);
- return (ret_sdl);
-}
-
-int
-if_getmtu(char *name)
-{
- struct ifaddrs *ifap, *ifa;
- struct if_data *ifd;
- u_long mtu = 0;
-
- if (getifaddrs(&ifap) < 0)
- return (0);
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (strcmp(ifa->ifa_name, name) == 0) {
- ifd = ifa->ifa_data;
- if (ifd)
- mtu = ifd->ifi_mtu;
- break;
- }
- }
- freeifaddrs(ifap);
-
-#ifdef SIOCGIFMTU /* XXX: this ifdef may not be necessary */
- if (mtu == 0) {
- struct ifreq ifr;
- int s;
-
- if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 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);
- }
- close(s);
-
- mtu = ifr.ifr_mtu;
- }
-#endif
-
- return (mtu);
-}
-
-/* give interface index and its old flags, then new flags returned */
-int
-if_getflags(int ifindex, int oifflags)
-{
- struct ifreq ifr;
- int s;
-
- if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "<%s> socket: %s", __func__,
- 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);
- close(s);
- return (oifflags & ~IFF_UP);
- }
- close(s);
- return (ifr.ifr_flags);
-}
-
#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
int
lladdropt_length(struct sockaddr_dl *sdl)
@@ -378,30 +277,6 @@ get_rtm_ifindex(char *buf)
}
int
-get_ifm_ifindex(char *buf)
-{
- struct if_msghdr *ifm = (struct if_msghdr *)buf;
-
- return ((int)ifm->ifm_index);
-}
-
-int
-get_ifam_ifindex(char *buf)
-{
- struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf;
-
- return ((int)ifam->ifam_index);
-}
-
-int
-get_ifm_flags(char *buf)
-{
- struct if_msghdr *ifm = (struct if_msghdr *)buf;
-
- return (ifm->ifm_flags);
-}
-
-int
get_prefixlen(char *buf)
{
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
@@ -458,140 +333,418 @@ prefixlen(u_char *p, u_char *lim)
return (masklen);
}
-int
-rtmsg_type(char *buf)
+struct ifinfo *
+update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname)
{
- struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct ifinfo *ifi;
+ int ifindex;
+
+ ifi = NULL;
+ ifindex = if_nametoindex(ifname);
+ TAILQ_FOREACH(ifi, ifi_head, ifi_next) {
+ if (ifindex != 0) {
+ if (ifindex == ifi->ifi_ifindex)
+ break;
+ } else {
+ if (strncmp(ifname, ifi->ifi_ifname,
+ sizeof(ifi->ifi_ifname)) == 0)
+ break;
+ }
+ }
- return (rtm->rtm_type);
-}
+ if (ifi == NULL) {
+ /* A new ifinfo element is needed. */
+ syslog(LOG_DEBUG, "<%s> new entry: %s", __func__,
+ ifname);
+
+ ELM_MALLOC(ifi, exit(1));
+ ifi->ifi_ifindex = 0;
+ strncpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)-1);
+ ifi->ifi_ifname[sizeof(ifi->ifi_ifname)-1] = '\0';
+ ifi->ifi_rainfo = NULL;
+ ifi->ifi_state = IFI_STATE_UNCONFIGURED;
+ TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
+ }
-int
-rtmsg_len(char *buf)
-{
- struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ ifi->ifi_persist = 1;
- return (rtm->rtm_msglen);
+ syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__,
+ ifi->ifi_ifname);
+ syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__,
+ ifi->ifi_ifname, ifi->ifi_state);
+ return (ifi);
}
int
-ifmsg_len(char *buf)
+update_ifinfo_nd_flags(struct ifinfo *ifi)
{
- struct if_msghdr *ifm = (struct if_msghdr *)buf;
+ struct in6_ndireq nd;
+ int s;
+ int error;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR,
+ "<%s> socket() failed.", __func__);
+ return (1);
+ }
+ /* ND flags */
+ memset(&nd, 0, sizeof(nd));
+ strncpy(nd.ifname, ifi->ifi_ifname,
+ sizeof(nd.ifname));
+ error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd);
+ if (error) {
+ close(s);
+ syslog(LOG_ERR,
+ "<%s> ioctl() failed.", __func__);
+ return (1);
+ }
+ ifi->ifi_nd_flags = nd.ndi.flags;
+ close(s);
- return (ifm->ifm_msglen);
+ return (0);
}
-/*
- * alloc buffer and get if_msghdrs block from kernel,
- * and put them into the buffer
- */
-static void
-get_iflist(char **buf, size_t *size)
+struct ifinfo *
+update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex)
{
- int mib[6];
-
- mib[0] = CTL_NET;
- mib[1] = PF_ROUTE;
- mib[2] = 0;
- mib[3] = AF_INET6;
- mib[4] = NET_RT_IFLIST;
- mib[5] = 0;
-
- if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) {
- syslog(LOG_ERR, "<%s> sysctl: iflist size get failed",
- __func__);
+ struct if_msghdr *ifm;
+ struct ifinfo *ifi = NULL;
+ struct sockaddr *sa;
+ struct sockaddr *rti_info[RTAX_MAX];
+ char *msg;
+ size_t len;
+ char *lim;
+ int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 };
+ int error;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) <
+ 0) {
+ syslog(LOG_ERR,
+ "<%s> sysctl: NET_RT_IFLIST size get failed", __func__);
exit(1);
}
- if ((*buf = malloc(*size)) == NULL) {
+ if ((msg = malloc(len)) == NULL) {
syslog(LOG_ERR, "<%s> malloc failed", __func__);
exit(1);
}
- if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
- syslog(LOG_ERR, "<%s> sysctl: iflist get failed",
- __func__);
+ if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) <
+ 0) {
+ syslog(LOG_ERR,
+ "<%s> sysctl: NET_RT_IFLIST get failed", __func__);
exit(1);
}
- return;
-}
-/*
- * alloc buffer and parse if_msghdrs block passed as arg,
- * and init the buffer as list of pointers ot each of the if_msghdr.
- */
-static void
-parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
-{
- int iflentry_size, malloc_size;
- struct if_msghdr *ifm;
- struct ifa_msghdr *ifam;
- char *lim;
+ lim = msg + len;
+ for (ifm = (struct if_msghdr *)msg;
+ ifm != NULL && ifm < (struct if_msghdr *)lim;
+ ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) {
+ int ifi_new;
- /*
- * Estimate least size of an iflist entry, to be obtained from kernel.
- * Should add sizeof(sockaddr) ??
- */
- iflentry_size = sizeof(struct if_msghdr);
- /* roughly estimate max list size of pointers to each if_msghdr */
- malloc_size = (bufsize/iflentry_size) * sizeof(size_t);
- if ((*ifmlist_p = (struct if_msghdr **)malloc(malloc_size)) == NULL) {
- syslog(LOG_ERR, "<%s> malloc failed", __func__);
- exit(1);
- }
+ syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %d",
+ __func__, ifm, lim, (char *)lim - (char *)ifm);
- lim = buf + bufsize;
- for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
+ if (ifm->ifm_version != RTM_VERSION) {
+ syslog(LOG_ERR,
+ "<%s> ifm_vesrion mismatch", __func__);
+ exit(1);
+ }
if (ifm->ifm_msglen == 0) {
- syslog(LOG_WARNING, "<%s> ifm_msglen is 0 "
- "(buf=%p lim=%p ifm=%p)", __func__,
- buf, lim, ifm);
- return;
+ syslog(LOG_WARNING,
+ "<%s> ifm_msglen is 0", __func__);
+ free(msg);
+ return (NULL);
}
+ ifi_new = 0;
if (ifm->ifm_type == RTM_IFINFO) {
- (*ifmlist_p)[ifm->ifm_index] = ifm;
+ struct ifreq ifr;
+ int s;
+ char ifname[IFNAMSIZ];
+
+ syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. "
+ "ifm_index = %d, ifindex = %d",
+ __func__, ifm->ifm_index, ifindex);
+
+ /* when ifindex is specified */
+ if (ifindex != UPDATE_IFINFO_ALL &&
+ ifindex != ifm->ifm_index)
+ continue;
+
+ /* lookup an entry with the same ifindex */
+ TAILQ_FOREACH(ifi, ifi_head, ifi_next) {
+ if (ifm->ifm_index == ifi->ifi_ifindex)
+ break;
+ if_indextoname(ifm->ifm_index, ifname);
+ if (strncmp(ifname, ifi->ifi_ifname,
+ sizeof(ifname)) == 0)
+ break;
+ }
+ if (ifi == NULL) {
+ syslog(LOG_DEBUG,
+ "<%s> new entry for idx=%d",
+ __func__, ifm->ifm_index);
+ ELM_MALLOC(ifi, exit(1));
+ ifi->ifi_rainfo = NULL;
+ ifi->ifi_state = IFI_STATE_UNCONFIGURED;
+ ifi->ifi_persist = 0;
+ ifi_new = 1;
+ }
+ /* ifindex */
+ ifi->ifi_ifindex = ifm->ifm_index;
+
+ /* ifname */
+ if_indextoname(ifm->ifm_index, ifi->ifi_ifname);
+ if (ifi->ifi_ifname == NULL) {
+ syslog(LOG_WARNING,
+ "<%s> ifname not found (idx=%d)",
+ __func__, ifm->ifm_index);
+ if (ifi_new)
+ free(ifi);
+ continue;
+ }
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR,
+ "<%s> socket() failed.", __func__);
+ if (ifi_new)
+ free(ifi);
+ continue;
+ }
+
+ /* MTU */
+ ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu;
+ if (ifi->ifi_phymtu == 0) {
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_addr.sa_family = AF_INET6;
+ strncpy(ifr.ifr_name, ifi->ifi_ifname,
+ sizeof(ifr.ifr_name));
+ error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr);
+ if (error) {
+ close(s);
+ syslog(LOG_ERR,
+ "<%s> ioctl() failed.",
+ __func__);
+ if (ifi_new)
+ free(ifi);
+ continue;
+ }
+ ifi->ifi_phymtu = ifr.ifr_mtu;
+ if (ifi->ifi_phymtu == 0) {
+ syslog(LOG_WARNING,
+ "<%s> no interface mtu info"
+ " on %s. %d will be used.",
+ __func__, ifi->ifi_ifname,
+ IPV6_MMTU);
+ ifi->ifi_phymtu = IPV6_MMTU;
+ }
+ }
+ close(s);
+
+ /* ND flags */
+ error = update_ifinfo_nd_flags(ifi);
+ if (error) {
+ if (ifi_new)
+ free(ifi);
+ continue;
+ }
+
+ /* SDL */
+ sa = (struct sockaddr *)(ifm + 1);
+ get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
+ if ((sa = rti_info[RTAX_IFP]) != NULL) {
+ if (sa->sa_family == AF_LINK) {
+ memcpy(&ifi->ifi_sdl,
+ (struct sockaddr_dl *)sa,
+ sizeof(ifi->ifi_sdl));
+ }
+ } else
+ memset(&ifi->ifi_sdl, 0,
+ sizeof(ifi->ifi_sdl));
+
+ /* flags */
+ ifi->ifi_flags = ifm->ifm_flags;
+
+ /* type */
+ ifi->ifi_type = ifm->ifm_type;
} 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);
- exit (1);
+ syslog(LOG_ERR,
+ "out of sync parsing NET_RT_IFLIST\n"
+ "expected %d, got %d\n msglen = %d\n",
+ RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen);
+ exit(1);
}
- for (ifam = (struct ifa_msghdr *)
- ((char *)ifm + ifm->ifm_msglen);
- ifam < (struct ifa_msghdr *)lim;
- ifam = (struct ifa_msghdr *)
- ((char *)ifam + ifam->ifam_msglen)) {
- /* 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);
- return;
- }
- if (ifam->ifam_type != RTM_NEWADDR)
- break;
+
+ if (ifi_new) {
+ syslog(LOG_DEBUG,
+ "<%s> adding %s(idx=%d) to ifilist",
+ __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
+ TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
}
- ifm = (struct if_msghdr *)ifam;
}
+ free(msg);
+
+ if (mcastif != NULL) {
+ error = sock_mc_rr_update(&sock, mcastif);
+ if (error)
+ exit(1);
+ }
+
+ return (ifi);
}
-void
-init_iflist(void)
+static struct if_msghdr *
+get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim)
{
+ struct ifa_msghdr *ifam;
+
+ for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen);
+ ifam < (struct ifa_msghdr *)lim;
+ ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) {
+ if (!ifam->ifam_msglen) {
+ syslog(LOG_WARNING,
+ "<%s> ifa_msglen is 0", __func__);
+ return (NULL);
+ }
+ if (ifam->ifam_type != RTM_NEWADDR)
+ break;
+ }
+
+ return ((struct if_msghdr *)ifam);
+}
+
+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);
+}
+
+
+int
+sock_mc_join(struct sockinfo *s, int ifindex)
+{
+ struct ipv6_mreq mreq;
+ char ifname[IFNAMSIZ];
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (ifindex == 0)
+ return (1);
+
+ /*
+ * join all routers multicast address on each advertising
+ * interface.
+ */
+ memset(&mreq, 0, sizeof(mreq));
+ /* XXX */
+ memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
+ &sin6_linklocal_allrouters.sin6_addr,
+ sizeof(mreq.ipv6mr_multiaddr.s6_addr));
+
+ mreq.ipv6mr_interface = ifindex;
+ if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
+ sizeof(mreq)) < 0) {
+ syslog(LOG_ERR,
+ "<%s> IPV6_JOIN_GROUP(link) on %s: %s",
+ __func__, if_indextoname(ifindex, ifname),
+ strerror(errno));
+ return (1);
+ }
syslog(LOG_DEBUG,
- "<%s> generate iflist.", __func__);
+ "<%s> %s: join link-local all-routers MC group",
+ __func__, if_indextoname(ifindex, ifname));
- if (ifblock) {
- free(ifblock);
- ifblock_size = 0;
+ return (0);
+}
+
+int
+sock_mc_leave(struct sockinfo *s, int ifindex)
+{
+ struct ipv6_mreq mreq;
+ char ifname[IFNAMSIZ];
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (ifindex == 0)
+ return (1);
+
+ /*
+ * join all routers multicast address on each advertising
+ * interface.
+ */
+
+ memset(&mreq, 0, sizeof(mreq));
+ /* XXX */
+ memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
+ &sin6_linklocal_allrouters.sin6_addr,
+ sizeof(mreq.ipv6mr_multiaddr.s6_addr));
+
+ mreq.ipv6mr_interface = ifindex;
+ if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,
+ sizeof(mreq)) < 0) {
+ syslog(LOG_ERR,
+ "<%s> IPV6_JOIN_LEAVE(link) on %s: %s",
+ __func__, if_indextoname(ifindex, ifname),
+ strerror(errno));
+ return (1);
+ }
+ syslog(LOG_DEBUG,
+ "<%s> %s: leave link-local all-routers MC group",
+ __func__, if_indextoname(ifindex, ifname));
+
+ return (0);
+}
+
+int
+sock_mc_rr_update(struct sockinfo *s, char *mif)
+{
+ struct ipv6_mreq mreq;
+
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (mif == NULL)
+ return (1);
+ /*
+ * When attending router renumbering, join all-routers site-local
+ * multicast group.
+ */
+ /* XXX */
+ memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
+ &sin6_sitelocal_allrouters.sin6_addr,
+ sizeof(mreq.ipv6mr_multiaddr.s6_addr));
+ if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) {
+ syslog(LOG_ERR,
+ "<%s> invalid interface: %s",
+ __func__, mif);
+ return (1);
+ }
+
+ if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &mreq, sizeof(mreq)) < 0) {
+ syslog(LOG_ERR,
+ "<%s> IPV6_JOIN_GROUP(site) on %s: %s",
+ __func__, mif, strerror(errno));
+ return (1);
}
- if (iflist)
- free(iflist);
- /* get iflist block from kernel */
- get_iflist(&ifblock, &ifblock_size);
- /* make list of pointers to each if_msghdr */
- parse_iflist(&iflist, ifblock, ifblock_size);
+ syslog(LOG_DEBUG,
+ "<%s> %s: join site-local all-routers MC group",
+ __func__, mif);
+
+ return (0);
}
diff --git a/usr.sbin/rtadvd/if.h b/usr.sbin/rtadvd/if.h
index 8728e19..5479216 100644
--- a/usr.sbin/rtadvd/if.h
+++ b/usr.sbin/rtadvd/if.h
@@ -30,29 +30,32 @@
* SUCH DAMAGE.
*/
-#define RTADV_TYPE2BITMASK(type) (0x1 << type)
+#define UPDATE_IFINFO_ALL 0
-extern struct if_msghdr **iflist;
-extern size_t ifblock_size;
-extern char *ifblock;
+struct sockinfo {
+ int si_fd;
+ const char *si_name;
+};
+
+extern struct sockinfo sock;
+extern struct sockinfo rtsock;
+extern struct sockinfo ctrlsock;
-struct nd_opt_hdr;
-struct sockaddr_dl *if_nametosdl(char *);
-int if_getmtu(char *);
-int if_getflags(int, int);
int lladdropt_length(struct sockaddr_dl *);
void lladdropt_fill(struct sockaddr_dl *, struct nd_opt_hdr *);
int rtbuf_len(void);
char *get_next_msg(char *, char *, int, size_t *, int);
struct in6_addr *get_addr(char *);
int get_rtm_ifindex(char *);
-int get_ifm_ifindex(char *);
-int get_ifam_ifindex(char *);
-int get_ifm_flags(char *);
int get_prefixlen(char *);
int prefixlen(u_char *, u_char *);
-int rtmsg_type(char *);
-int ifmsg_type(char *);
-int rtmsg_len(char *);
-int ifmsg_len(char *);
-void init_iflist(void);
+
+struct ifinfo *update_ifinfo(struct ifilist_head_t *, int);
+int update_ifinfo_nd_flags(struct ifinfo *);
+struct ifinfo *update_persist_ifinfo(struct ifilist_head_t *,
+ const char *);
+
+int sock_mc_join(struct sockinfo *, int);
+int sock_mc_leave(struct sockinfo *, int);
+int sock_mc_rr_update(struct sockinfo *, char *);
+int getinet6sysctl(int);
diff --git a/usr.sbin/rtadvd/pathnames.h b/usr.sbin/rtadvd/pathnames.h
index 13329da..248ee19 100644
--- a/usr.sbin/rtadvd/pathnames.h
+++ b/usr.sbin/rtadvd/pathnames.h
@@ -2,6 +2,5 @@
/* $FreeBSD$ */
#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
-#define _PATH_RTADVDDUMP "/var/run/rtadvd.dump"
#define _PATH_RTADVDPID "/var/run/rtadvd.pid"
-
+#define _PATH_CTRL_SOCK "/var/run/rtadvd.sock"
diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c
index 660ed53..3e36311 100644
--- a/usr.sbin/rtadvd/rrenum.c
+++ b/usr.sbin/rtadvd/rrenum.c
@@ -36,6 +36,7 @@
#include <sys/sysctl.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
@@ -142,6 +143,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
{
struct rr_pco_use *rpu, *rpulim;
struct rainfo *rai;
+ struct ifinfo *ifi;
struct prefix *pfx;
rpu = (struct rr_pco_use *)(rpm + 1);
@@ -207,8 +209,10 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) &&
rpm->rpm_matchlen == rpu->rpu_uselen &&
rpu->rpu_uselen == rpu->rpu_keeplen) {
- if ((rai = if_indextorainfo(ifindex)) == NULL)
+ ifi = if_indextoifinfo(ifindex);
+ if (ifi == NULL || ifi->ifi_rainfo == NULL)
continue; /* non-advertising IF */
+ rai = ifi->ifi_rainfo;
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
struct timeval now;
@@ -250,7 +254,8 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
{
int ifindex = 0;
struct in6_rrenumreq irr;
-
+ struct ifinfo *ifi;
+
if ((rr_pco_check(len, rpm) != 0))
return (1);
@@ -270,12 +275,18 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix;
while (if_indextoname(++ifindex, irr.irr_name)) {
+ ifi = if_indextoifinfo(ifindex);
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s> ifindex not found.",
+ __func__);
+ return (1);
+ }
/*
* 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)
+ (ifi->ifi_flags & IFF_UP) == 0)
continue;
/* TODO: interface scope check */
do_use_prefix(len, rpm, &irr, ifindex);
@@ -305,8 +316,7 @@ do_rr(int len, struct icmp6_router_renum *rr)
cp = (char *)(rr + 1);
len -= sizeof(struct icmp6_router_renum);
- /* get iflist block from kernel again, to get up-to-date information */
- init_iflist();
+ update_ifinfo(&ifilist, UPDATE_IFINFO_ALL);
while (cp < lim) {
int rpmlen;
diff --git a/usr.sbin/rtadvd/rtadvd.8 b/usr.sbin/rtadvd/rtadvd.8
index b41f7c06..b2e6670 100644
--- a/usr.sbin/rtadvd/rtadvd.8
+++ b/usr.sbin/rtadvd/rtadvd.8
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 22, 2010
+.Dd July 14, 2011
.Dt RTADVD 8
.Os
.Sh NAME
@@ -39,7 +39,6 @@
.Nm
.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 ...
@@ -129,13 +128,6 @@ Even more debugging information is printed.
.It Fl f
Foreground mode (useful when debugging).
Log messages will be dumped to stderr when this option is specified.
-.It Fl F
-Specify an alternative file in which to dump internal states when
-.Nm
-receives signal
-.Dv SIGUSR1 .
-The default is
-.Pa /var/run/rtadvd.dump .
.It Fl M
Specify an interface to join the all-routers site-local multicast group.
By default,
@@ -160,14 +152,6 @@ Do not add or delete prefixes dynamically.
Only statically configured prefixes, if any, will be advertised.
.El
.Pp
-Upon receipt of signal
-.Dv SIGUSR1 ,
-.Nm
-will dump the current internal state into
-.Pa /var/run/rtadvd.dump
-or the file specified with option
-.Fl F .
-.Pp
Use
.Dv SIGHUP
to reload the configuration file
@@ -196,10 +180,6 @@ to all the interfaces
The default configuration file.
.It Pa /var/run/rtadvd.pid
The default process ID file.
-.It Pa /var/run/rtadvd.dump
-The default file in which
-.Nm
-dumps its internal state.
.El
.Sh EXIT STATUS
.Ex -std
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c
index 72fb46e..d67280a 100644
--- a/usr.sbin/rtadvd/rtadvd.c
+++ b/usr.sbin/rtadvd/rtadvd.c
@@ -3,6 +3,7 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,12 +37,14 @@
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/queue.h>
+#include <sys/stat.h>
#include <sys/sysctl.h>
#include <net/if.h>
+#include <net/if_types.h>
#include <net/if_media.h>
-#include <net/route.h>
#include <net/if_dl.h>
+#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@@ -60,6 +63,7 @@
#include <errno.h>
#include <libutil.h>
#include <netdb.h>
+#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
@@ -67,41 +71,44 @@
#include <poll.h>
#endif
+#include "pathnames.h"
#include "rtadvd.h"
+#include "if.h"
#include "rrenum.h"
#include "advcap.h"
+#include "timer_subr.h"
#include "timer.h"
-#include "if.h"
#include "config.h"
-#include "dump.h"
-#include "pathnames.h"
+#include "control.h"
+#include "control_server.h"
+
+#define RTADV_TYPE2BITMASK(type) (0x1 << type)
struct msghdr rcvmhdr;
static u_char *rcvcmsgbuf;
static size_t rcvcmsgbuflen;
static u_char *sndcmsgbuf = NULL;
static size_t sndcmsgbuflen;
-volatile sig_atomic_t do_dump;
-volatile sig_atomic_t do_die;
-volatile sig_atomic_t do_reload;
struct msghdr sndmhdr;
struct iovec rcviov[2];
struct iovec sndiov[2];
struct sockaddr_in6 rcvfrom;
-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;
+
+#ifdef HAVE_POLL_H
+#define PFD_RAWSOCK 0
+#define PFD_RTSOCK 1
+#define PFD_CSOCK 2
+#define PFD_MAX 3
+#endif
struct railist_head_t railist =
TAILQ_HEAD_INITIALIZER(railist);
+struct ifilist_head_t ifilist =
+ TAILQ_HEAD_INITIALIZER(ifilist);
struct nd_optlist {
TAILQ_ENTRY(nd_optlist) nol_next;
@@ -144,30 +151,10 @@ u_int32_t ndopt_flags[] = {
[ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL,
};
-struct sockaddr_in6 sin6_linklocal_allnodes = {
- .sin6_len = sizeof(sin6_linklocal_allnodes),
- .sin6_family = AF_INET6,
- .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
-};
-
-struct sockaddr_in6 sin6_linklocal_allrouters = {
- .sin6_len = sizeof(sin6_linklocal_allrouters),
- .sin6_family = AF_INET6,
- .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
-};
-
-struct sockaddr_in6 sin6_sitelocal_allrouters = {
- .sin6_len = sizeof(sin6_sitelocal_allrouters),
- .sin6_family = AF_INET6,
- .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT,
-};
-
-static void set_reload(int);
-static void set_die(int);
static void die(void);
-static void sock_open(void);
-static void rtsock_open(void);
-static void rtadvd_input(void);
+static void sock_open(struct sockinfo *);
+static void rtsock_open(struct sockinfo *);
+static void rtadvd_input(struct sockinfo *);
static void rs_input(int, struct nd_router_solicit *,
struct in6_pktinfo *, struct sockaddr_in6 *);
static void ra_input(int, struct nd_router_advert *,
@@ -177,18 +164,15 @@ static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
static int nd6_options(struct nd_opt_hdr *, int,
union nd_opt *, u_int32_t);
static void free_ndopts(union nd_opt *);
-static void rtmsg_input(void);
-static void rtadvd_set_dump_file(int);
+static void rtmsg_input(struct sockinfo *);
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(int argc, char *argv[])
{
#ifdef HAVE_POLL_H
- struct pollfd set[2];
+ struct pollfd set[PFD_MAX];
#else
fd_set *fdsetp, *selectfdp;
int fdmasks;
@@ -197,14 +181,18 @@ main(int argc, char *argv[])
struct timeval *timeout;
int i, ch;
int fflag = 0, logopt;
+ int error;
pid_t pid, otherpid;
/* get command line options and arguments */
- while ((ch = getopt(argc, argv, "c:dDfF:M:p:Rs")) != -1) {
+ while ((ch = getopt(argc, argv, "c:C:dDfM:p:Rs")) != -1) {
switch (ch) {
case 'c':
conffile = optarg;
break;
+ case 'C':
+ ctrlsock.si_name = optarg;
+ break;
case 'd':
dflag++;
break;
@@ -229,9 +217,6 @@ main(int argc, char *argv[])
case 'p':
pidfilename = optarg;
break;
- case 'F':
- dumpfilename = optarg;
- break;
}
}
argc -= optind;
@@ -239,7 +224,7 @@ main(int argc, char *argv[])
if (argc == 0) {
fprintf(stderr,
"usage: rtadvd [-dDfRs] [-c conffile] "
- "[-F dumpfile] [-M ifname] "
+ "[-C ctrlsockname] [-M ifname] "
"[-p pidfile] interfaces...\n");
exit(1);
}
@@ -268,13 +253,6 @@ main(int argc, char *argv[])
srandom((u_long)time(NULL));
#endif
#endif
- /* get iflist block from kernel */
- init_iflist();
- ifl_names = argv;
- ifl_len = argc;
-
- loadconfig(argv, argc);
-
pfh = pidfile_open(pidfilename, 0600, &otherpid);
if (pfh == NULL) {
if (errno == EEXIST)
@@ -284,33 +262,46 @@ main(int argc, char *argv[])
"<%s> failed to open the pid log file, run anyway.",
__func__);
}
-
if (!fflag)
daemon(1, 0);
- sock_open();
+ sock_open(&sock);
+
+ update_ifinfo(&ifilist, UPDATE_IFINFO_ALL);
+ for (i = 0; i < argc; i++)
+ update_persist_ifinfo(&ifilist, argv[i]);
+
+ csock_open(&ctrlsock, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (ctrlsock.si_fd == -1) {
+ syslog(LOG_ERR, "<%s> cannot open control socket", __func__);
+ exit(1);
+ }
/* record the current PID */
pid = getpid();
pidfile_write(pfh);
#ifdef HAVE_POLL_H
- set[0].fd = sock;
- set[0].events = POLLIN;
+ set[PFD_RAWSOCK].fd = sock.si_fd;
+ set[PFD_RAWSOCK].events = POLLIN;
if (sflag == 0) {
- rtsock_open();
- set[1].fd = rtsock;
- set[1].events = POLLIN;
+ rtsock_open(&rtsock);
+ set[PFD_RTSOCK].fd = rtsock.si_fd;
+ set[PFD_RTSOCK].events = POLLIN;
} else
- set[1].fd = -1;
+ set[PFD_RTSOCK].fd = -1;
+ set[PFD_CSOCK].fd = ctrlsock.si_fd;
+ set[PFD_CSOCK].events = POLLIN;
#else
- maxfd = sock;
+ maxfd = sock.si_fd;
if (sflag == 0) {
rtsock_open();
- if (rtsock > sock)
- maxfd = rtsock;
+ if (rtsock.si_fd > sock.si_fd)
+ maxfd = rtsock.si_fd;
} else
- rtsock = -1;
+ rtsock.si_fd = -1;
+ if (maxfd < ctrlsock.si_fd)
+ maxfd = ctrlsock.si_fd;
fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
if ((fdsetp = malloc(fdmasks)) == NULL) {
@@ -322,33 +313,41 @@ main(int argc, char *argv[])
/*NOTREACHED*/
}
memset(fdsetp, 0, fdmasks);
- FD_SET(sock, fdsetp);
- if (rtsock >= 0)
- FD_SET(rtsock, fdsetp);
+ FD_SET(sock.si_fd, fdsetp);
+ if (rtsock.si_fd >= 0)
+ FD_SET(rtsock.si_fd, fdsetp);
+ FD_SET(ctrlsock.si_fd, fdsetp);
#endif
- signal(SIGTERM, set_die);
- signal(SIGUSR1, rtadvd_set_dump_file);
- signal(SIGHUP, set_reload);
+ signal(SIGTERM, set_do_die);
+ signal(SIGINT, set_do_die);
+ signal(SIGHUP, set_do_reload);
+
+ error = csock_listen(&ctrlsock);
+ if (error) {
+ syslog(LOG_ERR, "<%s> listen failed", __func__);
+ exit(1);
+ }
+
+ /* load configuration file */
+ set_do_reload(0);
while (1) {
#ifndef HAVE_POLL_H
memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */
#endif
- if (do_dump) { /* SIGUSR1 */
- do_dump = 0;
- rtadvd_dump_file(dumpfilename);
- }
-
- if (do_die) {
+ if (do_die())
die();
- /*NOTREACHED*/
- }
- if (do_reload) {
- loadconfig(argv, argc);
- do_reload = 0;
+ if (do_reload()) {
+ reset_do_reload();
+ loadconfig_ifname(NULL);
+ syslog(LOG_INFO,
+ "configuration file reloaded.");
}
+ /* timeout handler update for active interfaces */
+ rtadvd_update_timeout_handler();
+
/* timer expiration check and reset the timer */
timeout = rtadvd_check_timer();
@@ -364,8 +363,9 @@ main(int argc, char *argv[])
__func__);
}
#ifdef HAVE_POLL_H
- if ((i = poll(set, 2, timeout ? (timeout->tv_sec * 1000 +
- timeout->tv_usec / 1000) : INFTIM)) < 0)
+ if ((i = poll(set, sizeof(set)/sizeof(set[0]),
+ timeout ? (timeout->tv_sec * 1000 +
+ timeout->tv_usec / 1000) : INFTIM)) < 0)
#else
if ((i = select(maxfd + 1, selectfdp, NULL, NULL,
timeout)) < 0)
@@ -380,51 +380,35 @@ main(int argc, char *argv[])
if (i == 0) /* timeout */
continue;
#ifdef HAVE_POLL_H
- if (rtsock != -1 && set[1].revents & POLLIN)
+ if (rtsock.si_fd != -1 && set[PFD_RTSOCK].revents & POLLIN)
+#else
+ if (rtsock.si_fd != -1 && FD_ISSET(rtsock.si_fd, selectfdp))
+#endif
+ rtmsg_input(&rtsock);
+#ifdef HAVE_POLL_H
+ if (set[PFD_RAWSOCK].revents & POLLIN)
#else
- if (rtsock != -1 && FD_ISSET(rtsock, selectfdp))
+ if (FD_ISSET(sock.si_fd, selectfdp))
#endif
- rtmsg_input();
+ rtadvd_input(&sock);
#ifdef HAVE_POLL_H
- if (set[0].revents & POLLIN)
+ if (set[PFD_CSOCK].revents & POLLIN)
#else
- if (FD_ISSET(sock, selectfdp))
+ if (FD_ISSET(ctrlsock.si_fd, selectfdp))
#endif
- rtadvd_input();
+ {
+ int fd;
+
+ fd = csock_accept(&ctrlsock);
+ if (fd == -1)
+ syslog(LOG_ERR, "<%s> accept", __func__);
+ else
+ cmsg_handler_server(fd);
+ }
}
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(int sig __unused)
-{
-
- do_dump = 1;
-}
-
-static void
-set_reload(int sig __unused)
-{
-
- do_reload = 1;
-}
-
-static void
-set_die(int sig __unused)
-{
-
- do_die = 1;
-}
-
static void
die(void)
{
@@ -446,35 +430,48 @@ die(void)
make_packet(rai);
}
for (i = 0; i < retrans; i++) {
+ syslog(LOG_INFO, "<%s> final RA transmission #%d/%d\n",
+ __func__, i, retrans - i);
TAILQ_FOREACH(rai, &railist, rai_next)
- ra_output(rai);
+ if (rai->rai_ifinfo->ifi_state
+ == IFI_STATE_CONFIGURED)
+ ra_output(rai);
+ syslog(LOG_INFO, "<%s> waiting for %d sec.\n",
+ __func__, MIN_DELAY_BETWEEN_RAS);
sleep(MIN_DELAY_BETWEEN_RAS);
}
pidfile_remove(pfh);
-
+ csock_close(&ctrlsock);
+
exit(0);
}
static void
-rtmsg_input(void)
+rtmsg_input(struct sockinfo *s)
{
int n, type, ifindex = 0, plen;
size_t len;
char msg[2048], *next, *lim;
u_char ifname[IFNAMSIZ];
struct if_announcemsghdr *ifan;
+ struct rt_msghdr *rtm;
struct prefix *pfx;
struct rainfo *rai;
struct in6_addr *addr;
+ struct ifinfo *ifi;
char addrbuf[INET6_ADDRSTRLEN];
int prefixchange = 0;
- int error;
- n = read(rtsock, msg, sizeof(msg));
+ if (s == NULL) {
+ syslog(LOG_ERR, "<%s> internal error", __func__);
+ exit(1);
+ }
+ n = read(s->si_fd, msg, sizeof(msg));
+ rtm = (struct rt_msghdr *)msg;
syslog(LOG_DEBUG, "<%s> received a routing message "
- "(type = %d, len = %d)", __func__, rtmsg_type(msg), n);
+ "(type = %d, len = %d)", __func__, rtm->rtm_type, n);
- if (n > rtmsg_len(msg)) {
+ if (n > rtm->rtm_msglen) {
/*
* This usually won't happen for messages received on
* a routing socket.
@@ -483,10 +480,10 @@ rtmsg_input(void)
"<%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));
+ __func__, n, rtm->rtm_msglen);
#if 0
/* adjust length */
- n = rtmsg_len(msg);
+ n = rtm->rtm_msglen;
#endif
}
@@ -503,14 +500,7 @@ rtmsg_input(void)
RTADV_TYPE2BITMASK(RTM_IFANNOUNCE));
if (len == 0)
break;
- if (((struct rt_msghdr *)next)->rtm_version != RTM_VERSION) {
- syslog(LOG_ERR,
- "<%s> RTM_VERSION mismatch (%d != %d).",
- __func__, ((struct rt_msghdr *)next)->rtm_version,
- RTM_VERSION);
- continue;
- }
- type = rtmsg_type(next);
+ type = ((struct rt_msghdr *)next)->rtm_type;
switch (type) {
case RTM_ADD:
case RTM_DELETE:
@@ -518,10 +508,10 @@ rtmsg_input(void)
break;
case RTM_NEWADDR:
case RTM_DELADDR:
- ifindex = get_ifam_ifindex(next);
+ ifindex = (int)((struct ifa_msghdr *)next)->ifam_index;
break;
case RTM_IFINFO:
- ifindex = get_ifm_ifindex(next);
+ ifindex = (int)((struct if_msghdr *)next)->ifm_index;
break;
case RTM_IFANNOUNCE:
ifan = (struct if_announcemsghdr *)next;
@@ -538,32 +528,20 @@ rtmsg_input(void)
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);
+ syslog(LOG_INFO,
+ "<%s>: interface added (idx=%d)",
+ __func__, ifan->ifan_index);
+ update_ifinfo(&ifilist, ifan->ifan_index);
+ loadconfig_index(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);
+ syslog(LOG_INFO,
+ "<%s>: interface removed (idx=%d)",
+ __func__, ifan->ifan_index);
+ rmconfig(ifan->ifan_index);
+ update_ifinfo(&ifilist, ifan->ifan_index);
break;
}
continue;
@@ -575,26 +553,31 @@ rtmsg_input(void)
if_indextoname(ifindex, ifname));
continue;
}
-
- if ((rai = if_indextorainfo(ifindex)) == NULL) {
+ ifi = if_indextoifinfo(ifindex);
+ if (ifi == NULL) {
syslog(LOG_DEBUG,
- "<%s> route changed on "
- "non advertising interface(%s)",
- __func__,
- if_indextoname(ifindex, ifname));
+ "<%s> ifinfo not found for idx=%d. Why?",
+ __func__, ifindex);
+ continue;
+ }
+ rai = ifi->ifi_rainfo;
+ if (rai == NULL) {
+ syslog(LOG_DEBUG,
+ "<%s> route changed on "
+ "non advertising interface(%s)",
+ __func__, ifi->ifi_ifname);
continue;
}
- oldifflags = iflist[ifindex]->ifm_flags;
+
+ oldifflags = ifi->ifi_flags;
+ /* init ifflags because it may have changed */
+ update_ifinfo(&ifilist, ifindex);
switch (type) {
case RTM_ADD:
- /* init ifflags because it may have changed */
- iflist[ifindex]->ifm_flags =
- if_getflags(ifindex, iflist[ifindex]->ifm_flags);
-
if (sflag)
break; /* we aren't interested in prefixes */
-
+
addr = get_addr(msg);
plen = get_prefixlen(msg);
/* sanity check for plen */
@@ -623,17 +606,13 @@ rtmsg_input(void)
inet_ntop(AF_INET6, addr,
(char *)addrbuf,
sizeof(addrbuf)),
- plen, rai->rai_ifname);
+ plen, ifi->ifi_ifname);
break;
}
make_prefix(rai, ifindex, addr, plen);
prefixchange = 1;
break;
case RTM_DELETE:
- /* init ifflags because it may have changed */
- iflist[ifindex]->ifm_flags =
- if_getflags(ifindex, iflist[ifindex]->ifm_flags);
-
if (sflag)
break;
@@ -655,7 +634,7 @@ rtmsg_input(void)
"but it was not in list",
__func__, inet_ntop(AF_INET6, addr,
(char *)addrbuf, sizeof(addrbuf)),
- plen, rai->rai_ifname);
+ plen, ifi->ifi_ifname);
break;
}
invalidate_prefix(pfx);
@@ -663,12 +642,7 @@ rtmsg_input(void)
break;
case RTM_NEWADDR:
case RTM_DELADDR:
- /* init ifflags because it may have changed */
- iflist[ifindex]->ifm_flags =
- if_getflags(ifindex, iflist[ifindex]->ifm_flags);
- break;
case RTM_IFINFO:
- iflist[ifindex]->ifm_flags = get_ifm_flags(next);
break;
default:
/* should not reach here */
@@ -681,17 +655,17 @@ rtmsg_input(void)
/* check if an interface flag is changed */
if ((oldifflags & IFF_UP) && /* UP to DOWN */
- !(iflist[ifindex]->ifm_flags & IFF_UP)) {
+ !(ifi->ifi_flags & IFF_UP)) {
syslog(LOG_INFO,
"<%s> interface %s becomes down. stop timer.",
- __func__, rai->rai_ifname);
+ __func__, ifi->ifi_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)) {
+ (ifi->ifi_flags & IFF_UP)) {
syslog(LOG_INFO,
"<%s> interface %s becomes up. restart timer.",
- __func__, rai->rai_ifname);
+ __func__, ifi->ifi_ifname);
rai->rai_initcounter = 0; /* reset the counter */
rai->rai_waiting = 0; /* XXX */
@@ -701,7 +675,7 @@ rtmsg_input(void)
rtadvd_set_timer(&rai->rai_timer->rat_tm,
rai->rai_timer);
} else if (prefixchange &&
- (iflist[ifindex]->ifm_flags & IFF_UP)) {
+ (ifi->ifi_flags & IFF_UP)) {
/*
* An advertised prefix has been added or invalidated.
* Will notice the change in a short delay.
@@ -715,7 +689,7 @@ rtmsg_input(void)
}
void
-rtadvd_input(void)
+rtadvd_input(struct sockinfo *s)
{
ssize_t i;
int *hlimp = NULL;
@@ -728,14 +702,21 @@ rtadvd_input(void)
struct in6_pktinfo *pi = NULL;
u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
struct in6_addr dst = in6addr_any;
+ struct ifinfo *ifi;
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (s == NULL) {
+ syslog(LOG_ERR, "<%s> internal error", __func__);
+ exit(1);
+ }
/*
* Get message. We reset msg_controllen since the field could
* be modified if we had received a message before setting
* receive options.
*/
rcvmhdr.msg_controllen = rcvcmsgbuflen;
- if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0)
+ if ((i = recvmsg(s->si_fd, &rcvmhdr, 0)) < 0)
return;
/* extract optional information via Advanced API */
@@ -771,13 +752,12 @@ rtadvd_input(void)
* If we happen to receive data on an interface which is now gone
* or down, just discard the data.
*/
- if (iflist[pi->ipi6_ifindex] == NULL ||
- (iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) {
+ ifi = if_indextoifinfo(pi->ipi6_ifindex);
+ if (ifi == NULL || !(ifi->ifi_flags & IFF_UP)) {
syslog(LOG_INFO,
"<%s> received data on a disabled interface (%s)",
__func__,
- (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" :
- if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ (ifi == NULL) ? "[gone]" : ifi->ifi_ifname);
return;
}
@@ -888,7 +868,7 @@ rtadvd_input(void)
ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom);
break;
case ICMP6_ROUTER_RENUMBERING:
- if (accept_rr == 0) {
+ if (mcastif == NULL) {
syslog(LOG_ERR, "<%s> received a router renumbering "
"message, but not allowed to be accepted",
__func__);
@@ -920,6 +900,7 @@ rs_input(int len, struct nd_router_solicit *rs,
u_char ifnamebuf[IFNAMSIZ];
union nd_opt ndopts;
struct rainfo *rai;
+ struct ifinfo *ifi;
struct soliciter *sol;
syslog(LOG_DEBUG,
@@ -956,10 +937,14 @@ rs_input(int len, struct nd_router_solicit *rs,
goto done;
}
- TAILQ_FOREACH(rai, &railist, rai_next)
- if (pi->ipi6_ifindex == (unsigned int)rai->rai_ifindex)
- break;
-
+ ifi = if_indextoifinfo(pi->ipi6_ifindex);
+ if (ifi == NULL) {
+ syslog(LOG_INFO,
+ "<%s> if (idx=%d) not found. Why?",
+ __func__, pi->ipi6_ifindex);
+ goto done;
+ }
+ rai = ifi->ifi_rainfo;
if (rai == NULL) {
syslog(LOG_INFO,
"<%s> RS received on non advertising interface(%s)",
@@ -968,7 +953,7 @@ rs_input(int len, struct nd_router_solicit *rs,
goto done;
}
- rai->rai_rsinput++; /* increment statistics */
+ rai->rai_ifinfo->ifi_rsinput++;
/*
* Decide whether to send RA according to the rate-limit
@@ -1046,56 +1031,28 @@ set_short_delay(struct rainfo *rai)
static int
check_accept_rtadv(int idx)
{
- struct in6_ndireq nd;
- u_char ifname[IFNAMSIZ];
- int s6;
+ struct ifinfo *ifi;
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);
+
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (ifi->ifi_ifindex == idx)
+ break;
}
- if ((if_indextoname(idx, ifname)) == NULL) {
+ if (ifi == NULL) {
syslog(LOG_ERR,
- "<%s> ifindex->ifname failed (idx=%d).",
+ "<%s> if (idx=%d) not found. Why?",
__func__, idx);
- close(s6);
return (0);
}
- memset(&nd, 0, sizeof(nd));
- strncpy(nd.ifname, ifname, sizeof(nd.ifname));
- error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
+ error =update_ifinfo_nd_flags(ifi);
if (error) {
syslog(LOG_ERR,
- "<%s> ioctl(SIOCGIFINFO_IN6) failed for idx=%d.",
+ "<%s> nd6 flags failed (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);
+ return (0);
}
- else
- return (value);
+
+ return (ifi->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV);
}
static void
@@ -1103,6 +1060,7 @@ ra_input(int len, struct nd_router_advert *nra,
struct in6_pktinfo *pi, struct sockaddr_in6 *from)
{
struct rainfo *rai;
+ struct ifinfo *ifi;
u_char ntopbuf[INET6_ADDRSTRLEN];
u_char ifnamebuf[IFNAMSIZ];
union nd_opt ndopts;
@@ -1115,16 +1073,6 @@ ra_input(int len, struct nd_router_advert *nra,
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;
- }
-
/* ND option check */
memset(&ndopts, 0, sizeof(ndopts));
error = nd6_options((struct nd_opt_hdr *)(nra + 1),
@@ -1144,8 +1092,8 @@ ra_input(int len, struct nd_router_advert *nra,
/*
* RA consistency check according to RFC 4861 6.2.7
*/
- rai = if_indextorainfo(pi->ipi6_ifindex);
- if (rai == NULL) {
+ ifi = if_indextoifinfo(pi->ipi6_ifindex);
+ if (ifi->ifi_rainfo == NULL) {
syslog(LOG_INFO,
"<%s> received RA from %s on non-advertising"
" interface(%s)",
@@ -1155,15 +1103,18 @@ ra_input(int len, struct nd_router_advert *nra,
ifnamebuf));
goto done;
}
- rai->rai_rainput++; /* increment statistics */
-
+ rai = ifi->ifi_rainfo;
+ ifi->ifi_rainput++;
+ syslog(LOG_DEBUG, "<%s> ifi->ifi_rainput = %llu\n", __func__,
+ ifi->ifi_rainput);
+
/* Cur Hop Limit value */
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->rai_ifname, nra->nd_ra_curhoplimit,
+ __func__, ifi->ifi_ifname, nra->nd_ra_curhoplimit,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), rai->rai_hoplimit);
inconsistent++;
@@ -1174,7 +1125,7 @@ ra_input(int len, struct nd_router_advert *nra,
syslog(LOG_INFO,
"<%s> M flag inconsistent on %s:"
" %s from %s, %s from us",
- __func__, rai->rai_ifname, on_off[!rai->rai_managedflg],
+ __func__, ifi->ifi_ifname, on_off[!rai->rai_managedflg],
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), on_off[rai->rai_managedflg]);
inconsistent++;
@@ -1185,7 +1136,7 @@ ra_input(int len, struct nd_router_advert *nra,
syslog(LOG_INFO,
"<%s> O flag inconsistent on %s:"
" %s from %s, %s from us",
- __func__, rai->rai_ifname, on_off[!rai->rai_otherflg],
+ __func__, ifi->ifi_ifname, on_off[!rai->rai_otherflg],
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), on_off[rai->rai_otherflg]);
inconsistent++;
@@ -1197,7 +1148,7 @@ ra_input(int len, struct nd_router_advert *nra,
syslog(LOG_INFO,
"<%s> ReachableTime inconsistent on %s:"
" %d from %s, %d from us",
- __func__, rai->rai_ifname, reachabletime,
+ __func__, ifi->ifi_ifname, reachabletime,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), rai->rai_reachabletime);
inconsistent++;
@@ -1209,7 +1160,7 @@ ra_input(int len, struct nd_router_advert *nra,
syslog(LOG_INFO,
"<%s> RetranceTimer inconsistent on %s:"
" %d from %s, %d from us",
- __func__, rai->rai_ifname, retranstimer,
+ __func__, ifi->ifi_ifname, retranstimer,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), rai->rai_retranstimer);
inconsistent++;
@@ -1221,7 +1172,7 @@ ra_input(int len, struct nd_router_advert *nra,
syslog(LOG_INFO,
"<%s> MTU option value inconsistent on %s:"
" %d from %s, %d from us",
- __func__, rai->rai_ifname, mtu,
+ __func__, ifi->ifi_ifname, mtu,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), rai->rai_linkmtu);
inconsistent++;
@@ -1242,7 +1193,7 @@ ra_input(int len, struct nd_router_advert *nra,
}
if (inconsistent)
- rai->rai_rainconsistent++;
+ ifi->ifi_rainconsistent++;
done:
free_ndopts(&ndopts);
@@ -1254,6 +1205,7 @@ static int
prefix_check(struct nd_opt_prefix_info *pinfo,
struct rainfo *rai, struct sockaddr_in6 *from)
{
+ struct ifinfo *ifi;
u_int32_t preferred_time, valid_time;
struct prefix *pfx;
int inconsistent = 0;
@@ -1265,7 +1217,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo,
if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
return (0);
#endif
-
+ ifi = rai->rai_ifinfo;
/*
* log if the adveritsed prefix has link-local scope(sanity check?)
*/
@@ -1278,7 +1230,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo,
sizeof(prefixbuf)),
pinfo->nd_opt_pi_prefix_len,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
- sizeof(ntopbuf)), rai->rai_ifname);
+ sizeof(ntopbuf)), ifi->ifi_ifname);
if ((pfx = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
pinfo->nd_opt_pi_prefix_len)) == NULL) {
@@ -1289,7 +1241,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo,
sizeof(prefixbuf)),
pinfo->nd_opt_pi_prefix_len,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
- sizeof(ntopbuf)), rai->rai_ifname);
+ sizeof(ntopbuf)), ifi->ifi_ifname);
return (0);
}
@@ -1315,7 +1267,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo,
inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
sizeof(prefixbuf)),
pinfo->nd_opt_pi_prefix_len,
- rai->rai_ifname, preferred_time,
+ ifi->ifi_ifname, preferred_time,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), pfx->pfx_pltimeexpire);
inconsistent++;
@@ -1329,7 +1281,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo,
inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
sizeof(prefixbuf)),
pinfo->nd_opt_pi_prefix_len,
- rai->rai_ifname, preferred_time,
+ ifi->ifi_ifname, preferred_time,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), pfx->pfx_preflifetime);
@@ -1348,7 +1300,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo,
inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
sizeof(prefixbuf)),
pinfo->nd_opt_pi_prefix_len,
- rai->rai_ifname, preferred_time,
+ ifi->ifi_ifname, preferred_time,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), pfx->pfx_vltimeexpire);
inconsistent++;
@@ -1362,7 +1314,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo,
inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf,
sizeof(prefixbuf)),
pinfo->nd_opt_pi_prefix_len,
- rai->rai_ifname, valid_time,
+ ifi->ifi_ifname, valid_time,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
sizeof(ntopbuf)), pfx->pfx_validlifetime);
inconsistent++;
@@ -1553,15 +1505,19 @@ free_ndopts(union nd_opt *ndopts)
}
void
-sock_open(void)
+sock_open(struct sockinfo *s)
{
struct icmp6_filter filt;
- struct ipv6_mreq mreq;
- struct rainfo *rai;
int on;
/* XXX: should be max MTU attached to the node */
static u_char answer[1500];
+ syslog(LOG_DEBUG, "<%s> enter", __func__);
+
+ if (s == NULL) {
+ syslog(LOG_ERR, "<%s> internal error", __func__);
+ exit(1);
+ }
rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
CMSG_SPACE(sizeof(int));
rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen);
@@ -1578,13 +1534,13 @@ sock_open(void)
exit(1);
}
- if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ if ((s->si_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__, strerror(errno));
exit(1);
}
/* specify to tell receiving interface */
on = 1;
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof(on)) < 0) {
syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", __func__,
strerror(errno));
@@ -1592,7 +1548,7 @@ sock_open(void)
}
on = 1;
/* specify to tell value of hoplimit field of received IP6 hdr */
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
sizeof(on)) < 0) {
syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", __func__,
strerror(errno));
@@ -1601,62 +1557,16 @@ sock_open(void)
ICMP6_FILTER_SETBLOCKALL(&filt);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
- if (accept_rr)
+ if (mcastif != NULL)
ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
- if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ if (setsockopt(s->si_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
sizeof(filt)) < 0) {
syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s",
__func__, strerror(errno));
exit(1);
}
- /*
- * join all routers multicast address on each advertising interface.
- */
- 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) {
- syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %s",
- __func__, rai->rai_ifname, strerror(errno));
- exit(1);
- }
- }
-
- /*
- * When attending router renumbering, join all-routers site-local
- * multicast group.
- */
- if (accept_rr) {
- 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);
- exit(1);
- }
- } else
- mreq.ipv6mr_interface =
- TAILQ_FIRST(&railist)->rai_ifindex;
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
- &mreq, sizeof(mreq)) < 0) {
- syslog(LOG_ERR,
- "<%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);
@@ -1679,27 +1589,36 @@ sock_open(void)
/* open a routing socket to watch the routing table */
static void
-rtsock_open(void)
+rtsock_open(struct sockinfo *s)
{
- if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
+ if (s == NULL) {
+ syslog(LOG_ERR, "<%s> internal error", __func__);
+ exit(1);
+ }
+ if ((s->si_fd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
syslog(LOG_ERR,
"<%s> socket: %s", __func__, strerror(errno));
exit(1);
}
}
-struct rainfo *
-if_indextorainfo(int idx)
+struct ifinfo *
+if_indextoifinfo(int idx)
{
- struct rainfo *rai;
+ struct ifinfo *ifi;
- 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);
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (ifi->ifi_ifindex == idx)
+ return (ifi);
}
+ if (ifi != NULL)
+ syslog(LOG_DEBUG, "<%s> ifi found (idx=%d)",
+ __func__, idx);
+ else
+ syslog(LOG_DEBUG, "<%s> ifi not found (idx=%d)",
+ __func__, idx);
+
return (NULL); /* search failed */
}
@@ -1710,13 +1629,22 @@ ra_output(struct rainfo *rai)
struct cmsghdr *cm;
struct in6_pktinfo *pi;
struct soliciter *sol;
-
- if ((iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) == 0) {
- syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA",
- __func__, rai->rai_ifname);
+ struct ifinfo *ifi;
+
+ ifi = rai->rai_ifinfo;
+
+ if (ifi->ifi_state != IFI_STATE_CONFIGURED) {
+ syslog(LOG_DEBUG, "<%s> %s is unconfigured. "
+ "Skip sending RAs.",
+ __func__, ifi->ifi_ifname);
+ return;
+ }
+ if (!(ifi->ifi_flags & IFF_UP)) {
+ syslog(LOG_DEBUG, "<%s> %s is not up. "
+ "Skip sending RAs.",
+ __func__, ifi->ifi_ifname);
return;
}
-
/*
* Check lifetime, ACCEPT_RTADV flag, and ip6.forwarding.
*
@@ -1733,14 +1661,14 @@ ra_output(struct rainfo *rai)
*/
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);
+ __func__, rai->rai_lifetime, check_accept_rtadv(ifi->ifi_ifindex),
+ getinet6sysctl(IPV6CTL_FORWARDING), ifi->ifi_ifname);
if (rai->rai_lifetime != 0) {
- if (check_accept_rtadv(rai->rai_ifindex)) {
+ if (check_accept_rtadv(ifi->ifi_ifindex)) {
syslog(LOG_INFO,
"<%s> non-zero lifetime RA "
"on RA receiving interface %s."
- " Ignored.", __func__, rai->rai_ifname);
+ " Ignored.", __func__, ifi->ifi_ifname);
return;
}
if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) {
@@ -1765,7 +1693,7 @@ ra_output(struct rainfo *rai)
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 = rai->rai_ifindex;
+ pi->ipi6_ifindex = ifi->ifi_ifindex;
/* specify the hop limit of the packet */
{
@@ -1780,21 +1708,21 @@ ra_output(struct rainfo *rai)
syslog(LOG_DEBUG,
"<%s> send RA on %s, # of waitings = %d",
- __func__, rai->rai_ifname, rai->rai_waiting);
+ __func__, ifi->ifi_ifname, rai->rai_waiting);
- i = sendmsg(sock, &sndmhdr, 0);
+ i = sendmsg(sock.si_fd, &sndmhdr, 0);
if (i < 0 || (size_t)i != rai->rai_ra_datalen) {
if (i < 0) {
syslog(LOG_ERR, "<%s> sendmsg on %s: %s",
- __func__, rai->rai_ifname,
+ __func__, ifi->ifi_ifname,
strerror(errno));
}
}
/* update counter */
if (rai->rai_initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
rai->rai_initcounter++;
- rai->rai_raoutput++;
+ ifi->ifi_raoutput++;
/*
* unicast advertisements
@@ -1818,13 +1746,14 @@ struct rtadvd_timer *
ra_timeout(void *arg)
{
struct rainfo *rai;
-
+ struct ifinfo *ifi;
#ifdef notyet
/* if necessary, reconstruct the packet. */
#endif
rai = (struct rainfo *)arg;
+ ifi = rai->rai_ifinfo;
syslog(LOG_DEBUG, "<%s> RA timer on %s is expired",
- __func__, rai->rai_ifname);
+ __func__, ifi->ifi_ifname);
ra_output(rai);
@@ -1837,8 +1766,10 @@ ra_timer_update(void *arg, struct timeval *tm)
{
long interval;
struct rainfo *rai;
-
+ struct ifinfo *ifi;
+
rai = (struct rainfo *)arg;
+ ifi = rai->rai_ifinfo;
/*
* Whenever a multicast advertisement is sent from an interface,
* the timer is reset to a uniformly-distributed random value
@@ -1870,7 +1801,7 @@ ra_timer_update(void *arg, struct timeval *tm)
syslog(LOG_DEBUG,
"<%s> RA timer on %s is set to %ld:%ld",
- __func__, rai->rai_ifname,
+ __func__, ifi->ifi_ifname,
(long int)tm->tv_sec, (long int)tm->tv_usec);
return;
diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h
index 190bb0d..53bc555 100644
--- a/usr.sbin/rtadvd/rtadvd.h
+++ b/usr.sbin/rtadvd/rtadvd.h
@@ -3,6 +3,7 @@
/*
* Copyright (C) 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,6 +31,17 @@
* SUCH DAMAGE.
*/
+#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)
+
#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
@@ -183,12 +195,10 @@ struct rainfo {
int rai_waiting;
/* interface information */
- int rai_ifindex;
+ struct ifinfo *rai_ifinfo;
+
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 rai_lifetime; /* AdvDefaultLifetime */
@@ -218,25 +228,51 @@ struct rainfo {
size_t rai_ra_datalen;
u_char *rai_ra_data;
- /* statistics */
- 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 */
TAILQ_HEAD(, soliciter) rai_soliciter; /* recent solication source */
};
-/* Interface list including RA information */
+/* RA information list */
extern TAILQ_HEAD(railist_head_t, rainfo) railist;
+#define IFI_STATE_UNCONFIGURED 0
+#define IFI_STATE_CONFIGURED 1
+
+struct ifinfo {
+ TAILQ_ENTRY(ifinfo) ifi_next;
+
+ u_int16_t ifi_state;
+ u_int16_t ifi_persist;
+ u_int16_t ifi_ifindex;
+ char ifi_ifname[IFNAMSIZ];
+ u_int8_t ifi_type;
+ u_int16_t ifi_flags;
+ u_int32_t ifi_nd_flags;
+ u_int32_t ifi_phymtu;
+ struct sockaddr_dl ifi_sdl;
+
+ struct rainfo *ifi_rainfo;
+
+ /* statistics */
+ u_int64_t ifi_raoutput; /* # of RAs sent */
+ u_int64_t ifi_rainput; /* # of RAs received */
+ u_int64_t ifi_rainconsistent; /* # of inconsistent recv'd RAs */
+ u_int64_t ifi_rsinput; /* # of RSs received */
+};
+
+/* Interface list */
+extern TAILQ_HEAD(ifilist_head_t, ifinfo) ifilist;
+
+extern char *mcastif;
+
struct rtadvd_timer *ra_timeout(void *);
void ra_timer_update(void *, struct timeval *);
void ra_output(struct rainfo *);
int prefix_match(struct in6_addr *, int,
struct in6_addr *, int);
-struct rainfo *if_indextorainfo(int);
+struct ifinfo *if_indextoifinfo(int);
struct prefix *find_prefix(struct rainfo *,
struct in6_addr *, int);
+void rtadvd_set_reload(int);
+void rtadvd_set_die(int);
diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c
index 8cad6ad..d51c897 100644
--- a/usr.sbin/rtadvd/timer.c
+++ b/usr.sbin/rtadvd/timer.c
@@ -3,6 +3,7 @@
/*
* Copyright (C) 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +33,22 @@
#include <sys/time.h>
#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
#include <unistd.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <search.h>
-#include "timer.h"
+#include <netdb.h>
-#define MILLION 1000000
+#include "rtadvd.h"
+#include "timer_subr.h"
+#include "timer.h"
struct rtadvd_timer_head_t ra_timer =
TAILQ_HEAD_INITIALIZER(ra_timer);
@@ -55,6 +63,46 @@ rtadvd_timer_init(void)
TAILQ_INIT(&ra_timer);
}
+void
+rtadvd_update_timeout_handler(void)
+{
+ struct rainfo *rai;
+ struct ifinfo *ifi;
+
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ rai = ifi->ifi_rainfo;
+ if (rai == NULL)
+ continue;
+
+ switch (ifi->ifi_state) {
+ case IFI_STATE_CONFIGURED:
+ if (rai->rai_timer != NULL)
+ continue;
+
+ syslog(LOG_DEBUG, "<%s> add timer for %s (idx=%d)",
+ __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
+ 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);
+ break;
+ case IFI_STATE_UNCONFIGURED:
+ if (rai->rai_timer == NULL)
+ continue;
+
+ syslog(LOG_DEBUG,
+ "<%s> remove timer for %s (idx=%d)", __func__,
+ ifi->ifi_ifname, ifi->ifi_ifindex);
+ rtadvd_remove_timer(rai->rai_timer);
+ break;
+ }
+ }
+
+ return;
+}
+
struct rtadvd_timer *
rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
void (*update)(void *, struct timeval *),
@@ -99,22 +147,6 @@ rtadvd_remove_timer(struct rtadvd_timer *rat)
free(rat);
}
-void
-rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *rat)
-{
- struct timeval now;
-
- /* reset the timer */
- gettimeofday(&now, NULL);
- TIMEVAL_ADD(&now, tm, &rat->rat_tm);
-
- /* update the next expiration time */
- if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
- tm_max = rat->rat_tm;
-
- return;
-}
-
/*
* Check expiration for each timer. If a timer expires,
* call the expire function for the timer and update the timer.
@@ -151,55 +183,18 @@ rtadvd_check_timer(void)
return (&returnval);
}
-struct timeval *
-rtadvd_timer_rest(struct rtadvd_timer *rat)
-{
- static struct timeval returnval, now;
-
- gettimeofday(&now, NULL);
- if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
- syslog(LOG_DEBUG,
- "<%s> a timer must be expired, but not yet",
- __func__);
- returnval.tv_sec = returnval.tv_usec = 0;
- }
- else
- TIMEVAL_SUB(&rat->rat_tm, &now, &returnval);
-
- return (&returnval);
-}
-
-/* result = a + b */
void
-TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
+rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *rat)
{
- long l;
+ struct timeval now;
- if ((l = a->tv_usec + b->tv_usec) < MILLION) {
- result->tv_usec = l;
- result->tv_sec = a->tv_sec + b->tv_sec;
- }
- else {
- result->tv_usec = l - MILLION;
- result->tv_sec = a->tv_sec + b->tv_sec + 1;
- }
-}
+ /* reset the timer */
+ gettimeofday(&now, NULL);
+ TIMEVAL_ADD(&now, tm, &rat->rat_tm);
-/*
- * result = a - b
- * XXX: this function assumes that a >= b.
- */
-void
-TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
-{
- long l;
+ /* update the next expiration time */
+ if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
+ tm_max = rat->rat_tm;
- if ((l = a->tv_usec - b->tv_usec) >= 0) {
- result->tv_usec = l;
- result->tv_sec = a->tv_sec - b->tv_sec;
- }
- else {
- result->tv_usec = MILLION + l;
- result->tv_sec = a->tv_sec - b->tv_sec - 1;
- }
+ return;
}
diff --git a/usr.sbin/rtadvd/timer.h b/usr.sbin/rtadvd/timer.h
index e2e0c65..f70e0d1 100644
--- a/usr.sbin/rtadvd/timer.h
+++ b/usr.sbin/rtadvd/timer.h
@@ -30,22 +30,6 @@
* SUCH DAMAGE.
*/
-/* 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)))
-
-/* 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_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 {
TAILQ_ENTRY(rtadvd_timer) rat_next;
@@ -59,14 +43,10 @@ struct rtadvd_timer {
};
void rtadvd_timer_init(void);
+void rtadvd_update_timeout_handler(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/rtadvd/timer_subr.c b/usr.sbin/rtadvd/timer_subr.c
new file mode 100644
index 0000000..004919b
--- /dev/null
+++ b/usr.sbin/rtadvd/timer_subr.c
@@ -0,0 +1,126 @@
+/* $FreeBSD$ */
+/* $KAME: timer.c,v 1.9 2002/06/10 19:59:47 itojun Exp $ */
+
+/*
+ * 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:
+ * 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.
+ * 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT 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/time.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include <stdio.h>
+
+#include "timer.h"
+#include "timer_subr.h"
+
+struct timeval *
+rtadvd_timer_rest(struct rtadvd_timer *rat)
+{
+ static struct timeval returnval, now;
+
+ gettimeofday(&now, NULL);
+ if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
+ syslog(LOG_DEBUG,
+ "<%s> a timer must be expired, but not yet",
+ __func__);
+ returnval.tv_sec = returnval.tv_usec = 0;
+ }
+ else
+ TIMEVAL_SUB(&rat->rat_tm, &now, &returnval);
+
+ return (&returnval);
+}
+
+/* result = a + b */
+void
+TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec + b->tv_usec) < MILLION) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec + b->tv_sec;
+ }
+ else {
+ result->tv_usec = l - MILLION;
+ result->tv_sec = a->tv_sec + b->tv_sec + 1;
+ }
+}
+
+/*
+ * result = a - b
+ * XXX: this function assumes that a >= b.
+ */
+void
+TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec - b->tv_usec) >= 0) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec - b->tv_sec;
+ }
+ else {
+ result->tv_usec = MILLION + l;
+ result->tv_sec = a->tv_sec - b->tv_sec - 1;
+ }
+}
+
+char *
+sec2str(u_int32_t s, char *buf)
+{
+ int day;
+ int hour;
+ int min;
+ int sec;
+ char *p;
+
+ min = s / 60;
+ sec = s % 60;
+
+ hour = min / 60;
+ min = min % 60;
+
+ day = hour / 24;
+ hour = hour % 24;
+
+ p = buf;
+ if (day > 0)
+ p += sprintf(p, "%dd", day);
+ if (hour > 0)
+ p += sprintf(p, "%dh", hour);
+ if (min > 0)
+ p += sprintf(p, "%dm", min);
+
+ if ((sec == 0 && p == buf) ||
+ (sec > 0 && p > buf))
+ sprintf(p, "%ds", sec);
+
+ return (buf);
+}
diff --git a/usr.sbin/rtadvd/dump.h b/usr.sbin/rtadvd/timer_subr.h
index 8696e13..7d2f683 100644
--- a/usr.sbin/rtadvd/dump.h
+++ b/usr.sbin/rtadvd/timer_subr.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: dump.h,v 1.1 2000/05/23 11:31:26 itojun Exp $ */
+/* $KAME: timer.h,v 1.5 2002/05/31 13:30:38 jinmei Exp $ */
/*
* Copyright (C) 1998 WIDE Project.
@@ -30,4 +30,28 @@
* SUCH DAMAGE.
*/
-extern void rtadvd_dump_file(const char *);
+#define SSBUFLEN 1024
+#define MILLION 1000000
+
+/* 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)))
+
+/* 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_EQUAL(a,b) \
+ (((a)->tv_sec == (b)->tv_sec) && \
+ ((a)->tv_usec == (b)->tv_usec))
+
+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 *);
+char *sec2str(u_int32_t, char *buf);
OpenPOWER on IntegriCloud