summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2011-07-14 10:09:58 +0000
committerhrs <hrs@FreeBSD.org>2011-07-14 10:09:58 +0000
commitcdcbea6ad239dd44f37a01b119599e17dac4a5a8 (patch)
treec97e2a5f6ba4790dc756b51374a4d00de9f4ecae /usr.sbin
parent90aa2cef03ff2efa8e9af771632eb3d02d0df168 (diff)
downloadFreeBSD-src-cdcbea6ad239dd44f37a01b119599e17dac4a5a8.zip
FreeBSD-src-cdcbea6ad239dd44f37a01b119599e17dac4a5a8.tar.gz
- Refactoring the interface list. It now supports dynamically
added/removed interfaces in a more consistent manner and reloading the configuration file. - Add initial support for control socket. RA information in the daemon can be obtained by rtadvctl(8) instead of SIGUSR1 in a similar manner to ifconfig(8). The information dump has been removed in favor of it. (reload the configuration file) # rtadvctl reload (show RA messages being sent on each interfaces) # rtadvctl show em0: flags=<UP,CONFIGURED,PERSIST> status=<RA_SEND> mtu 1280 DefaultLifetime: 30m MinAdvInterval/MaxAdvInterval: 3m20s/3m20s AdvLinkMTU: <none>, Flags: O, Preference: medium ReachableTime: 0s, RetransTimer: 0s, CurHopLimit: 64 AdvIfPrefixes: yes (show RA messages being sent only on em0) # rtadvctl show em0 (rtadvctl -v show provides additional information) # rtadvctl -v show em0 em0: flags=<UP,CONFIGURED,PERSIST> status=<RA_SEND> mtu 1280 DefaultLifetime: 30m MinAdvInterval/MaxAdvInterval: 3m20s/3m20s AdvLinkMTU: <none>, Flags: O, Preference: medium ReachableTime: 0s, RetransTimer: 0s, CurHopLimit: 64 AdvIfPrefixes: yes Prefixes (1): 2001:db8:1::/64 (CONFIG, vltime=30d, pltime=7d, flags=LA) RDNSS entries: 2001:db8:1::128 (ltime=2m40s) (stop rtadvd) # rtadvctl shutdown A remaining issue when reloading the configuration file is that during that period rtadvd cannot communicate with rtadvctl due to some additional RA sending for graceful shutdown. This will be fixed later.
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