Remove the iflist array and store ifflags in rainfo.

Add support for SIGHUP to re-read the configuration for each interface.
If an invalid configuration is found, we continue to use the old one;
otherwise we expire the current one and then start advertising the new one.

Specififed interfaces don't have to exist at startup.
If specified interfaces arrive, load their config and start advertising.
If they depart, remove their rainfo structure and continue.

Fixes PR/43881 and PR/47311
This commit is contained in:
roy 2012-12-13 15:36:35 +00:00
parent 9a4570ee22
commit 83ab565911
11 changed files with 475 additions and 336 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: advcap.c,v 1.13 2011/12/10 19:14:29 roy Exp $ */
/* $NetBSD: advcap.c,v 1.14 2012/12/13 15:36:35 roy Exp $ */
/* $KAME: advcap.c,v 1.11 2003/05/19 09:46:50 keiichi Exp $ */
/*
@ -47,6 +47,10 @@
#include <string.h>
#include "pathnames.h"
#ifndef __UNCONST
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif
#ifndef BUFSIZ
#define BUFSIZ 1024
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: config.c,v 1.29 2012/12/11 16:37:23 roy Exp $ */
/* $NetBSD: config.c,v 1.30 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $ */
/*
@ -39,6 +39,9 @@
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#ifdef __FreeBSD__
#include <net/if_var.h>
#endif
#include <netinet/in.h>
#include <netinet/in_var.h>
@ -57,6 +60,7 @@
#include <search.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <inttypes.h>
#include "rtadvd.h"
#include "advcap.h"
@ -64,6 +68,10 @@
#include "if.h"
#include "config.h"
#ifndef __arraycount
#define __arraycount(__x) (sizeof(__x) / sizeof(__x[0]))
#endif
static time_t prefix_timo = (60 * 120); /* 2 hours.
* XXX: should be configurable. */
static struct rtadvd_timer *prefix_timeout(void *);
@ -92,11 +100,56 @@ encode_domain(char *dst, const char *src)
}
void
getconfig(const char *intface)
free_rainfo(struct rainfo *rai)
{
struct prefix *pfx;
struct rtinfo *rti;
struct rdnss *rdnss;
struct rdnss_addr *rdnsa;
struct dnssl *dnssl;
struct dnssl_domain *dnsd;
rtadvd_remove_timer(&rai->timer);
while ((pfx = TAILQ_FIRST(&rai->prefix))) {
TAILQ_REMOVE(&rai->prefix, pfx, next);
free(pfx);
}
while ((rti = TAILQ_FIRST(&rai->route))) {
TAILQ_REMOVE(&rai->route, rti, next);
free(rti);
}
while ((rdnss = TAILQ_FIRST(&rai->rdnss))) {
TAILQ_REMOVE(&rai->rdnss, rdnss, next);
while ((rdnsa = TAILQ_FIRST(&rdnss->list))) {
TAILQ_REMOVE(&rdnss->list, rdnsa, next);
free(rdnsa);
}
free(rdnss);
}
while ((dnssl = TAILQ_FIRST(&rai->dnssl))) {
TAILQ_REMOVE(&rai->dnssl, dnssl, next);
while ((dnsd = TAILQ_FIRST(&dnssl->list))) {
TAILQ_REMOVE(&dnssl->list, dnsd, next);
free(dnsd);
}
free(dnssl);
}
free(rai->sdl);
free(rai->ra_data);
free(rai);
}
void
getconfig(const char *intface, int exithard)
{
int stat, c, i;
char tbuf[BUFSIZ];
struct rainfo *tmp;
struct rainfo *tmp, *rai;
int32_t val;
int64_t val64;
char buf[BUFSIZ];
@ -104,6 +157,8 @@ getconfig(const char *intface)
char *addr, *flagstr, *ap;
static int forwarding = -1;
char entbuf[256], abuf[256];
struct rdnss *rdnss;
struct dnssl *dnssl;
#define MUSTHAVE(var, cap) \
do { \
@ -111,7 +166,7 @@ getconfig(const char *intface)
if ((t = agetnum(cap)) < 0) { \
fprintf(stderr, "rtadvd: need %s for interface %s\n", \
cap, intface); \
exit(1); \
goto errexit; \
} \
var = t; \
} while (0)
@ -120,16 +175,24 @@ getconfig(const char *intface)
if ((var = agetnum(cap)) < 0) \
var = def; \
} while (0)
#define ELM_MALLOC(p,error_action) \
#define ELM_MALLOC(p) \
do { \
p = calloc(1, sizeof(*p)); \
if (p == NULL) { \
syslog(LOG_ERR, "<%s> calloc failed: %m", \
__func__); \
error_action; \
goto errexit; \
} \
} while(/*CONSTCOND*/0)
if (if_nametoindex(intface) == 0) {
syslog(LOG_INFO, "<%s> interface %s not found, ignoring",
__func__, intface);
return;
}
syslog(LOG_DEBUG, "<%s> loading configuration for interface %s",
__func__, intface);
if ((stat = agetent(tbuf, intface)) <= 0) {
memset(tbuf, 0, sizeof(tbuf));
@ -140,7 +203,11 @@ getconfig(const char *intface)
__func__, intface);
}
ELM_MALLOC(tmp, exit(1));
ELM_MALLOC(tmp);
TAILQ_INIT(&tmp->prefix);
TAILQ_INIT(&tmp->route);
TAILQ_INIT(&tmp->rdnss);
TAILQ_INIT(&tmp->dnssl);
/* check if we are allowed to forward packets (if not determined) */
if (forwarding < 0) {
@ -158,11 +225,19 @@ getconfig(const char *intface)
syslog(LOG_ERR,
"<%s> can't get information of %s",
__func__, intface);
exit(1);
goto errexit;
}
tmp->ifindex = tmp->sdl->sdl_index;
} else
} else {
tmp->ifindex = if_nametoindex(intface);
if (tmp->ifindex == 0) {
syslog(LOG_ERR,
"<%s> can't get information of %s",
__func__, intface);
goto errexit;
}
}
tmp->ifflags = if_getflags(tmp->ifindex, 0);
strlcpy(tmp->ifname, intface, sizeof(tmp->ifname));
if ((tmp->phymtu = if_getmtu(intface)) == 0) {
tmp->phymtu = IPV6_MMTU;
@ -180,7 +255,7 @@ getconfig(const char *intface)
"<%s> maxinterval (%d) on %s is invalid "
"(must be between %u and %u)", __func__, val,
intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
exit(1);
goto errexit;
}
tmp->maxinterval = val;
MAYHAVE(val, "mininterval", tmp->maxinterval/3);
@ -190,7 +265,7 @@ getconfig(const char *intface)
"(must be between %u and %d)",
__func__, val, intface, MIN_MININTERVAL,
(tmp->maxinterval * 3) / 4);
exit(1);
goto errexit;
}
tmp->mininterval = val;
@ -209,7 +284,7 @@ getconfig(const char *intface)
if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
syslog(LOG_ERR, "<%s> the \'h\' and \'l\'"
" router flags are exclusive", __func__);
exit(1);
goto errexit;
}
val |= ND_RA_FLAG_RTPREF_LOW;
}
@ -226,7 +301,7 @@ getconfig(const char *intface)
if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) {
syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s",
__func__, tmp->rtpref, intface);
exit(1);
goto errexit;
}
MAYHAVE(val, "rltime", tmp->maxinterval * 3);
@ -236,7 +311,7 @@ getconfig(const char *intface)
"(must be 0 or between %d and %d)",
__func__, val, intface,
tmp->maxinterval, MAXROUTERLIFETIME);
exit(1);
goto errexit;
}
/*
* Basically, hosts MUST NOT send Router Advertisement messages at any
@ -252,7 +327,7 @@ getconfig(const char *intface)
"which must not be allowed for hosts. you must "
"change router lifetime or enable IPv6 forwarding.",
__func__, intface);
exit(1);
goto errexit;
}
tmp->lifetime = val & 0xffff;
@ -262,7 +337,7 @@ getconfig(const char *intface)
"<%s> reachable time (%d) on %s is invalid "
"(must be no greater than %d)",
__func__, val, intface, MAXREACHABLETIME);
exit(1);
goto errexit;
}
tmp->reachabletime = (uint32_t)val;
@ -270,7 +345,7 @@ getconfig(const char *intface)
if (val64 < 0 || val64 > 0xffffffff) {
syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range",
__func__, (long long)val64, intface);
exit(1);
goto errexit;
}
tmp->retranstimer = (uint32_t)val64;
@ -278,7 +353,7 @@ getconfig(const char *intface)
syslog(LOG_ERR,
"<%s> mobile-ip6 configuration not supported",
__func__);
exit(1);
goto errexit;
}
/* prefix information */
@ -291,7 +366,6 @@ getconfig(const char *intface)
tmp->clockskew = val;
tmp->pfxs = 0;
TAILQ_INIT(&tmp->prefix);
for (i = -1; i < MAXPREFIX; i++) {
struct prefix *pfx;
@ -305,7 +379,7 @@ getconfig(const char *intface)
syslog(LOG_ERR,
"<%s> can't allocate memory: %m",
__func__);
exit(1);
goto errexit;
}
TAILQ_INSERT_TAIL(&tmp->prefix, pfx, next);
@ -318,14 +392,14 @@ getconfig(const char *intface)
syslog(LOG_ERR,
"<%s> inet_pton failed for %s",
__func__, addr);
exit(1);
goto errexit;
}
if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
syslog(LOG_ERR,
"<%s> multicast prefix (%s) must "
"not be advertised on %s",
__func__, addr, intface);
exit(1);
goto errexit;
}
if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
syslog(LOG_NOTICE,
@ -339,7 +413,7 @@ getconfig(const char *intface)
syslog(LOG_ERR, "<%s> prefixlen (%d) for %s "
"on %s out of range",
__func__, val, addr, intface);
exit(1);
goto errexit;
}
pfx->prefixlen = (int)val;
@ -364,7 +438,7 @@ getconfig(const char *intface)
"%s/%d on %s is out of range",
__func__, (long long)val64,
addr, pfx->prefixlen, intface);
exit(1);
goto errexit;
}
pfx->validlifetime = (uint32_t)val64;
@ -384,7 +458,7 @@ getconfig(const char *intface)
"is out of range",
__func__, (long long)val64,
addr, pfx->prefixlen, intface);
exit(1);
goto errexit;
}
pfx->preflifetime = (uint32_t)val64;
@ -404,7 +478,7 @@ getconfig(const char *intface)
syslog(LOG_ERR,
"<%s> mtu (%" PRIi64 ") on %s out of range",
__func__, val64, intface);
exit(1);
goto errexit;
}
tmp->linkmtu = (uint32_t)val64;
if (tmp->linkmtu == 0) {
@ -420,7 +494,7 @@ getconfig(const char *intface)
"be between least MTU (%d) and physical link MTU (%d)",
__func__, tmp->linkmtu, intface,
IPV6_MMTU, tmp->phymtu);
exit(1);
goto errexit;
}
#ifdef SIOCSIFINFO_IN6
@ -430,7 +504,7 @@ getconfig(const char *intface)
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %m", __func__);
exit(1);
goto errexit;
}
memset(&ndi, 0, sizeof(ndi));
strncpy(ndi.ifname, intface, IFNAMSIZ);
@ -452,7 +526,6 @@ getconfig(const char *intface)
#endif
/* route information */
TAILQ_INIT(&tmp->route);
for (i = -1; i < MAXROUTE; i++) {
struct rtinfo *rti;
char oentbuf[256];
@ -470,7 +543,7 @@ getconfig(const char *intface)
if (addr == NULL)
continue;
ELM_MALLOC(rti, exit(1));
ELM_MALLOC(rti);
memset(rti, 0, sizeof(*rti));
/* link into chain */
@ -479,7 +552,7 @@ getconfig(const char *intface)
if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
syslog(LOG_ERR, "<%s> inet_pton failed for %s",
__func__, addr);
exit(1);
goto errexit;
}
#if 0
/*
@ -494,14 +567,14 @@ getconfig(const char *intface)
"<%s> multicast route (%s) must "
"not be advertised on %s",
__func__, addr, intface);
exit(1);
goto errexit;
}
if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
syslog(LOG_NOTICE,
"<%s> link-local route (%s) will "
"be advertised on %s",
__func__, addr, intface);
exit(1);
goto errexit;
}
#endif
@ -521,7 +594,7 @@ getconfig(const char *intface)
syslog(LOG_ERR, "<%s> prefixlen (%d) for %s on %s "
"out of range",
__func__, val, addr, intface);
exit(1);
goto errexit;
}
rti->prefixlen = (int)val;
@ -536,7 +609,7 @@ getconfig(const char *intface)
"<%s> the \'h\' and \'l\' route"
" preferences are exclusive",
__func__);
exit(1);
goto errexit;
}
val |= ND_RA_FLAG_RTPREF_LOW;
}
@ -557,7 +630,7 @@ getconfig(const char *intface)
"for %s/%d on %s",
__func__, rti->rtpref, addr,
rti->prefixlen, intface);
exit(1);
goto errexit;
}
/*
@ -585,15 +658,13 @@ getconfig(const char *intface)
syslog(LOG_ERR, "<%s> route lifetime (%lld) for "
"%s/%d on %s out of range", __func__,
(long long)val64, addr, rti->prefixlen, intface);
exit(1);
goto errexit;
}
rti->ltime = (uint32_t)val64;
}
/* RDNSS */
TAILQ_INIT(&tmp->rdnss);
for (i = -1; i < MAXRDNSS; i++) {
struct rdnss *rdnss;
struct rdnss_addr *rdnsa;
makeentry(entbuf, sizeof(entbuf), i, "rdnss");
@ -601,20 +672,21 @@ getconfig(const char *intface)
if (addr == NULL)
continue;
ELM_MALLOC(rdnss, exit(1));
ELM_MALLOC(rdnss);
TAILQ_INSERT_TAIL(&tmp->rdnss, rdnss, next);
TAILQ_INIT(&rdnss->list);
for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) {
c = strcspn(ap, ",");
strncpy(abuf, ap, c);
abuf[c] = '\0';
ELM_MALLOC(rdnsa, exit(1));
ELM_MALLOC(rdnsa);
TAILQ_INSERT_TAIL(&rdnss->list, rdnsa, next);
if (inet_pton(AF_INET6, abuf, &rdnsa->addr) != 1) {
syslog(LOG_ERR, "<%s> inet_pton failed for %s",
__func__, addr);
exit(1);
goto errexit;
}
TAILQ_INSERT_TAIL(&rdnss->list, rdnsa, next);
}
makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
@ -624,17 +696,15 @@ getconfig(const char *intface)
{
syslog(LOG_ERR, "<%s> %s (%lld) on %s is invalid",
__func__, entbuf, (long long)val64, intface);
exit(1);
goto errexit;
}
rdnss->lifetime = (uint32_t)val64;
TAILQ_INSERT_TAIL(&tmp->rdnss, rdnss, next);
}
/* DNSSL */
TAILQ_INIT(&tmp->dnssl);
for (i = -1; i < MAXDNSSL; i++) {
struct dnssl *dnssl;
struct dnssl_domain *dnsd;
makeentry(entbuf, sizeof(entbuf), i, "dnssl");
@ -642,16 +712,17 @@ getconfig(const char *intface)
if (addr == NULL)
continue;
ELM_MALLOC(dnssl, exit(1));
ELM_MALLOC(dnssl);
TAILQ_INSERT_TAIL(&tmp->dnssl, dnssl, next);
TAILQ_INIT(&dnssl->list);
for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) {
c = strcspn(ap, ",");
strncpy(abuf, ap, c);
abuf[c] = '\0';
ELM_MALLOC(dnsd, exit(1));
dnsd->len = encode_domain(dnsd->domain, abuf);
ELM_MALLOC(dnsd);
TAILQ_INSERT_TAIL(&dnssl->list, dnsd, next);
dnsd->len = encode_domain(dnsd->domain, abuf);
}
makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
@ -661,11 +732,44 @@ getconfig(const char *intface)
{
syslog(LOG_ERR, "<%s> %s (%lld) on %s is invalid",
__func__, entbuf, (long long)val64, intface);
exit(1);
goto errexit;
}
dnssl->lifetime = (uint32_t)val64;
TAILQ_INSERT_TAIL(&tmp->dnssl, dnssl, next);
}
/* If we are advertising an existing RA configuration,
* expire it */
TAILQ_FOREACH(rai, &ralist, next) {
if (rai->ifindex == tmp->ifindex) {
TAILQ_REMOVE(&ralist, rai, next);
/* If we already have a leaving RA use that
* as this config hasn't been advertised */
if (rai->leaving) {
tmp->leaving = rai->leaving;
free_rainfo(rai);
rai = tmp->leaving;
rai->leaving_for = tmp;
break;
}
rai->lifetime = 0;
TAILQ_FOREACH(rdnss, &rai->rdnss, next)
rdnss->lifetime = 0;
TAILQ_FOREACH(dnssl, &rai->dnssl, next)
dnssl->lifetime = 0;
rai->leaving_for = tmp;
tmp->leaving = rai;
rai->mininterval = MIN_DELAY_BETWEEN_RAS;
rai->maxinterval = MIN_DELAY_BETWEEN_RAS;
rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS;
if (rai->timer == NULL)
rai->timer = rtadvd_add_timer(ra_timeout,
ra_timer_update,
rai, rai);
ra_timer_update((void *)rai, &rai->timer->tm);
rtadvd_set_timer(&rai->timer->tm, rai->timer);
break;
}
}
/* okey */
@ -675,10 +779,18 @@ getconfig(const char *intface)
make_packet(tmp);
/* set timer */
if (rai)
return;
tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
tmp, tmp);
ra_timer_update((void *)tmp, &tmp->timer->tm);
rtadvd_set_timer(&tmp->timer->tm, tmp->timer);
ra_timer_set_short_delay(tmp);
return;
errexit:
if (exithard)
exit(1);
free_rainfo(tmp);
}
void
@ -839,8 +951,7 @@ delete_prefix(struct prefix *prefix)
__func__, inet_ntop(AF_INET6, &prefix->prefix,
ntopbuf, INET6_ADDRSTRLEN),
prefix->prefixlen, rai->ifname);
if (prefix->timer)
rtadvd_remove_timer(&prefix->timer);
rtadvd_remove_timer(&prefix->timer);
free(prefix);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: config.h,v 1.8 2011/12/11 20:44:44 christos Exp $ */
/* $NetBSD: config.h,v 1.9 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: config.h,v 1.9 2003/08/06 04:19:40 ono Exp $ */
/*
@ -30,7 +30,8 @@
* SUCH DAMAGE.
*/
extern void getconfig(const char *);
extern void free_rainfo(struct rainfo *);
extern void getconfig(const char *, int);
extern void delete_prefix(struct prefix *);
extern void invalidate_prefix(struct prefix *);
extern void update_prefix(struct prefix *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: dump.c,v 1.9 2011/12/10 19:14:29 roy Exp $ */
/* $NetBSD: dump.c,v 1.10 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: dump.c,v 1.34 2004/06/14 05:35:59 itojun Exp $ */
/*
@ -35,6 +35,9 @@
#include <net/if.h>
#include <net/if_dl.h>
#ifdef __FreeBSD__
#include <net/if_var.h>
#endif
#include <netinet/in.h>
@ -103,8 +106,7 @@ if_dump(void)
fprintf(fp, "%s:\n", rai->ifname);
fprintf(fp, " Status: %s\n",
(iflist[rai->ifindex]->ifm_flags & IFF_UP) ? "UP" :
"DOWN");
(rai->ifflags & IFF_UP) ? "UP" : "DOWN");
/* control information */
if (rai->lastsent.tv_sec) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.c,v 1.21 2011/12/12 01:11:33 roy Exp $ */
/* $NetBSD: if.c,v 1.22 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: if.c,v 1.36 2004/11/30 22:32:01 suz Exp $ */
/*
@ -31,13 +31,18 @@
*/
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_types.h>
#include <ifaddrs.h>
#ifdef __FreeBSD__
#include <net/ethernet.h>
#else
#include <net/if_ether.h>
#endif
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet/in.h>
@ -47,6 +52,7 @@
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "rtadvd.h"
#include "if.h"
@ -56,15 +62,6 @@
#define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
#endif
struct if_msghdr **iflist;
int iflist_init_ok;
size_t ifblock_size;
char *ifblock;
static void get_iflist(char **buf, size_t *size);
static void parse_iflist(struct if_msghdr ***ifmlist_p, char *buf,
size_t bufsize);
static void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
@ -111,44 +108,22 @@ if_nametosdl(const char *name)
int
if_getmtu(const char *name)
{
struct ifaddrs *ifap, *ifa;
struct if_data *ifd;
u_long mtu = 0;
struct ifreq ifr;
int s, mtu;
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, &ifr) < 0) {
close(s);
return(0);
}
close(s);
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
return 0;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET6;
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
}
#endif
else
mtu = 0;
close(s);
return(mtu);
return mtu;
}
/* give interface index and its old flags, then new flags returned */
@ -164,6 +139,7 @@ if_getflags(int ifindex, int oifflags)
return (oifflags & ~IFF_UP);
}
memset(&ifr, 0, sizeof(ifr));
if_indextoname(ifindex, ifr.ifr_name);
if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s",
@ -288,6 +264,9 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
*lenp = ifam->ifam_msglen;
return (char *)rtm;
/* NOTREACHED */
#ifdef RTM_IFANNOUNCE
case RTM_IFANNOUNCE:
#endif
case RTM_IFINFO:
/* found */
*lenp = rtm->rtm_msglen;
@ -348,6 +327,24 @@ get_ifm_flags(char *buf)
return (ifm->ifm_flags);
}
#ifdef RTM_IFANNOUNCE
int
get_ifan_ifindex(char *buf)
{
struct if_announcemsghdr *ifan = (struct if_announcemsghdr *)buf;
return ((int)ifan->ifan_index);
}
int
get_ifan_what(char *buf)
{
struct if_announcemsghdr *ifan = (struct if_announcemsghdr *)buf;
return ((int)ifan->ifan_what);
}
#endif
int
get_prefixlen(char *buf)
{
@ -420,122 +417,3 @@ rtmsg_len(char *buf)
return(rtm->rtm_msglen);
}
int
ifmsg_len(char *buf)
{
struct if_msghdr *ifm = (struct if_msghdr *)buf;
return(ifm->ifm_msglen);
}
/*
* alloc buffer and get if_msghdrs block from kernel,
* and put them into the buffer
*/
static void
get_iflist(char **buf, size_t *size)
{
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__);
exit(1);
}
if ((*buf = malloc(*size)) == 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__);
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;
/*
* 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(void *);
if ((*ifmlist_p = (struct if_msghdr **)malloc(malloc_size)) == NULL) {
syslog(LOG_ERR, "<%s> malloc failed", __func__);
exit(1);
}
lim = buf + bufsize;
for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
if (ifm->ifm_msglen == 0) {
syslog(LOG_WARNING, "<%s> ifm_msglen is 0 "
"(buf=%p lim=%p ifm=%p)", __func__,
buf, lim, ifm);
return;
}
if (ifm->ifm_type == RTM_IFINFO) {
(*ifmlist_p)[ifm->ifm_index] = ifm;
} else {
syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n"
"expected %d, got %d\n msglen = %d\n"
"buf:%p, ifm:%p, lim:%p\n",
RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
buf, ifm, lim);
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;
}
ifm = (struct if_msghdr *)ifam;
}
}
void
init_iflist()
{
if (ifblock) {
free(ifblock);
ifblock_size = 0;
}
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);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.h,v 1.9 2011/12/11 20:44:44 christos Exp $ */
/* $NetBSD: if.h,v 1.10 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: if.h,v 1.12 2003/09/21 07:17:03 itojun Exp $ */
/*
@ -32,10 +32,6 @@
#define RTADV_TYPE2BITMASK(type) (0x1 << type)
extern struct if_msghdr **iflist;
extern size_t ifblock_size;
extern char *ifblock;
struct nd_opt_hdr;
struct sockaddr_dl *if_nametosdl(const char *);
int if_getmtu(const char *);
@ -48,10 +44,11 @@ int get_rtm_ifindex(char *);
int get_ifm_ifindex(char *);
int get_ifam_ifindex(char *);
int get_ifm_flags(char *);
#ifdef RTM_IFANNOUNCE
int get_ifan_ifindex(char *);
int get_ifan_what(char *);
#endif
int get_prefixlen(char *);
int prefixlen(const unsigned char *, const unsigned char *);
int rtmsg_type(char *);
int ifmsg_type(char *);
int rtmsg_len(char *);
int ifmsg_len(char *);
void init_iflist(void);

View File

@ -1,4 +1,4 @@
/* $NetBSD: rrenum.c,v 1.14 2011/12/10 19:14:29 roy Exp $ */
/* $NetBSD: rrenum.c,v 1.15 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: rrenum.c,v 1.14 2004/06/14 05:36:00 itojun Exp $ */
/*
@ -36,6 +36,9 @@
#include <sys/sysctl.h>
#include <net/if.h>
#ifdef __FreeBSD__
#include <net/if_var.h>
#endif
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
@ -175,9 +178,9 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
irr->irr_u_uselen = rpu->rpu_uselen;
irr->irr_u_keeplen = rpu->rpu_keeplen;
irr->irr_raf_mask_onlink =
(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
irr->irr_raf_mask_auto =
(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
irr->irr_vltime = ntohl(rpu->rpu_vltime);
irr->irr_pltime = ntohl(rpu->rpu_pltime);
irr->irr_raf_onlink =
@ -241,6 +244,7 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
{
int ifindex = 0;
struct in6_rrenumreq irr;
struct rainfo *rai;
if ((rr_pco_check(len, rpm) != 0))
return 1;
@ -260,16 +264,19 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
irr.irr_matchprefix.sin6_family = AF_INET6;
irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix;
while (if_indextoname(++ifindex, irr.irr_name)) {
/*
* if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off,
* the interface is not applied
*/
if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
(iflist[ifindex]->ifm_flags & IFF_UP) == 0)
continue;
/* TODO: interface scope check */
do_use_prefix(len, rpm, &irr, ifindex);
/*
* 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) {
while (if_indextoname(++ifindex, irr.irr_name)) {
rai = if_indextorainfo(ifindex);
if (rai && (rai->ifflags & IFF_UP)) {
/* TODO: interface scope check */
do_use_prefix(len, rpm, &irr, ifindex);
}
}
}
if (errno == ENXIO)
return 0;
@ -296,9 +303,6 @@ do_rr(size_t 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();
while (cp < lim) {
size_t rpmlen;

View File

@ -1,4 +1,4 @@
.\" $NetBSD: rtadvd.8,v 1.22 2011/04/28 12:12:47 wiz Exp $
.\" $NetBSD: rtadvd.8,v 1.23 2012/12/13 15:36:36 roy Exp $
.\" $KAME: rtadvd.8,v 1.24 2002/05/31 16:16:08 jinmei Exp $
.\"
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd March 5, 2006
.Dd December 13, 2006
.Dt RTADVD 8
.Os
.Sh NAME
@ -36,8 +36,9 @@
.Nd router advertisement daemon
.Sh SYNOPSIS
.Nm
.Op Fl DdfMRs
.Op Fl DdfRs
.Op Fl c Ar configfile
.Op Fl M Ar ifname
.Ar interface ...
.Sh DESCRIPTION
.Nm
@ -126,7 +127,7 @@ Print debugging information.
.It Fl f
Foreground mode (useful when debugging).
Log messages will be dumped to stderr when this option is specified.
.It Fl M
.It Fl M Ar ifname
Specify an interface to join the all-routers site-local multicast group.
By default,
.Nm
@ -155,6 +156,17 @@ Do not add or delete prefixes dynamically.
Only statically configured prefixes, if any, will be advertised.
.El
.Pp
Use
.Dv SIGHUP
to reload the configuration file
.Pa /etc/rtadvd.conf.
If an invalid parameter is found in the configuration file upon the reload, the
entry will be ignored and the old configuration will be used.
When parameters in an existing entry are updated,
.Nm
will send Router Advertisement messages with the old configuration but zero
router lifetime to the interface first, and then start to send a new message.
.Pp
Upon receipt of signal
.Dv SIGUSR1 ,
.Nm

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtadvd.c,v 1.38 2011/12/11 20:44:44 christos Exp $ */
/* $NetBSD: rtadvd.c,v 1.39 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: rtadvd.c,v 1.92 2005/10/17 14:40:02 suz Exp $ */
/*
@ -54,7 +54,9 @@
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
#ifdef __NetBSD__
#include <util.h>
#endif
#include <poll.h>
#include "rtadvd.h"
@ -68,9 +70,10 @@
struct msghdr rcvmhdr;
static unsigned char *rcvcmsgbuf;
static size_t rcvcmsgbuflen;
static unsigned char *sndcmsgbuf = NULL;
static unsigned char *sndcmsgbuf;
static size_t sndcmsgbuflen;
volatile sig_atomic_t do_dump;
volatile sig_atomic_t do_reconf;
volatile sig_atomic_t do_die;
struct msghdr sndmhdr;
struct iovec rcviov[2];
@ -83,6 +86,9 @@ int rtsock = -1;
int accept_rr = 0;
int dflag = 0, sflag = 0;
static char **if_argv;
static int if_argc;
char *conffile = NULL;
struct ralist_head_t ralist = TAILQ_HEAD_INITIALIZER(ralist);
@ -147,7 +153,8 @@ struct sockaddr_in6 sin6_sitelocal_allrouters = {
};
static void set_die(int);
static void die(void) __dead;
static void die(void); // XXX __dead;
static void set_reconf(int);
static void sock_open(void);
static void rtsock_open(void);
static void rtadvd_input(void);
@ -155,14 +162,13 @@ static void rs_input(int, struct nd_router_solicit *,
struct in6_pktinfo *, struct sockaddr_in6 *);
static void ra_input(int, struct nd_router_advert *,
struct in6_pktinfo *, struct sockaddr_in6 *);
static struct rainfo *ra_output(struct rainfo *);
static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
struct sockaddr_in6 *);
static int nd6_options(struct nd_opt_hdr *, int, union nd_opts *, uint32_t);
static void free_ndopts(union nd_opts *);
static void ra_output(struct rainfo *);
static void rtmsg_input(void);
static void rtadvd_set_dump_file(int);
static void set_short_delay(struct rainfo *);
int
main(int argc, char *argv[])
@ -207,8 +213,8 @@ main(int argc, char *argv[])
argv += optind;
if (argc == 0) {
fprintf(stderr,
"usage: rtadvd [-DdfMRs] [-c configfile] "
"interface ...\n");
"usage: rtadvd [-DdfRs] [-c conffile]"
" [-M ifname] interface ...\n");
exit(1);
}
@ -226,23 +232,24 @@ main(int argc, char *argv[])
/* timer initialization */
rtadvd_timer_init();
/* get iflist block from kernel */
init_iflist();
if_argc = argc;
if_argv = argv;
while (argc--)
getconfig(*argv++);
getconfig(*argv++, 1);
if (!fflag)
daemon(1, 0);
sock_open();
#ifdef __NetBSD__
/* record the current PID */
if (pidfile(NULL) < 0) {
syslog(LOG_ERR,
"<%s> failed to open the pid log file, run anyway.",
__func__);
}
#endif
set[0].fd = sock;
set[0].events = POLLIN;
@ -254,6 +261,7 @@ main(int argc, char *argv[])
set[1].fd = -1;
signal(SIGTERM, set_die);
signal(SIGHUP, set_reconf);
signal(SIGUSR1, rtadvd_set_dump_file);
for (;;) {
@ -262,6 +270,16 @@ main(int argc, char *argv[])
rtadvd_dump_file(dumpfilename);
}
if (do_reconf) { /* SIGHUP */
do_reconf = 0;
syslog(LOG_INFO, "<%s> reloading config on SIGHUP",
__func__);
argc = if_argc;
argv = if_argv;
while (argc--)
getconfig(*argv++, 0);
}
if (do_die) {
die();
/*NOTREACHED*/
@ -301,21 +319,32 @@ main(int argc, char *argv[])
}
static void
rtadvd_set_dump_file(int sig)
rtadvd_set_dump_file(__unused int sig)
{
do_dump = 1;
}
static void
set_die(int sig)
set_reconf(__unused int sig)
{
do_reconf = 1;
}
static void
set_die(__unused int sig)
{
do_die = 1;
}
static void
die(void)
{
struct rainfo *ra;
struct rainfo *rai;
struct rdnss *rdnss;
struct dnssl *dnssl;
int i;
const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
@ -324,15 +353,29 @@ die(void)
__func__);
}
TAILQ_FOREACH(ra, &ralist, next) {
ra->lifetime = 0;
make_packet(ra);
TAILQ_FOREACH(rai, &ralist, next) {
rai->lifetime = 0;
TAILQ_FOREACH(rdnss, &rai->rdnss, next)
rdnss->lifetime = 0;
TAILQ_FOREACH(dnssl, &rai->dnssl, next)
dnssl->lifetime = 0;
make_packet(rai);
}
for (i = 0; i < retrans; i++) {
TAILQ_FOREACH(ra, &ralist, next)
ra_output(ra);
sleep(MIN_DELAY_BETWEEN_RAS);
TAILQ_FOREACH(rai, &ralist, next)
ra_output(rai);
//sleep(MIN_DELAY_BETWEEN_RAS);
}
while ((rai = TAILQ_FIRST(&ralist))) {
TAILQ_REMOVE(&ralist, rai, next);
if (rai->leaving)
free_rainfo(rai->leaving);
free_rainfo(rai);
}
free(rcvcmsgbuf);
free(sndcmsgbuf);
exit(0);
/*NOTREACHED*/
}
@ -346,19 +389,21 @@ rtmsg_input(void)
struct rt_msghdr rt_msghdr;
char data[2048];
} buffer;
char *msg, *next, *lim;
char *msg, *next, *lim, **argv;
char ifname[IF_NAMESIZE];
struct prefix *prefix;
struct rainfo *rai;
struct in6_addr *addr;
char addrbuf[INET6_ADDRSTRLEN];
int prefixchange = 0;
int prefixchange = 0, argc;
memset(&buffer, 0, sizeof(buffer));
n = read(rtsock, &buffer, sizeof(buffer));
msg = buffer.data;
if (dflag > 1) {
syslog(LOG_DEBUG, "<%s> received a routing message "
"(type = %d, len = %d)", __func__, rtmsg_type(msg), n);
"(type = %d, len = %d)", __func__, rtmsg_type(msg),
rtmsg_len(msg));
}
if (n > rtmsg_len(msg)) {
/*
@ -386,6 +431,9 @@ rtmsg_input(void)
RTADV_TYPE2BITMASK(RTM_DELETE) |
RTADV_TYPE2BITMASK(RTM_NEWADDR) |
RTADV_TYPE2BITMASK(RTM_DELADDR) |
#ifdef RTM_IFANNOUNCE
RTADV_TYPE2BITMASK(RTM_IFANNOUNCE) |
#endif
RTADV_TYPE2BITMASK(RTM_IFINFO));
if (len == 0)
break;
@ -399,6 +447,30 @@ rtmsg_input(void)
case RTM_DELADDR:
ifindex = get_ifam_ifindex(next);
break;
#ifdef RTM_IFANNOUNCE
case RTM_IFANNOUNCE:
ifindex = get_ifan_ifindex(next);
if (get_ifan_what(next) == IFAN_ARRIVAL) {
syslog(LOG_DEBUG,
"<%s> interface %s arrived",
__func__,
if_indextoname(ifindex, ifname));
if (if_argc == 0) {
getconfig(ifname, 0);
continue;
}
argc = if_argc;
argv = if_argv;
while (argc--) {
if (strcmp(ifname, *argv++) == 0) {
getconfig(ifname, 0);
break;
}
}
continue;
}
break;
#endif
case RTM_IFINFO:
ifindex = get_ifm_ifindex(next);
break;
@ -417,19 +489,19 @@ rtmsg_input(void)
if (dflag > 1) {
syslog(LOG_DEBUG,
"<%s> route changed on "
"non advertising interface(%s)",
"non advertising interface %s (%d)",
__func__,
if_indextoname(ifindex, ifname));
if_indextoname(ifindex, ifname),
ifindex);
}
continue;
}
oldifflags = iflist[ifindex]->ifm_flags;
oldifflags = rai->ifflags;
switch (type) {
case RTM_ADD:
/* init ifflags because it may have changed */
iflist[ifindex]->ifm_flags =
if_getflags(ifindex, iflist[ifindex]->ifm_flags);
rai->ifflags = if_getflags(ifindex, rai->ifflags);
if (sflag)
break; /* we aren't interested in prefixes */
@ -470,8 +542,7 @@ rtmsg_input(void)
break;
case RTM_DELETE:
/* init ifflags because it may have changed */
iflist[ifindex]->ifm_flags =
if_getflags(ifindex, iflist[ifindex]->ifm_flags);
rai->ifflags = if_getflags(ifindex, rai->ifflags);
if (sflag)
break;
@ -507,12 +578,25 @@ rtmsg_input(void)
case RTM_NEWADDR:
case RTM_DELADDR:
/* init ifflags because it may have changed */
iflist[ifindex]->ifm_flags =
if_getflags(ifindex, iflist[ifindex]->ifm_flags);
rai->ifflags = if_getflags(ifindex, rai->ifflags);
break;
case RTM_IFINFO:
iflist[ifindex]->ifm_flags = get_ifm_flags(next);
rai->ifflags = get_ifm_flags(next);
break;
#ifdef RTM_IFANNOUNCE
case RTM_IFANNOUNCE:
if (get_ifan_what(next) == IFAN_DEPARTURE) {
syslog(LOG_DEBUG,
"<%s> interface %s departed",
__func__, rai->ifname);
TAILQ_REMOVE(&ralist, rai, next);
if (rai->leaving)
free_rainfo(rai->leaving);
free_rainfo(rai);
continue;
}
break;
#endif
default:
/* should not reach here */
if (dflag > 1) {
@ -526,31 +610,31 @@ rtmsg_input(void)
/* check if an interface flag is changed */
if ((oldifflags & IFF_UP) != 0 && /* UP to DOWN */
(iflist[ifindex]->ifm_flags & IFF_UP) == 0) {
(rai->ifflags & IFF_UP) == 0) {
syslog(LOG_INFO,
"<%s> interface %s becomes down. stop timer.",
__func__, rai->ifname);
rtadvd_remove_timer(&rai->timer);
} else if ((oldifflags & IFF_UP) == 0 && /* DOWN to UP */
(iflist[ifindex]->ifm_flags & IFF_UP) != 0) {
(rai->ifflags & IFF_UP) != 0) {
syslog(LOG_INFO,
"<%s> interface %s becomes up. restart timer.",
__func__, rai->ifname);
rai->initcounter = 0; /* reset the counter */
rai->waiting = 0; /* XXX */
rtadvd_remove_timer(&rai->timer);
rai->timer = rtadvd_add_timer(ra_timeout,
ra_timer_update, rai, rai);
ra_timer_update((void *)rai, &rai->timer->tm);
rtadvd_set_timer(&rai->timer->tm, rai->timer);
} else if (prefixchange &&
iflist[ifindex]->ifm_flags & IFF_UP) {
} else if (prefixchange && rai->ifflags & IFF_UP) {
/*
* An advertised prefix has been added or invalidated.
* Will notice the change in a short delay.
*/
rai->initcounter = 0;
set_short_delay(rai);
ra_timer_set_short_delay(rai);
}
}
@ -571,6 +655,7 @@ rtadvd_input(void)
struct in6_pktinfo *pi = NULL;
char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
struct in6_addr dst = in6addr_any;
struct rainfo *rai;
/*
* Get message. We reset msg_controllen since the field could
@ -610,11 +695,21 @@ rtadvd_input(void)
return;
}
if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) {
if (dflag > 1) {
syslog(LOG_DEBUG,
"<%s> received data for non advertising "
"interface (%s)",
__func__,
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
}
return;
}
/*
* If we happen to receive data on an interface which is now down,
* just discard the data.
*/
if ((iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) {
if ((rai->ifflags & IFF_UP) == 0) {
syslog(LOG_INFO,
"<%s> received data on a disabled interface (%s)",
__func__,
@ -750,7 +845,7 @@ rs_input(int len, struct nd_router_solicit *rs,
{
char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
union nd_opts ndopts;
struct rainfo *ra;
struct rainfo *rai;
struct soliciter *sol;
syslog(LOG_DEBUG,
@ -790,11 +885,7 @@ rs_input(int len, struct nd_router_solicit *rs,
goto done;
}
TAILQ_FOREACH(ra, &ralist, next) {
if (pi->ipi6_ifindex == ra->ifindex)
break;
}
if (ra == NULL) {
if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) {
syslog(LOG_INFO,
"<%s> RS received on non advertising interface(%s)",
__func__,
@ -802,7 +893,14 @@ rs_input(int len, struct nd_router_solicit *rs,
goto done;
}
ra->rsinput++; /* increment statistics */
if (rai->leaving) {
syslog(LOG_INFO,
"<%s> RS received on reconfiguring advertising interface(%s)",
__func__, rai->ifname);
goto done;
}
rai->rsinput++; /* increment statistics */
/*
* Decide whether to send RA according to the rate-limit
@ -815,25 +913,25 @@ rs_input(int len, struct nd_router_solicit *rs,
sol->addr = *from;
/* XXX RFC2553 need clarification on flowinfo */
sol->addr.sin6_flowinfo = 0;
TAILQ_INSERT_HEAD(&ra->soliciter, sol, next);
TAILQ_INSERT_HEAD(&rai->soliciter, sol, next);
}
/*
* If there is already a waiting RS packet, don't
* update the timer.
*/
if (ra->waiting++)
if (rai->waiting++)
goto done;
set_short_delay(ra);
ra_timer_set_short_delay(rai);
done:
free_ndopts(&ndopts);
return;
}
static void
set_short_delay(struct rainfo *rai)
void
ra_timer_set_short_delay(struct rainfo *rai)
{
long delay; /* must not be greater than 1000000 */
struct timeval interval, now, min_delay, tm_tmp, *rest;
@ -923,6 +1021,12 @@ ra_input(int len, struct nd_router_advert *ra,
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
goto done;
}
if (rai->leaving) {
syslog(LOG_DEBUG,
"<%s> recieved RA on re-configuring interface (%s)",
__func__, rai->ifname);
goto done;
}
rai->rainput++; /* increment statistics */
/* Cur Hop Limit value */
@ -1494,25 +1598,25 @@ if_indextorainfo(unsigned int idx)
return(NULL); /* search failed */
}
static void
ra_output(struct rainfo *rainfo)
struct rainfo *
ra_output(struct rainfo *rai)
{
int i;
struct cmsghdr *cm;
struct in6_pktinfo *pi;
struct soliciter *sol;
if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) {
if ((rai->ifflags & IFF_UP) == 0) {
syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA",
__func__, rainfo->ifname);
return;
__func__, rai->ifname);
return NULL;
}
make_packet(rainfo); /* XXX: inefficient */
make_packet(rai); /* XXX: inefficient */
sndmhdr.msg_name = (void *)&sin6_linklocal_allnodes;
sndmhdr.msg_iov[0].iov_base = (void *)rainfo->ra_data;
sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen;
sndmhdr.msg_iov[0].iov_base = (void *)rai->ra_data;
sndmhdr.msg_iov[0].iov_len = rai->ra_datalen;
cm = CMSG_FIRSTHDR(&sndmhdr);
/* specify the outgoing interface */
@ -1521,7 +1625,7 @@ ra_output(struct rainfo *rainfo)
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
pi = (struct in6_pktinfo *)CMSG_DATA(cm);
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
pi->ipi6_ifindex = rainfo->ifindex;
pi->ipi6_ifindex = rai->ifindex;
/* specify the hop limit of the packet */
{
@ -1536,14 +1640,14 @@ ra_output(struct rainfo *rainfo)
syslog(LOG_DEBUG,
"<%s> send RA on %s, # of waitings = %d",
__func__, rainfo->ifname, rainfo->waiting);
__func__, rai->ifname, rai->waiting);
i = sendmsg(sock, &sndmhdr, 0);
if (i < 0 || (size_t)i != rainfo->ra_datalen) {
if (i < 0 || (size_t)i != rai->ra_datalen) {
if (i < 0) {
syslog(LOG_ERR, "<%s> sendmsg on %s: %s",
__func__, rainfo->ifname,
__func__, rai->ifname,
strerror(errno));
}
}
@ -1553,33 +1657,51 @@ ra_output(struct rainfo *rainfo)
* XXX commented out. reason: though spec does not forbit it, unicast
* advert does not really help
*/
while ((sol = TAILQ_FIRST(&rainfo->soliciter)) != NULL) {
while ((sol = TAILQ_FIRST(&rai->soliciter)) != NULL) {
#if 0
sndmhdr.msg_name = (void *)&sol->addr;
i = sendmsg(sock, &sndmhdr, 0);
if (i < 0 || i != rainfo->ra_datalen) {
if (i < 0 || i != rai->ra_datalen) {
if (i < 0) {
syslog(LOG_ERR,
"<%s> unicast sendmsg on %s: %s",
__func__, rainfo->ifname,
__func__, rai->ifname,
strerror(errno));
}
}
#endif
TAILQ_REMOVE(&rainfo->soliciter, sol, next);
TAILQ_REMOVE(&rai->soliciter, sol, next);
free(sol);
}
if (rai->leaving_adv > 0) {
if (--(rai->leaving_adv) == 0) {
syslog(LOG_DEBUG,
"<%s> expired RA,"
" new config active for interface (%s)",
__func__, rai->ifname);
rai->leaving_for->timer = rtadvd_add_timer(ra_timeout,
ra_timer_update,
rai->leaving_for, rai->leaving_for);
ra_timer_set_short_delay(rai->leaving_for);
rai->leaving_for->leaving = NULL;
free_rainfo(rai);
return NULL;
}
}
/* update counter */
if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
rainfo->initcounter++;
rainfo->raoutput++;
if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
rai->initcounter++;
rai->raoutput++;
/* update timestamp */
gettimeofday(&rainfo->lastsent, NULL);
gettimeofday(&rai->lastsent, NULL);
/* reset waiting conter */
rainfo->waiting = 0;
rai->waiting = 0;
return rai;
}
/* process RA timer */
@ -1596,9 +1718,9 @@ ra_timeout(void *data)
"<%s> RA timer on %s is expired",
__func__, rai->ifname);
ra_output(rai);
return(rai->timer);
if (ra_output(rai))
return(rai->timer);
return NULL;
}
/* update RA timer */
@ -1614,8 +1736,9 @@ ra_timer_update(void *data, struct timeval *tm)
* between the interface's configured MinRtrAdvInterval and
* MaxRtrAdvInterval (RFC2461 6.2.4).
*/
interval = rai->mininterval;
interval += arc4random() % (rai->maxinterval - rai->mininterval);
interval = rai->mininterval;
if (rai->mininterval != rai->maxinterval)
interval += arc4random() % (rai->maxinterval-rai->mininterval);
/*
* For the first few advertisements (up to

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtadvd.h,v 1.11 2011/12/10 19:14:29 roy Exp $ */
/* $NetBSD: rtadvd.h,v 1.12 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: rtadvd.h,v 1.30 2005/10/17 14:40:02 suz Exp $ */
/*
@ -137,9 +137,13 @@ struct rainfo {
int initcounter; /* counter for the first few advertisements */
struct timeval lastsent; /* timestamp when the latest RA was sent */
int waiting; /* number of RS waiting for RA */
struct rainfo *leaving; /* the config which is leaving */
struct rainfo *leaving_for; /* the new config to activate */
int leaving_adv; /* number of RA left to send */
/* interface information */
uint16_t ifindex;
int ifflags;
int advlinkopt; /* bool: whether include link-layer addr opt */
struct sockaddr_dl *sdl;
char ifname[16];
@ -183,6 +187,7 @@ extern TAILQ_HEAD(ralist_head_t, rainfo) ralist;
struct rtadvd_timer *ra_timeout(void *);
void ra_timer_update(void *, struct timeval *);
void ra_timer_set_short_delay(struct rainfo *);
int prefix_match(struct in6_addr *, int, struct in6_addr *, int);
struct rainfo *if_indextorainfo(unsigned int);

View File

@ -1,4 +1,4 @@
/* $NetBSD: timer.c,v 1.10 2011/12/10 19:14:29 roy Exp $ */
/* $NetBSD: timer.c,v 1.11 2012/12/13 15:36:36 roy Exp $ */
/* $KAME: timer.c,v 1.11 2005/04/14 06:22:35 suz Exp $ */
/*
@ -93,9 +93,11 @@ void
rtadvd_remove_timer(struct rtadvd_timer **timer)
{
TAILQ_REMOVE(&ra_timer, *timer, next);
free(*timer);
*timer = NULL;
if (*timer) {
TAILQ_REMOVE(&ra_timer, *timer, next);
free(*timer);
*timer = NULL;
}
}
void
@ -125,12 +127,12 @@ rtadvd_check_timer(void)
{
static struct timeval returnval;
struct timeval now;
struct rtadvd_timer *tm;
struct rtadvd_timer *tm, *tmn;
gettimeofday(&now, NULL);
tm_max = tm_limit;
TAILQ_FOREACH(tm, &ra_timer, next) {
TAILQ_FOREACH_SAFE(tm, &ra_timer, next, tmn) {
if (TIMEVAL_LEQ(tm->tm, now)) {
if ((*tm->expire)(tm->expire_data) == NULL)
continue; /* the timer was removed */