summaryrefslogtreecommitdiffstats
path: root/usr.sbin/rtadvd/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/rtadvd/config.c')
-rw-r--r--usr.sbin/rtadvd/config.c548
1 files changed, 357 insertions, 191 deletions
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index c0e442b..681611f 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
@@ -52,6 +53,7 @@
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
+#include <inttypes.h>
#include <netdb.h>
#include <string.h>
#include <search.h>
@@ -130,48 +132,153 @@ 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;
- int error;
+ struct ifinfo *ifi;
+
+ 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;
- for (i = 0; i < ifl_len; i++) {
- idx = if_nametoindex(ifl_names[i]);
- if (idx == 0) {
+ 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) == 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;
+ }
+ }
+ return (0);
+}
+
+int
+rm_ifinfo_index(int idx)
+{
+ struct ifinfo *ifi;
+
+ ifi = if_indextoifinfo(idx);
+ if (ifi == NULL) {
+ syslog(LOG_ERR, "<%s>: ifinfo not found (idx=%d)",
+ __func__, idx);
+ return (-1);
+ }
+
+ return (rm_ifinfo(ifi));
+}
+
+int
+rm_ifinfo(struct ifinfo *ifi)
+{
+ int error;
+
+ syslog(LOG_DEBUG, "<%s> enter (%s).", __func__, ifi->ifi_ifname);
+ switch (ifi->ifi_state) {
+ case IFI_STATE_UNCONFIGURED:
+ return (0);
+ break;
+ default:
+ ifi->ifi_state = IFI_STATE_UNCONFIGURED;
+ syslog(LOG_DEBUG,
+ "<%s> ifname=%s marked as UNCONFIGURED.",
+ __func__, ifi->ifi_ifname);
+
+ /* XXX: No MC leaving here becasue index is disappeared */
+
+ /* Inactivate timer */
+ rtadvd_remove_timer(ifi->ifi_ra_timer);
+ ifi->ifi_ra_timer = NULL;
+ break;
+ }
+
+ /* clean up ifi */
+ if (!ifi->ifi_persist) {
+ TAILQ_REMOVE(&ifilist, ifi, ifi_next);
+ syslog(LOG_DEBUG, "<%s>: ifinfo (idx=%d) removed.",
+ __func__, ifi->ifi_ifindex);
+ 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 */
+ switch (ifi->ifi_state) {
+ case IFI_STATE_CONFIGURED:
+ if (ifi->ifi_rainfo != NULL) {
+ error = rm_rainfo(ifi->ifi_rainfo);
+ if (error)
+ return (error);
+ ifi->ifi_rainfo = NULL;
+ }
+ break;
+ case IFI_STATE_TRANSITIVE:
+ if (ifi->ifi_rainfo == ifi->ifi_rainfo_trans) {
+ if (ifi->ifi_rainfo != NULL) {
+ error = rm_rainfo(ifi->ifi_rainfo);
+ if (error)
+ return (error);
+ ifi->ifi_rainfo = NULL;
+ ifi->ifi_rainfo_trans = NULL;
+ }
+ } else {
+ if (ifi->ifi_rainfo != NULL) {
+ error = rm_rainfo(ifi->ifi_rainfo);
+ if (error)
+ return (error);
+ ifi->ifi_rainfo = NULL;
+ }
+ if (ifi->ifi_rainfo_trans != NULL) {
+ error = rm_rainfo(ifi->ifi_rainfo_trans);
+ if (error)
+ return (error);
+ ifi->ifi_rainfo_trans = NULL;
+ }
+ }
}
+ syslog(LOG_DEBUG, "<%s> leave (%s).", __func__, ifi->ifi_ifname);
return (0);
}
int
-rmconfig(int idx)
+rm_rainfo(struct rainfo *rai)
{
- struct rainfo *rai;
struct prefix *pfx;
struct soliciter *sol;
struct rdnss *rdn;
@@ -179,26 +286,16 @@ rmconfig(int idx)
struct dnssl *dns;
struct rtinfo *rti;
- rai = if_indextorainfo(idx);
- if (rai == NULL) {
- syslog(LOG_ERR, "<%s>: rainfo not found (idx=%d)",
- __func__, idx);
- return (-1);
- }
+ syslog(LOG_DEBUG, "<%s>: enter", __func__);
TAILQ_REMOVE(&railist, rai, rai_next);
- syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.",
- __func__, idx);
-
- /* Free all of allocated memories for this entry. */
- rtadvd_remove_timer(rai->rai_timer);
+ if (rai->rai_ifinfo != NULL)
+ syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.",
+ __func__, rai->rai_ifinfo->ifi_ifindex);
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,51 +321,51 @@ rmconfig(int idx)
free(rti);
}
free(rai);
-
+ syslog(LOG_DEBUG, "<%s>: leave", __func__);
+
return (0);
}
-int
-getconfig(int idx)
+struct ifinfo *
+getconfig(struct ifinfo *ifi)
{
int stat, i;
+ int error;
char tbuf[BUFSIZ];
struct rainfo *rai;
struct rainfo *rai_old;
- long val;
+ int32_t 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 (ifi == NULL) /* if does not exist */
+ return (NULL);
- TAILQ_FOREACH(rai_old, &railist, rai_next)
- if (idx == rai_old->rai_ifindex)
- break;
+ if (ifi->ifi_state == IFI_STATE_TRANSITIVE &&
+ ifi->ifi_rainfo == NULL) {
+ syslog(LOG_INFO, "<%s> %s is shutting down. Skipped.",
+ __func__, ifi->ifi_ifname);
+ return (NULL);
+ }
- 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));
TAILQ_INIT(&rai->rai_prefix);
-#ifdef ROUTEINFO
TAILQ_INIT(&rai->rai_route);
-#endif
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 +379,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);
}
/*
@@ -309,24 +393,24 @@ getconfig(int idx)
MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
syslog(LOG_ERR,
- "<%s> maxinterval (%ld) on %s is invalid "
+ "<%s> maxinterval (%" PRIu32 ") 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;
+ rai->rai_maxinterval = (uint16_t)val;
MAYHAVE(val, "mininterval", rai->rai_maxinterval/3);
- if ((u_int)val < MIN_MININTERVAL ||
- (u_int)val > (rai->rai_maxinterval * 3) / 4) {
+ if ((uint16_t)val < MIN_MININTERVAL ||
+ (uint16_t)val > (rai->rai_maxinterval * 3) / 4) {
syslog(LOG_ERR,
- "<%s> mininterval (%ld) on %s is invalid "
+ "<%s> mininterval (%" PRIu32 ") 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;
}
- rai->rai_mininterval = (u_int)val;
+ rai->rai_mininterval = (uint16_t)val;
MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
rai->rai_hoplimit = val & 0xff;
@@ -359,17 +443,17 @@ 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;
}
MAYHAVE(val, "rltime", rai->rai_maxinterval * 3);
- if ((u_int)val && ((u_int)val < rai->rai_maxinterval ||
- (u_int)val > MAXROUTERLIFETIME)) {
+ if ((uint16_t)val && ((uint16_t)val < rai->rai_maxinterval ||
+ (uint16_t)val > MAXROUTERLIFETIME)) {
syslog(LOG_ERR,
- "<%s> router lifetime (%ld) on %s is invalid "
+ "<%s> router lifetime (%" PRIu32 ") 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;
}
@@ -378,20 +462,20 @@ getconfig(int idx)
MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
if (val < 0 || val > MAXREACHABLETIME) {
syslog(LOG_ERR,
- "<%s> reachable time (%ld) on %s is invalid "
+ "<%s> reachable time (%" PRIu32 ") 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;
+ rai->rai_reachabletime = (uint32_t)val;
MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
if (val64 < 0 || val64 > 0xffffffff) {
- syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range",
- __func__, (long long)val64, intface);
+ syslog(LOG_ERR, "<%s> retrans time (%" PRIu64 ") on %s out of range",
+ __func__, val64, ifi->ifi_ifname);
goto getconfig_free_rai;
}
- rai->rai_retranstimer = (u_int32_t)val64;
+ rai->rai_retranstimer = (uint32_t)val64;
if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
syslog(LOG_ERR,
@@ -433,21 +517,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 "
+ syslog(LOG_ERR, "<%s> prefixlen (%" PRIu32 ") 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;
@@ -469,13 +553,13 @@ getconfig(int idx)
makeentry(entbuf, sizeof(entbuf), i, "vltime");
MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
if (val64 < 0 || val64 > 0xffffffff) {
- syslog(LOG_ERR, "<%s> vltime (%lld) for "
+ syslog(LOG_ERR, "<%s> vltime (%" PRIu64 ") for "
"%s/%d on %s is out of range",
- __func__, (long long)val64,
- addr, pfx->pfx_prefixlen, intface);
+ __func__, val64,
+ addr, pfx->pfx_prefixlen, ifi->ifi_ifname);
goto getconfig_free_pfx;
}
- pfx->pfx_validlifetime = (u_int32_t)val64;
+ pfx->pfx_validlifetime = (uint32_t)val64;
makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
if (agetflag(entbuf)) {
@@ -489,13 +573,13 @@ getconfig(int idx)
MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
if (val64 < 0 || val64 > 0xffffffff) {
syslog(LOG_ERR,
- "<%s> pltime (%lld) for %s/%d on %s "
+ "<%s> pltime (%" PRIu64 ") for %s/%d on %s "
"is out of range",
- __func__, (long long)val64,
- addr, pfx->pfx_prefixlen, intface);
+ __func__, val64,
+ addr, pfx->pfx_prefixlen, ifi->ifi_ifname);
goto getconfig_free_pfx;
}
- pfx->pfx_preflifetime = (u_int32_t)val64;
+ pfx->pfx_preflifetime = (uint32_t)val64;
makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
if (agetflag(entbuf)) {
@@ -514,28 +598,28 @@ getconfig_free_pfx:
if (rai->rai_advifprefix && rai->rai_pfxs == 0)
get_prefix(rai);
- MAYHAVE(val, "mtu", 0);
- if (val < 0 || (u_int)val > 0xffffffff) {
+ MAYHAVE(val64, "mtu", 0);
+ if (val < 0 || val64 > 0xffffffff) {
syslog(LOG_ERR,
- "<%s> mtu (%ld) on %s out of range",
- __func__, val, intface);
+ "<%s> mtu (%" PRIu64 ") on %s out of range",
+ __func__, val64, ifi->ifi_ifname);
goto getconfig_free_rai;
}
- rai->rai_linkmtu = (u_int32_t)val;
+ rai->rai_linkmtu = (uint32_t)val64;
if (rai->rai_linkmtu == 0) {
char *mtustr;
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 "
+ "<%s> advertised link mtu (%" PRIu32 ") 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__, rai->rai_linkmtu, ifi->ifi_ifname,
+ IPV6_MMTU, ifi->ifi_phymtu);
goto getconfig_free_rai;
}
@@ -550,10 +634,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,14 +645,13 @@ 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);
}
#endif
/* route information */
-#ifdef ROUTEINFO
rai->rai_routes = 0;
for (i = -1; i < MAXROUTE; i++) {
struct rtinfo *rti;
@@ -605,14 +688,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
@@ -630,9 +713,9 @@ getconfig_free_pfx:
val = 64;
}
if (val < 0 || val > 128) {
- syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s "
+ syslog(LOG_ERR, "<%s> prefixlen (%" PRIu32 ") 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 +751,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,17 +771,19 @@ 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 "
+ syslog(LOG_ERR, "<%s> route lifetime (%" PRIu64 ") for "
"%s/%d on %s out of range", __func__,
- (long long)val64, addr, rti->rti_prefixlen, intface);
+ val64, addr, rti->rti_prefixlen,
+ ifi->ifi_ifname);
goto getconfig_free_rti;
}
- rti->rti_ltime = (u_int32_t)val64;
+ rti->rti_ltime = (uint32_t)val64;
/* link into chain */
TAILQ_INSERT_TAIL(&rai->rai_route, rti, rti_next);
@@ -707,7 +792,7 @@ getconfig_free_pfx:
getconfig_free_rti:
free(rti);
}
-#endif
+
/* DNS server and DNS search list information */
for (i = -1; i < MAXRDNSSENT ; i++) {
struct rdnss *rdn;
@@ -739,11 +824,11 @@ getconfig_free_rti:
makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2));
- if ((u_int)val < rai->rai_maxinterval ||
- (u_int)val > rai->rai_maxinterval * 2) {
- syslog(LOG_ERR, "%s (%ld) on %s is invalid "
+ if ((uint16_t)val < rai->rai_maxinterval ||
+ (uint16_t)val > rai->rai_maxinterval * 2) {
+ syslog(LOG_ERR, "%s (%" PRIu16 ") 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;
}
@@ -788,11 +873,11 @@ getconfig_free_rdn:
makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2));
- if ((u_int)val < rai->rai_maxinterval ||
- (u_int)val > rai->rai_maxinterval * 2) {
- syslog(LOG_ERR, "%s (%ld) on %s is invalid "
+ if ((uint16_t)val < rai->rai_maxinterval ||
+ (uint16_t)val > rai->rai_maxinterval * 2) {
+ syslog(LOG_ERR, "%s (%" PRIu16 ") 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;
}
@@ -816,36 +901,108 @@ getconfig_free_dns:
* Before the removal, RDNSS and DNSSL options with
* zero-lifetime will be sent.
*/
- if (rai_old != NULL) {
- const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
- struct rdnss *rdn;
- struct dnssl *dns;
+ switch (ifi->ifi_state) {
+ case IFI_STATE_UNCONFIGURED:
+ /* UNCONFIGURED -> TRANSITIVE */
+
+ error = sock_mc_join(&sock, ifi->ifi_ifindex);
+ if (error)
+ exit(1);
+
+ ifi->ifi_state = IFI_STATE_TRANSITIVE;
+ ifi->ifi_burstcount = MAX_INITIAL_RTR_ADVERTISEMENTS;
+ ifi->ifi_burstinterval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
- rai_old->rai_lifetime = 0;
- TAILQ_FOREACH(rdn, &rai_old->rai_rdnss, rd_next)
- rdn->rd_ltime = 0;
- TAILQ_FOREACH(dns, &rai_old->rai_dnssl, dn_next)
- dns->dn_ltime = 0;
+ /* The same two rai mean initial burst */
+ ifi->ifi_rainfo = rai;
+ ifi->ifi_rainfo_trans = rai;
+ TAILQ_INSERT_TAIL(&railist, rai, rai_next);
- make_packet(rai_old);
- for (i = 0; i < retrans; i++) {
- ra_output(rai_old);
- sleep(MIN_DELAY_BETWEEN_RAS);
+ if (ifi->ifi_ra_timer == NULL)
+ ifi->ifi_ra_timer = rtadvd_add_timer(ra_timeout,
+ ra_timer_update, ifi, ifi);
+ ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm);
+ rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
+ ifi->ifi_ra_timer);
+
+ syslog(LOG_DEBUG,
+ "<%s> ifname=%s marked as TRANSITIVE (initial burst).",
+ __func__, ifi->ifi_ifname);
+ break;
+ case IFI_STATE_CONFIGURED:
+ /* CONFIGURED -> TRANSITIVE */
+ rai_old = ifi->ifi_rainfo;
+ if (rai_old == NULL) {
+ syslog(LOG_ERR,
+ "<%s> ifi_rainfo is NULL"
+ " in IFI_STATE_CONFIGURED.", __func__);
+ ifi = NULL;
+ break;
+ } else {
+ struct rdnss *rdn;
+ struct dnssl *dns;
+
+ rai_old->rai_lifetime = 0;
+ TAILQ_FOREACH(rdn, &rai_old->rai_rdnss, rd_next)
+ rdn->rd_ltime = 0;
+ TAILQ_FOREACH(dns, &rai_old->rai_dnssl, dn_next)
+ dns->dn_ltime = 0;
+
+ ifi->ifi_rainfo_trans = rai_old;
+ ifi->ifi_state = IFI_STATE_TRANSITIVE;
+ ifi->ifi_burstcount = MAX_FINAL_RTR_ADVERTISEMENTS;
+ ifi->ifi_burstinterval = MIN_DELAY_BETWEEN_RAS;
+
+ ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm);
+ rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
+ ifi->ifi_ra_timer);
+
+ syslog(LOG_DEBUG,
+ "<%s> ifname=%s marked as TRANSITIVE"
+ " (transitional burst)",
+ __func__, ifi->ifi_ifname);
+ }
+ ifi->ifi_rainfo = rai;
+ TAILQ_INSERT_TAIL(&railist, rai, rai_next);
+ break;
+ case IFI_STATE_TRANSITIVE:
+ if (ifi->ifi_rainfo != NULL) {
+ if (ifi->ifi_rainfo == ifi->ifi_rainfo_trans) {
+ /* Reinitialize initial burst */
+ rm_rainfo(ifi->ifi_rainfo);
+ ifi->ifi_rainfo = rai;
+ ifi->ifi_rainfo_trans = rai;
+ ifi->ifi_burstcount =
+ MAX_INITIAL_RTR_ADVERTISEMENTS;
+ ifi->ifi_burstinterval =
+ MAX_INITIAL_RTR_ADVERT_INTERVAL;
+ } else {
+ /* Replace ifi_rainfo with the new one */
+ rm_rainfo(ifi->ifi_rainfo);
+ ifi->ifi_rainfo = rai;
+ }
+ TAILQ_INSERT_TAIL(&railist, rai, rai_next);
+
+ ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm);
+ rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm,
+ ifi->ifi_ra_timer);
+ } else {
+ /* XXX: NOTREACHED. Being shut down. */
+ syslog(LOG_ERR,
+ "<%s> %s is shutting down. Skipped.",
+ __func__, ifi->ifi_ifname);
+ rm_rainfo(rai);
+
+ return (NULL);
}
- rmconfig(idx);
+ break;
}
- 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,8 +1011,9 @@ get_prefix(struct rainfo *rai)
struct ifaddrs *ifap, *ifa;
struct prefix *pfx;
struct in6_addr *a;
- u_char *p, *ep, *m, *lim;
- u_char ntopbuf[INET6_ADDRSTRLEN];
+ struct ifinfo *ifi;
+ char *p, *ep, *m, *lim;
+ char ntopbuf[INET6_ADDRSTRLEN];
if (getifaddrs(&ifap) < 0) {
syslog(LOG_ERR,
@@ -863,20 +1021,22 @@ 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;
a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
if (IN6_IS_ADDR_LINKLOCAL(a))
continue;
+
/* get prefix length */
- m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
- lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
+ m = (char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
+ lim = (char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
plen = prefixlen(m, lim);
if (plen <= 0 || plen > 128) {
syslog(LOG_ERR, "<%s> failed to get prefixlen "
@@ -897,8 +1057,8 @@ get_prefix(struct rainfo *rai)
/* set prefix, sweep bits outside of prefixlen */
pfx->pfx_prefixlen = plen;
memcpy(&pfx->pfx_prefix, a, sizeof(*a));
- p = (u_char *)&pfx->pfx_prefix;
- ep = (u_char *)(&pfx->pfx_prefix + 1);
+ p = (char *)&pfx->pfx_prefix;
+ ep = (char *)(&pfx->pfx_prefix + 1);
while (m < lim && p < ep)
*p++ &= *m++;
while (p < ep)
@@ -910,7 +1070,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 +1111,10 @@ static void
add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
{
struct prefix *pfx;
- u_char ntopbuf[INET6_ADDRSTRLEN];
+ struct ifinfo *ifi;
+ 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,11 +1130,9 @@ 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++;
- make_packet(rai);
}
/*
@@ -983,30 +1143,34 @@ 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;
+ 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);
+
rai->rai_pfxs--;
- make_packet(rai);
}
void
invalidate_prefix(struct prefix *pfx)
{
- u_char ntopbuf[INET6_ADDRSTRLEN];
struct timeval timo;
struct rainfo *rai;
+ struct ifinfo *ifi;
+ 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 +1181,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 +1207,12 @@ prefix_timeout(void *arg)
void
update_prefix(struct prefix *pfx)
{
- u_char ntopbuf[INET6_ADDRSTRLEN];
struct rainfo *rai;
+ struct ifinfo *ifi;
+ 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 +1222,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);
@@ -1091,7 +1257,7 @@ init_prefix(struct in6_prefixreq *ipr)
/* omit other field initialization */
}
else if (ipr->ipr_origin < PR_ORIG_RR) {
- u_char ntopbuf[INET6_ADDRSTRLEN];
+ char ntopbuf[INET6_ADDRSTRLEN];
syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is"
"lower than PR_ORIG_RR(router renumbering)."
@@ -1143,25 +1309,25 @@ make_packet(struct rainfo *rai)
struct nd_router_advert *ra;
struct nd_opt_prefix_info *ndopt_pi;
struct nd_opt_mtu *ndopt_mtu;
-#ifdef ROUTEINFO
struct nd_opt_route_info *ndopt_rti;
struct rtinfo *rti;
-#endif
struct nd_opt_rdnss *ndopt_rdnss;
struct rdnss *rdn;
struct nd_opt_dnssl *ndopt_dnssl;
struct dnssl *dns;
size_t len;
struct prefix *pfx;
+ 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;
@@ -1170,11 +1336,11 @@ make_packet(struct rainfo *rai)
packlen += sizeof(struct nd_opt_prefix_info) * rai->rai_pfxs;
if (rai->rai_linkmtu)
packlen += sizeof(struct nd_opt_mtu);
-#ifdef ROUTEINFO
+
TAILQ_FOREACH(rti, &rai->rai_route, rti_next)
packlen += sizeof(struct nd_opt_route_info) +
((rti->rti_prefixlen + 0x3f) >> 6) * 8;
-#endif
+
TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
struct rdnss_addr *rdna;
@@ -1217,7 +1383,7 @@ make_packet(struct rainfo *rai)
ra->nd_ra_type = ND_ROUTER_ADVERT;
ra->nd_ra_code = 0;
ra->nd_ra_cksum = 0;
- ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rai->rai_hoplimit);
+ ra->nd_ra_curhoplimit = (uint8_t)(0xff & rai->rai_hoplimit);
ra->nd_ra_flags_reserved = 0; /* just in case */
/*
* XXX: the router preference field, which is a 2-bit field, should be
@@ -1234,7 +1400,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;
}
@@ -1248,7 +1414,7 @@ make_packet(struct rainfo *rai)
}
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
- u_int32_t vltime, pltime;
+ uint32_t vltime, pltime;
struct timeval now;
ndopt_pi = (struct nd_opt_prefix_info *)buf;
@@ -1270,7 +1436,7 @@ make_packet(struct rainfo *rai)
if (pfx->pfx_vltimeexpire == 0)
vltime = pfx->pfx_validlifetime;
else
- vltime = (pfx->pfx_vltimeexpire > now.tv_sec) ?
+ vltime = ((time_t)pfx->pfx_vltimeexpire > now.tv_sec) ?
pfx->pfx_vltimeexpire - now.tv_sec : 0;
}
if (pfx->pfx_timer)
@@ -1279,7 +1445,7 @@ make_packet(struct rainfo *rai)
if (pfx->pfx_pltimeexpire == 0)
pltime = pfx->pfx_preflifetime;
else
- pltime = (pfx->pfx_pltimeexpire > now.tv_sec) ?
+ pltime = ((time_t)pfx->pfx_pltimeexpire > now.tv_sec) ?
pfx->pfx_pltimeexpire - now.tv_sec : 0;
}
if (vltime < pltime) {
@@ -1297,9 +1463,8 @@ make_packet(struct rainfo *rai)
buf += sizeof(struct nd_opt_prefix_info);
}
-#ifdef ROUTEINFO
TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
- u_int8_t psize = (rti->rti_prefixlen + 0x3f) >> 6;
+ uint8_t psize = (rti->rti_prefixlen + 0x3f) >> 6;
ndopt_rti = (struct nd_opt_route_info *)buf;
ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
@@ -1310,7 +1475,7 @@ make_packet(struct rainfo *rai)
memcpy(ndopt_rti + 1, &rti->rti_prefix, psize * 8);
buf += sizeof(struct nd_opt_route_info) + psize * 8;
}
-#endif
+
TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
struct rdnss_addr *rdna;
@@ -1331,6 +1496,7 @@ make_packet(struct rainfo *rai)
syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__,
ndopt_rdnss->nd_opt_rdnss_len);
}
+
TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
struct dnssl_addr *dnsa;
OpenPOWER on IntegriCloud