Index: head/usr.sbin/rtadvd/advcap.c =================================================================== --- head/usr.sbin/rtadvd/advcap.c (revision 71332) +++ head/usr.sbin/rtadvd/advcap.c (revision 71333) @@ -1,455 +1,454 @@ +/* $FreeBSD$ */ /* $KAME: advcap.c,v 1.3 2000/05/16 13:34:13 itojun Exp $ */ /* * Copyright (c) 1983 The Regents of the University of California. * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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$ */ /* * remcap - routines for dealing with the remote host data base * * derived from termcap */ #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" #ifndef BUFSIZ #define BUFSIZ 1024 #endif #define MAXHOP 32 /* max number of tc= indirections */ #define tgetent agetent #define tnchktc anchktc #define tnamatch anamatch #define tgetnum agetnum #define tgetflag agetflag #define tgetstr agetstr #if 0 #define V_TERMCAP "REMOTE" #define V_TERM "HOST" #endif char *RM; /* * termcap - routines for dealing with the terminal capability data base * * BUG: Should use a "last" pointer in tbuf, so that searching * for capabilities alphabetically would not be a n**2/2 * process when large numbers of capabilities are given. * Note: If we add a last pointer now we will screw up the * tc capability. We really should compile termcap. * * Essentially all the work here is scanning and decoding escapes * in string capabilities. We don't use stdio because the editor * doesn't, and because living w/o it is not hard. */ static char *tbuf; static int hopcount; /* detect infinite loops in termcap, init 0 */ static char *remotefile; extern char *conffile; int tgetent __P((char *, char *)); int getent __P((char *, char *, char *)); int tnchktc __P((void)); int tnamatch __P((char *)); static char *tskip __P((char *)); int tgetnum __P((char *)); int tgetflag __P((char *)); char *tgetstr __P((char *, char **)); static char *tdecode __P((char *, char **)); /* * Get an entry for terminal name in buffer bp, * from the termcap file. Parse is very rudimentary; * we just notice escaped newlines. */ int tgetent(bp, name) char *bp, *name; { char *cp; remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF; return (getent(bp, name, cp)); } int getent(bp, name, cp) char *bp, *name, *cp; { register int c; register int i = 0, cnt = 0; char ibuf[BUFSIZ]; int tf; tbuf = bp; tf = 0; /* * TERMCAP can have one of two things in it. It can be the * name of a file to use instead of /etc/termcap. In this * case it better start with a "/". Or it can be an entry to * use so we don't have to read the file. In this case it * has to already have the newlines crunched out. */ if (cp && *cp) { tf = open(RM = cp, O_RDONLY); } if (tf < 0) { syslog(LOG_INFO, "<%s> open: %s", __FUNCTION__, strerror(errno)); return (-2); } for (;;) { cp = bp; for (;;) { if (i == cnt) { cnt = read(tf, ibuf, BUFSIZ); if (cnt <= 0) { close(tf); return (0); } i = 0; } c = ibuf[i++]; if (c == '\n') { if (cp > bp && cp[-1] == '\\') { cp--; continue; } break; } if (cp >= bp+BUFSIZ) { write(2,"Remcap entry too long\n", 23); break; } else *cp++ = c; } *cp = 0; /* * The real work for the match. */ if (tnamatch(name)) { close(tf); return (tnchktc()); } } } /* * tnchktc: check the last entry, see if it's tc=xxx. If so, * recursively find xxx and append that entry (minus the names) * to take the place of the tc=xxx entry. This allows termcap * entries to say "like an HP2621 but doesn't turn on the labels". * Note that this works because of the left to right scan. */ int tnchktc() { register char *p, *q; char tcname[16]; /* name of similar terminal */ char tcbuf[BUFSIZ]; char *holdtbuf = tbuf; int l; p = tbuf + strlen(tbuf) - 2; /* before the last colon */ while (*--p != ':') if (p MAXHOP) { write(2, "Infinite tc= loop\n", 18); return (0); } if (getent(tcbuf, tcname, remotefile) != 1) { return (0); } for (q = tcbuf; *q++ != ':'; ) ; l = p - holdtbuf + strlen(q); if (l > BUFSIZ) { write(2, "Remcap entry too long\n", 23); q[BUFSIZ - (p-holdtbuf)] = 0; } strcpy(p, q); tbuf = holdtbuf; return (1); } /* * Tnamatch deals with name matching. The first field of the termcap * entry is a sequence of names separated by |'s, so we compare * against each such name. The normal : terminator after the last * name (before the first field) stops us. */ int tnamatch(np) char *np; { register char *Np, *Bp; Bp = tbuf; if (*Bp == '#') return (0); for (;;) { for (Np = np; *Np && *Bp == *Np; Bp++, Np++) continue; if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) return (1); while (*Bp && *Bp != ':' && *Bp != '|') Bp++; if (*Bp == 0 || *Bp == ':') return (0); Bp++; } } /* * Skip to the next field. Notice that this is very dumb, not * knowing about \: escapes or any such. If necessary, :'s can be put * into the termcap file in octal. */ static char * tskip(bp) register char *bp; { int dquote; dquote = 0; while (*bp) { switch (*bp) { case ':': if (!dquote) goto breakbreak; else bp++; break; case '\\': bp++; if (isdigit(*bp)) { while (isdigit(*bp++)) ; } else bp++; case '"': dquote = (dquote ? 1 : 0); bp++; break; default: bp++; break; } } breakbreak: if (*bp == ':') bp++; return (bp); } /* * Return the (numeric) option id. * Numeric options look like * li#80 * i.e. the option string is separated from the numeric value by * a # character. If the option is not found we return -1. * Note that we handle octal numbers beginning with 0. */ int tgetnum(id) char *id; { register long int i; register int base; register char *bp = tbuf; for (;;) { bp = tskip(bp); if (*bp == 0) return (-1); if (strncmp(bp, id, strlen(id)) != 0) continue; bp += strlen(id); if (*bp == '@') return (-1); if (*bp != '#') continue; bp++; base = 10; if (*bp == '0') base = 8; i = 0; while (isdigit(*bp)) i *= base, i += *bp++ - '0'; return (i); } } /* * Handle a flag option. * Flag options are given "naked", i.e. followed by a : or the end * of the buffer. Return 1 if we find the option, or 0 if it is * not given. */ int tgetflag(id) char *id; { register char *bp = tbuf; for (;;) { bp = tskip(bp); if (!*bp) return (0); if (strncmp(bp, id, strlen(id)) == 0) { bp += strlen(id); if (!*bp || *bp == ':') return (1); else if (*bp == '@') return (0); } } } /* * Get a string valued option. * These are given as * cl=^Z * Much decoding is done on the strings, and the strings are * placed in area, which is a ref parameter which is updated. * No checking on area overflow. */ char * tgetstr(id, area) char *id, **area; { register char *bp = tbuf; for (;;) { bp = tskip(bp); if (!*bp) return (0); if (strncmp(bp, id, strlen(id)) != 0) continue; bp += strlen(id); if (*bp == '@') return (0); if (*bp != '=') continue; bp++; return (tdecode(bp, area)); } } /* * Tdecode does the grung work to decode the * string capability escapes. */ static char * tdecode(str, area) register char *str; char **area; { register char *cp; register int c; register char *dp; int i; char term; term = ':'; cp = *area; again: if (*str == '"') { term = '"'; str++; } while ((c = *str++) && c != term) { switch (c) { case '^': c = *str++ & 037; break; case '\\': dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\""; c = *str++; nextc: if (*dp++ == c) { c = *dp++; break; } dp++; if (*dp) goto nextc; if (isdigit(c)) { c -= '0', i = 2; do c <<= 3, c |= *str++ - '0'; while (--i && isdigit(*str)); } break; } *cp++ = c; } if (c == term && term != ':') { term = ':'; goto again; } *cp++ = 0; str = *area; *area = cp; return (str); } Index: head/usr.sbin/rtadvd/advcap.h =================================================================== --- head/usr.sbin/rtadvd/advcap.h (revision 71332) +++ head/usr.sbin/rtadvd/advcap.h (revision 71333) @@ -1,47 +1,46 @@ +/* $FreeBSD$ */ /* $KAME$ */ /* * Copyright (C) 1994,1995 by Andrey A. Chernov, Moscow, Russia. * 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 AUTHOR ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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$ */ /* Based on Id: termcap.h,v 1.8 1996/09/10 12:42:10 peter Exp */ #ifndef _ADVCAP_H_ #define _ADVCAP_H_ #include __BEGIN_DECLS extern int agetent __P((char *, const char *)); extern int agetflag __P((const char *)); extern int agetnum __P((const char *)); extern char *agetstr __P((const char *, char **)); __END_DECLS #endif /* _ADVCAP_H_ */ Index: head/usr.sbin/rtadvd/config.c =================================================================== --- head/usr.sbin/rtadvd/config.c (revision 71332) +++ head/usr.sbin/rtadvd/config.c (revision 71333) @@ -1,747 +1,746 @@ +/* $FreeBSD$ */ /* $KAME: config.c,v 1.11 2000/05/16 13:34:13 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. - * - * $FreeBSD$ */ #include #include #include #include #include #if defined(__FreeBSD__) && __FreeBSD__ >= 3 #include #endif /* __FreeBSD__ >= 3 */ #include #include #include #include #include #include #include #ifdef MIP6 #include #endif #include #include #include #include #include #include #if defined(__NetBSD__) || defined(__OpenBSD__) #include #endif #include #include "rtadvd.h" #include "advcap.h" #include "timer.h" #include "if.h" #include "config.h" static void makeentry __P((char *, int, char *, int)); static void get_prefix __P((struct rainfo *)); extern struct rainfo *ralist; void getconfig(intface) char *intface; { int stat, pfxs, i; char tbuf[BUFSIZ]; struct rainfo *tmp; long val; char buf[BUFSIZ]; char *bp = buf; char *addr; #define MUSTHAVE(var, cap) \ do { \ int t; \ if ((t = agetnum(cap)) < 0) { \ fprintf(stderr, "rtadvd: need %s for interface %s\n", \ cap, intface); \ exit(1); \ } \ var = t; \ } while (0) #define MAYHAVE(var, cap, def) \ do { \ if ((var = agetnum(cap)) < 0) \ var = def; \ } while (0) if ((stat = agetent(tbuf, intface)) <= 0) { memset(tbuf, 0, sizeof(tbuf)); syslog(LOG_INFO, "<%s> %s isn't defined in the configuration file" " or the configuration file doesn't exist." " Treat it as default", __FUNCTION__, intface); } tmp = (struct rainfo *)malloc(sizeof(*ralist)); memset(tmp, 0, sizeof(*tmp)); tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; /* get interface information */ if (agetflag("nolladdr")) tmp->advlinkopt = 0; else tmp->advlinkopt = 1; if (tmp->advlinkopt) { if ((tmp->sdl = if_nametosdl(intface)) == NULL) { syslog(LOG_ERR, "<%s> can't get information of %s", __FUNCTION__, intface); exit(1); } tmp->ifindex = tmp->sdl->sdl_index; } else tmp->ifindex = if_nametoindex(intface); strncpy(tmp->ifname, intface, sizeof(tmp->ifname)); if ((tmp->phymtu = if_getmtu(intface)) == 0) { tmp->phymtu = IPV6_MMTU; syslog(LOG_WARNING, "<%s> can't get interface mtu of %s. Treat as %d", __FUNCTION__, intface, IPV6_MMTU); } /* * set router configuration variables. */ MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { syslog(LOG_ERR, "<%s> maxinterval must be between %e and %u", __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL); exit(1); } tmp->maxinterval = (u_int)val; MAYHAVE(val, "mininterval", tmp->maxinterval/3); if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { syslog(LOG_ERR, "<%s> mininterval must be between %e and %d", __FUNCTION__, MIN_MININTERVAL, (tmp->maxinterval * 3) / 4); exit(1); } tmp->mininterval = (u_int)val; MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); tmp->hoplimit = val & 0xff; MAYHAVE(val, "raflags", 0); tmp->managedflg= val & ND_RA_FLAG_MANAGED; tmp->otherflg = val & ND_RA_FLAG_OTHER; #ifdef MIP6 if (mobileip6) tmp->haflg = val & ND_RA_FLAG_HA; #endif MAYHAVE(val, "rltime", tmp->maxinterval * 3); if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { syslog(LOG_ERR, "<%s> router lifetime on %s must be 0 or" " between %d and %d", __FUNCTION__, intface, tmp->maxinterval, MAXROUTERLIFETIME); exit(1); } tmp->lifetime = val & 0xffff; MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); if (val > MAXREACHABLETIME) { syslog(LOG_ERR, "<%s> reachable time must be no greater than %d", __FUNCTION__, MAXREACHABLETIME); exit(1); } tmp->reachabletime = (u_int32_t)val; MAYHAVE(val, "retrans", DEF_ADVRETRANSTIMER); if (val < 0 || val > 0xffffffff) { syslog(LOG_ERR, "<%s> retrans time out of range", __FUNCTION__); exit(1); } tmp->retranstimer = (u_int32_t)val; #ifdef MIP6 if (!mobileip6) #else if (1) #endif { if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { syslog(LOG_ERR, "<%s> mobile-ip6 configuration without " "proper command line option", __FUNCTION__); exit(1); } } #ifdef MIP6 else { tmp->hapref = 0; if ((val = agetnum("hapref")) >= 0) tmp->hapref = (int16_t)val; if (tmp->hapref != 0) { tmp->hatime = 0; MUSTHAVE(val, "hatime"); tmp->hatime = (u_int16_t)val; if (tmp->hatime <= 0) { syslog(LOG_ERR, "<%s> home agent lifetime must be greater than 0", __FUNCTION__); exit(1); } } } #endif /* prefix information */ if ((pfxs = agetnum("addrs")) < 0) { /* auto configure prefix information */ if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { syslog(LOG_ERR, "<%s> conflicting prefix configuration for %s: " "automatic and manual config at the same time", __FUNCTION__, intface); exit(1); } get_prefix(tmp); } else { tmp->pfxs = pfxs; for (i = 0; i < pfxs; i++) { struct prefix *pfx; char entbuf[256]; int added = (pfxs > 1) ? 1 : 0; /* allocate memory to store prefix information */ if ((pfx = malloc(sizeof(struct prefix))) == NULL) { syslog(LOG_ERR, "<%s> can't allocate enough memory", __FUNCTION__); exit(1); } /* link into chain */ insque(pfx, &tmp->prefix); pfx->origin = PREFIX_FROM_CONFIG; makeentry(entbuf, i, "prefixlen", added); MAYHAVE(val, entbuf, 64); if (val < 0 || val > 128) { syslog(LOG_ERR, "<%s> prefixlen out of range", __FUNCTION__); exit(1); } pfx->prefixlen = (int)val; makeentry(entbuf, i, "pinfoflags", added); #ifdef MIP6 if (mobileip6) { MAYHAVE(val, entbuf, (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| ND_OPT_PI_FLAG_RTADDR)); } else #endif { MAYHAVE(val, entbuf, (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); } pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; #ifdef MIP6 if (mobileip6) pfx->routeraddr = val & ND_OPT_PI_FLAG_RTADDR; #endif makeentry(entbuf, i, "vltime", added); MAYHAVE(val, entbuf, DEF_ADVVALIDLIFETIME); if (val < 0 || val > 0xffffffff) { syslog(LOG_ERR, "<%s> vltime out of range", __FUNCTION__); exit(1); } pfx->validlifetime = (u_int32_t)val; makeentry(entbuf, i, "pltime", added); MAYHAVE(val, entbuf, DEF_ADVPREFERREDLIFETIME); if (val < 0 || val > 0xffffffff) { syslog(LOG_ERR, "<%s> pltime out of range", __FUNCTION__); exit(1); } pfx->preflifetime = (u_int32_t)val; makeentry(entbuf, i, "addr", added); addr = (char *)agetstr(entbuf, &bp); if (addr == NULL) { syslog(LOG_ERR, "<%s> need %s as an prefix for " "interface %s", __FUNCTION__, entbuf, intface); exit(1); } if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) { syslog(LOG_ERR, "<%s> inet_pton failed for %s", __FUNCTION__, addr); exit(1); } if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { syslog(LOG_ERR, "<%s> multicast prefix(%s) must " "not be advertised (IF=%s)", __FUNCTION__, addr, intface); exit(1); } if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) syslog(LOG_NOTICE, "<%s> link-local prefix(%s) will be" " advertised on %s", __FUNCTION__, addr, intface); } } MAYHAVE(val, "mtu", 0); if (val < 0 || val > 0xffffffff) { syslog(LOG_ERR, "<%s> mtu out of range", __FUNCTION__); exit(1); } tmp->linkmtu = (u_int32_t)val; if (tmp->linkmtu == 0) { char *mtustr; if ((mtustr = (char *)agetstr("mtu", &bp)) && strcmp(mtustr, "auto") == 0) tmp->linkmtu = tmp->phymtu; } else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { syslog(LOG_ERR, "<%s> advertised link mtu must be between" " least MTU and physical link MTU", __FUNCTION__); exit(1); } /* okey */ tmp->next = ralist; ralist = tmp; /* construct the sending packet */ make_packet(tmp); /* set timer */ tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, tmp, tmp); ra_timer_update((void *)tmp, &tmp->timer->tm); rtadvd_set_timer(&tmp->timer->tm, tmp->timer); } static void get_prefix(struct rainfo *rai) { size_t len; u_char *buf, *lim, *next; u_char ntopbuf[INET6_ADDRSTRLEN]; if ((len = rtbuf_len()) < 0) { syslog(LOG_ERR, "<%s> can't get buffer length for routing info", __FUNCTION__); exit(1); } if ((buf = malloc(len)) == NULL) { syslog(LOG_ERR, "<%s> can't allocate buffer", __FUNCTION__); exit(1); } if (get_rtinfo(buf, &len) < 0) { syslog(LOG_ERR, "<%s> can't get routing inforamtion", __FUNCTION__); exit(1); } lim = buf + len; next = get_next_msg(buf, lim, rai->ifindex, &len, RTADV_TYPE2BITMASK(RTM_GET)); while (next < lim) { struct prefix *pp; struct in6_addr *a; /* allocate memory to store prefix info. */ if ((pp = malloc(sizeof(*pp))) == NULL) { syslog(LOG_ERR, "<%s> can't get allocate buffer for prefix", __FUNCTION__); exit(1); } memset(pp, 0, sizeof(*pp)); /* set prefix and its length */ a = get_addr(next); memcpy(&pp->prefix, a, sizeof(*a)); if ((pp->prefixlen = get_prefixlen(next)) < 0) { syslog(LOG_ERR, "<%s> failed to get prefixlen " "or prefixl is invalid", __FUNCTION__); exit(1); } syslog(LOG_DEBUG, "<%s> add %s/%d to prefix list on %s", __FUNCTION__, inet_ntop(AF_INET6, a, ntopbuf, INET6_ADDRSTRLEN), pp->prefixlen, rai->ifname); /* set other fields with protocol defaults */ pp->validlifetime = DEF_ADVVALIDLIFETIME; pp->preflifetime = DEF_ADVPREFERREDLIFETIME; pp->onlinkflg = 1; pp->autoconfflg = 1; pp->origin = PREFIX_FROM_KERNEL; /* link into chain */ insque(pp, &rai->prefix); /* counter increment */ rai->pfxs++; /* forward pointer and get next prefix(if any) */ next += len; next = get_next_msg(next, lim, rai->ifindex, &len, RTADV_TYPE2BITMASK(RTM_GET)); } free(buf); } static void makeentry(buf, id, string, add) char *buf, *string; int id, add; { strcpy(buf, string); if (add) { char *cp; cp = (char *)index(buf, '\0'); cp += sprintf(cp, "%d", id); *cp = '\0'; } } /* * Add a prefix to the list of specified interface and reconstruct * the outgoing packet. * The prefix must not be in the list. * XXX: other parameter of the prefix(e.g. lifetime) shoule be * able to be specified. */ static void add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) { struct prefix *prefix; u_char ntopbuf[INET6_ADDRSTRLEN]; if ((prefix = malloc(sizeof(*prefix))) == NULL) { syslog(LOG_ERR, "<%s> memory allocation failed", __FUNCTION__); return; /* XXX: error or exit? */ } prefix->prefix = ipr->ipr_prefix.sin6_addr; prefix->prefixlen = ipr->ipr_plen; prefix->validlifetime = ipr->ipr_vltime; prefix->preflifetime = ipr->ipr_pltime; prefix->onlinkflg = ipr->ipr_raf_onlink; prefix->autoconfflg = ipr->ipr_raf_auto; prefix->origin = PREFIX_FROM_DYNAMIC; insque(prefix, &rai->prefix); syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), ipr->ipr_plen, rai->ifname); /* free the previous packet */ free(rai->ra_data); rai->ra_data = 0; /* reconstruct the packet */ rai->pfxs++; make_packet(rai); /* * reset the timer so that the new prefix will be advertised quickly. */ rai->initcounter = 0; ra_timer_update((void *)rai, &rai->timer->tm); rtadvd_set_timer(&rai->timer->tm, rai->timer); } /* * Delete a prefix to the list of specified interface and reconstruct * the outgoing packet. * The prefix must be in the list. */ void delete_prefix(struct rainfo *rai, struct prefix *prefix) { u_char ntopbuf[INET6_ADDRSTRLEN]; remque(prefix); syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); free(prefix); rai->pfxs--; make_packet(rai); } /* * Try to get an in6_prefixreq contents for a prefix which matches * ipr->ipr_prefix and ipr->ipr_plen and belongs to * the interface whose name is ipr->ipr_name[]. */ static int init_prefix(struct in6_prefixreq *ipr) { int s; if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, strerror(errno)); exit(1); } if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__, strerror(errno)); ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; ipr->ipr_raf_onlink = 1; ipr->ipr_raf_auto = 1; /* omit other field initialization */ } else if (ipr->ipr_origin < PR_ORIG_RR) { u_char ntopbuf[INET6_ADDRSTRLEN]; syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" "lower than PR_ORIG_RR(router renumbering)." "This should not happen if I am router", __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, sizeof(ntopbuf)), ipr->ipr_origin); close(s); return 1; } close(s); return 0; } void make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) { struct in6_prefixreq ipr; memset(&ipr, 0, sizeof(ipr)); if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" "exist. This should not happen! %s", __FUNCTION__, ifindex, strerror(errno)); exit(1); } ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); ipr.ipr_prefix.sin6_family = AF_INET6; ipr.ipr_prefix.sin6_addr = *addr; ipr.ipr_plen = plen; if (init_prefix(&ipr)) return; /* init failed by some error */ add_prefix(rai, &ipr); } void make_packet(struct rainfo *rainfo) { size_t packlen, lladdroptlen = 0; char *buf; struct nd_router_advert *ra; struct nd_opt_prefix_info *ndopt_pi; struct nd_opt_mtu *ndopt_mtu; #ifdef MIP6 struct nd_opt_advint *ndopt_advint; struct nd_opt_hai *ndopt_hai; #endif struct prefix *pfx; /* calculate total length */ packlen = sizeof(struct nd_router_advert); if (rainfo->advlinkopt) { if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { syslog(LOG_INFO, "<%s> link-layer address option has" " null length on %s." " Treat as not included.", __FUNCTION__, rainfo->ifname); rainfo->advlinkopt = 0; } packlen += lladdroptlen; } if (rainfo->pfxs) packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; if (rainfo->linkmtu) packlen += sizeof(struct nd_opt_mtu); #ifdef MIP6 if (mobileip6 && rainfo->maxinterval) packlen += sizeof(struct nd_opt_advint); if (mobileip6 && rainfo->hatime) packlen += sizeof(struct nd_opt_hai); #endif /* allocate memory for the packet */ if ((buf = malloc(packlen)) == NULL) { syslog(LOG_ERR, "<%s> can't get enough memory for an RA packet", __FUNCTION__); exit(1); } rainfo->ra_data = buf; /* XXX: what if packlen > 576? */ rainfo->ra_datalen = packlen; /* * construct the packet */ ra = (struct nd_router_advert *)buf; ra->nd_ra_type = ND_ROUTER_ADVERT; ra->nd_ra_code = 0; ra->nd_ra_cksum = 0; ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); ra->nd_ra_flags_reserved = 0; ra->nd_ra_flags_reserved |= rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; ra->nd_ra_flags_reserved |= rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; #ifdef MIP6 ra->nd_ra_flags_reserved |= rainfo->haflg ? ND_RA_FLAG_HA : 0; #endif ra->nd_ra_router_lifetime = htons(rainfo->lifetime); ra->nd_ra_reachable = htonl(rainfo->reachabletime); ra->nd_ra_retransmit = htonl(rainfo->retranstimer); buf += sizeof(*ra); if (rainfo->advlinkopt) { lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); buf += lladdroptlen; } if (rainfo->linkmtu) { ndopt_mtu = (struct nd_opt_mtu *)buf; ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; ndopt_mtu->nd_opt_mtu_len = 1; ndopt_mtu->nd_opt_mtu_reserved = 0; ndopt_mtu->nd_opt_mtu_mtu = ntohl(rainfo->linkmtu); buf += sizeof(struct nd_opt_mtu); } #ifdef MIP6 if (mobileip6 && rainfo->maxinterval) { ndopt_advint = (struct nd_opt_advint *)buf; ndopt_advint->nd_opt_int_type = ND_OPT_ADV_INTERVAL; ndopt_advint->nd_opt_int_len = 1; ndopt_advint->nd_opt_int_reserved = 0; ndopt_advint->nd_opt_int_interval = ntohl(rainfo->maxinterval * 1000); buf += sizeof(struct nd_opt_advint); } #endif #ifdef MIP6 if (rainfo->hatime) { ndopt_hai = (struct nd_opt_hai *)buf; ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION; ndopt_hai->nd_opt_hai_len = 1; ndopt_hai->nd_opt_hai_reserved = 0; ndopt_hai->nd_opt_hai_pref = ntohs(rainfo->hapref); ndopt_hai->nd_opt_hai_lifetime = ntohs(rainfo->hatime); buf += sizeof(struct nd_opt_hai); } #endif for (pfx = rainfo->prefix.next; pfx != &rainfo->prefix; pfx = pfx->next) { ndopt_pi = (struct nd_opt_prefix_info *)buf; ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; ndopt_pi->nd_opt_pi_len = 4; ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; ndopt_pi->nd_opt_pi_flags_reserved = 0; if (pfx->onlinkflg) ndopt_pi->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; if (pfx->autoconfflg) ndopt_pi->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; #ifdef MIP6 if (pfx->routeraddr) ndopt_pi->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RTADDR; #endif ndopt_pi->nd_opt_pi_valid_time = ntohl(pfx->validlifetime); ndopt_pi->nd_opt_pi_preferred_time = ntohl(pfx->preflifetime); ndopt_pi->nd_opt_pi_reserved2 = 0; ndopt_pi->nd_opt_pi_prefix = pfx->prefix; buf += sizeof(struct nd_opt_prefix_info); } return; } Index: head/usr.sbin/rtadvd/config.h =================================================================== --- head/usr.sbin/rtadvd/config.h (revision 71332) +++ head/usr.sbin/rtadvd/config.h (revision 71333) @@ -1,37 +1,36 @@ +/* $FreeBSD$ */ /* $KAME$ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 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. - * - * $FreeBSD$ */ extern void getconfig __P((char *)); extern void delete_prefix __P((struct rainfo *, struct prefix *)); extern void make_prefix __P((struct rainfo *, int, struct in6_addr *, int)); extern void make_packet __P((struct rainfo *)); Index: head/usr.sbin/rtadvd/dump.c =================================================================== --- head/usr.sbin/rtadvd/dump.c (revision 71332) +++ head/usr.sbin/rtadvd/dump.c (revision 71333) @@ -1,215 +1,214 @@ +/* $FreeBSD$ */ /* $KAME: dump.c,v 1.10 2000/05/23 11:31:25 itojun 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. - * - * $FreeBSD$ */ #include #include #include #if defined(__FreeBSD__) && __FreeBSD__ >= 3 #include #endif /* __FreeBSD__ >= 3 */ #include #include /* XXX: the following two are non-standard include files */ #include #include #include #include #include #include #include #include #include #include "rtadvd.h" #include "timer.h" #include "if.h" #include "dump.h" static FILE *fp; extern struct rainfo *ralist; static char *ether_str __P((struct sockaddr_dl *)); static void if_dump __P((void)); #ifdef __FreeBSD__ /* XXX: see PORTABILITY */ #define LONGLONG "%qu" #else #define LONGLONG "%llu" #endif static char * ether_str(sdl) struct sockaddr_dl *sdl; { static char ebuf[32]; u_char *cp; if (sdl->sdl_alen && sdl->sdl_alen > 5) { cp = (u_char *)LLADDR(sdl); sprintf(ebuf, "%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); } else { sprintf(ebuf, "NONE"); } return(ebuf); } static void if_dump() { struct rainfo *rai; struct prefix *pfx; char prefixbuf[INET6_ADDRSTRLEN]; int first; for (rai = ralist; rai; rai = rai->next) { fprintf(fp, "%s:\n", rai->ifname); fprintf(fp, " Status: %s\n", (iflist[rai->ifindex]->ifm_flags & IFF_UP) ? "UP" : "DOWN"); /* control information */ if (rai->lastsent.tv_sec) { /* note that ctime() appends CR by itself */ fprintf(fp, " Last RA sent: %s", ctime((time_t *)&rai->lastsent.tv_sec)); } if (rai->timer) { fprintf(fp, " Next RA will be sent: %s", ctime((time_t *)&rai->timer->tm.tv_sec)); } else fprintf(fp, " RA timer is stopped"); fprintf(fp, " waits: %d, initcount: %d\n", rai->waiting, rai->initcounter); /* statistics */ fprintf(fp, " statistics: RA(out/in/inconsistent): " LONGLONG "/" LONGLONG "/" LONGLONG ", ", (unsigned long long)rai->raoutput, (unsigned long long)rai->rainput, (unsigned long long)rai->rainconsistent); fprintf(fp, "RS(input): " LONGLONG "\n", (unsigned long long)rai->rsinput); /* interface information */ if (rai->advlinkopt) fprintf(fp, " Link-layer address: %s\n", ether_str(rai->sdl)); fprintf(fp, " MTU: %d\n", rai->phymtu); /* Router configuration variables */ fprintf(fp, " DefaultLifetime: %d, MaxAdvInterval: %d, " "MinAdvInterval: %d\n", rai->lifetime, rai->maxinterval, rai->mininterval); fprintf(fp, " Flags: %s%s%s MTU: %d\n", rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", #ifdef MIP6 rai->haflg ? "H" : #endif "", rai->linkmtu); fprintf(fp, " ReachableTime: %d, RetransTimer: %d, " "CurHopLimit: %d\n", rai->reachabletime, rai->retranstimer, rai->hoplimit); #ifdef MIP6 fprintf(fp, " HAPreference: %d, HALifetime: %d\n", rai->hapref, rai->hatime); #endif for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix; pfx = pfx->next) { if (first) { fprintf(fp, " Prefixes:\n"); first = 0; } fprintf(fp, " %s/%d(", inet_ntop(AF_INET6, &pfx->prefix, prefixbuf, sizeof(prefixbuf)), pfx->prefixlen); switch(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->validlifetime == ND6_INFINITE_LIFETIME) fprintf(fp, "vltime: infinity, "); else fprintf(fp, "vltime: %ld, ", (long)pfx->validlifetime); if (pfx->preflifetime == ND6_INFINITE_LIFETIME) fprintf(fp, "pltime: infinity, "); else fprintf(fp, "pltime: %ld, ", (long)pfx->preflifetime); fprintf(fp, "flags: %s%s%s", pfx->onlinkflg ? "L" : "", pfx->autoconfflg ? "A" : "", #ifdef MIP6 pfx->routeraddr ? "R" : #endif ""); fprintf(fp, ")\n"); } } } void rtadvd_dump_file(dumpfile) char *dumpfile; { if ((fp = fopen(dumpfile, "w")) == NULL) { syslog(LOG_WARNING, "<%s> open a dump file(%s)", __FUNCTION__, dumpfile); return; } if_dump(); fclose(fp); } Index: head/usr.sbin/rtadvd/dump.h =================================================================== --- head/usr.sbin/rtadvd/dump.h (revision 71332) +++ head/usr.sbin/rtadvd/dump.h (revision 71333) @@ -1,34 +1,33 @@ +/* $FreeBSD$ */ /* $KAME$ */ /* * 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. - * - * $FreeBSD$ */ extern void rtadvd_dump_file __P((char *)); Index: head/usr.sbin/rtadvd/if.c =================================================================== --- head/usr.sbin/rtadvd/if.c (revision 71332) +++ head/usr.sbin/rtadvd/if.c (revision 71333) @@ -1,601 +1,600 @@ +/* $FreeBSD$ */ /* $KAME: if.c,v 1.14 2000/10/25 04:28:34 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 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. - * - * $FreeBSD$ */ #include #include #include #include #include #include #ifdef __FreeBSD__ # include #endif #include #ifdef __NetBSD__ #include #endif #include #include #include #include #ifdef __bsdi__ # include #endif #ifdef __OpenBSD__ #include #endif #include #include #include #include #include #include "rtadvd.h" #include "if.h" #define ROUNDUP(a, size) \ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) #define NEXT_SA(ap) (ap) = (struct sockaddr *) \ ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ sizeof(u_long)) :\ sizeof(u_long))) struct if_msghdr **iflist; int iflist_init_ok; size_t ifblock_size; char *ifblock; static void get_iflist __P((char **buf, size_t *size)); static void parse_iflist __P((struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)); static void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) { int i; for (i = 0; i < RTAX_MAX; i++) { if (addrs & (1 << i)) { rti_info[i] = sa; NEXT_SA(sa); } else rti_info[i] = NULL; } } 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_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) return(NULL); memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); 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", __FUNCTION__, 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", __FUNCTION__, 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) { switch(sdl->sdl_type) { case IFT_ETHER: return(ROUNDUP8(ETHER_ADDR_LEN + 2)); default: return(0); } } void lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) { char *addr; ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ switch(sdl->sdl_type) { case IFT_ETHER: ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; addr = (char *)(ndopt + 1); memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); break; default: syslog(LOG_ERR, "<%s> unsupported link type(%d)", __FUNCTION__, sdl->sdl_type); exit(1); } return; } int rtbuf_len() { size_t len; int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) return(-1); return(len); } int get_rtinfo(char *buf, size_t *len) { int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; if (sysctl(mib, 6, buf, len, NULL, 0) < 0) return(-1); return(0); } #define FILTER_MATCH(type, filter) ((0x1 << type) & filter) #define SIN6(s) ((struct sockaddr_in6 *)(s)) #define SDL(s) ((struct sockaddr_dl *)(s)) char * get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) { struct rt_msghdr *rtm; struct ifa_msghdr *ifam; struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; *lenp = 0; for (rtm = (struct rt_msghdr *)buf; rtm < (struct rt_msghdr *)lim; rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { /* just for safety */ if (!rtm->rtm_msglen) { syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " "(buf=%p lim=%p rtm=%p)", __FUNCTION__, buf, lim, rtm); break; } if (FILTER_MATCH(rtm->rtm_type, filter) == 0) { continue; } switch (rtm->rtm_type) { case RTM_GET: case RTM_ADD: case RTM_DELETE: /* address related checks */ sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((dst = rti_info[RTAX_DST]) == NULL || dst->sa_family != AF_INET6) continue; if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) continue; if ((gw = rti_info[RTAX_GATEWAY]) == NULL || gw->sa_family != AF_LINK) continue; if (ifindex && SDL(gw)->sdl_index != ifindex) continue; if (rti_info[RTAX_NETMASK] == NULL) continue; /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_NEWADDR: case RTM_DELADDR: ifam = (struct ifa_msghdr *)rtm; /* address related checks */ sa = (struct sockaddr *)(ifam + 1); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); if ((ifa = rti_info[RTAX_IFA]) == NULL || (ifa->sa_family != AF_INET && ifa->sa_family != AF_INET6)) continue; if (ifa->sa_family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) continue; if (ifindex && ifam->ifam_index != ifindex) continue; /* found */ *lenp = ifam->ifam_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_IFINFO: /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ } } return (char *)rtm; } #undef FILTER_MATCH(type, filter) struct in6_addr * get_addr(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; struct sockaddr *sa, *rti_info[RTAX_MAX]; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); return(&SIN6(rti_info[RTAX_DST])->sin6_addr); } int get_rtm_ifindex(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; struct sockaddr *sa, *rti_info[RTAX_MAX]; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); } 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; struct sockaddr *sa, *rti_info[RTAX_MAX]; u_char *p, *lim; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); sa = rti_info[RTAX_NETMASK]; p = (u_char *)(&SIN6(sa)->sin6_addr); lim = (u_char *)sa + sa->sa_len; return prefixlen(p, lim); } int prefixlen(u_char *p, u_char *lim) { int masklen; for (masklen = 0; p < lim; p++) { switch (*p) { case 0xff: masklen += 8; break; case 0xfe: masklen += 7; break; case 0xfc: masklen += 6; break; case 0xf8: masklen += 5; break; case 0xf0: masklen += 4; break; case 0xe0: masklen += 3; break; case 0xc0: masklen += 2; break; case 0x80: masklen += 1; break; case 0x00: break; default: return(-1); } } return(masklen); } int rtmsg_type(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; return(rtm->rtm_type); } int rtmsg_len(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)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", __FUNCTION__); exit(1); } if ((*buf = malloc(*size)) == NULL) { syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__); exit(1); } if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) { syslog(LOG_ERR, "<%s> sysctl: iflist get failed", __FUNCTION__); 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(size_t); if ((*ifmlist_p = (struct if_msghdr **)malloc(malloc_size)) == NULL) { syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__); 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)", __FUNCTION__, 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)", __FUNCTION__, 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); } Index: head/usr.sbin/rtadvd/if.h =================================================================== --- head/usr.sbin/rtadvd/if.h (revision 71332) +++ head/usr.sbin/rtadvd/if.h (revision 71333) @@ -1,60 +1,59 @@ +/* $FreeBSD$ */ /* $KAME: if.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 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. - * - * $FreeBSD$ */ #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 __P((char *name)); int if_getmtu __P((char *name)); int if_getflags __P((int ifindex, int oifflags)); int lladdropt_length __P((struct sockaddr_dl *sdl)); void lladdropt_fill __P((struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)); int rtbuf_len __P((void)); int get_rtinfo __P((char *buf, size_t *len)); char *get_next_msg __P((char *buf, char *lim, int ifindex, size_t *lenp, int filter)); struct in6_addr *get_addr __P((char *buf)); int get_rtm_ifindex __P((char *buf)); int get_ifm_ifindex __P((char *buf)); int get_ifam_ifindex __P((char *buf)); int get_ifm_flags __P((char *buf)); int get_prefixlen __P((char *buf)); int rtmsg_type __P((char *buf)); int ifmsg_type __P((char *buf)); int rtmsg_len __P((char *buf)); int ifmsg_len __P((char *buf)); void init_iflist __P((void)); Index: head/usr.sbin/rtadvd/pathnames.h =================================================================== --- head/usr.sbin/rtadvd/pathnames.h (revision 71332) +++ head/usr.sbin/rtadvd/pathnames.h (revision 71333) @@ -1,4 +1,4 @@ +/* $FreeBSD$ */ /* $KAME$ */ -/* $FreeBSD$ */ #define _PATH_RTADVDCONF "/etc/rtadvd.conf" Index: head/usr.sbin/rtadvd/rrenum.c =================================================================== --- head/usr.sbin/rtadvd/rrenum.c (revision 71332) +++ head/usr.sbin/rtadvd/rrenum.c (revision 71333) @@ -1,419 +1,418 @@ +/* $FreeBSD$ */ /* $KAME: rrenum.c,v 1.3 2000/05/16 13:34:14 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 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. - * - * $FreeBSD$ */ #include #include #include #include #include #if defined(__FreeBSD__) && __FreeBSD__ >= 3 #include #endif /* __FreeBSD__ >= 3 */ #include #include #include #include #include #include #include #include #include #include "rrenum.h" #include "if.h" #define RR_ISSET_SEGNUM(segnum_bits, segnum) \ ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0) #define RR_SET_SEGNUM(segnum_bits, segnum) \ (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31))) struct rr_operation { u_long rro_seqnum; u_long rro_segnum_bits[8]; }; static struct rr_operation rro; static int rr_rcvifindex; static int rrcmd2pco[RPM_PCO_MAX] = { 0, SIOCAIFPREFIX_IN6, SIOCCIFPREFIX_IN6, SIOCSGIFPREFIX_IN6 }; static int s = -1; /* * Check validity of a Prefix Control Operation(PCO). * Return 0 on success, 1 on failure. */ static int rr_pco_check(int len, struct rr_pco_match *rpm) { struct rr_pco_use *rpu, *rpulim; int checklen; /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */ if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", __FUNCTION__, rpm->rpm_len); return 1; } /* rpm->rpm_code must be valid value */ switch(rpm->rpm_code) { case RPM_PCO_ADD: case RPM_PCO_CHANGE: case RPM_PCO_SETGLOBAL: break; default: syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __FUNCTION__, rpm->rpm_code); return 1; } /* rpm->rpm_matchlen must be 0 to 128 inclusive */ if (rpm->rpm_matchlen > 128) { syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", __FUNCTION__, rpm->rpm_matchlen); return 1; } /* * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be * between 0 and 128 inclusive */ for (rpu = (struct rr_pco_use *)(rpm + 1), rpulim = (struct rr_pco_use *)((char *)rpm + len); rpu < rpulim; rpu += 1) { checklen = rpu->rpu_uselen; checklen += rpu->rpu_keeplen; /* * omit these check, because either of rpu_uselen * and rpu_keeplen is unsigned char * (128 > rpu_uselen > 0) * (128 > rpu_keeplen > 0) * (rpu_uselen + rpu_keeplen > 0) */ if (checklen > 128) { syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" " rpu_keeplen %d is %d(over 128)", __FUNCTION__, rpu->rpu_uselen, rpu->rpu_keeplen, rpu->rpu_uselen + rpu->rpu_keeplen); return 1; } } return 0; } static void do_use_prefix(int len, struct rr_pco_match *rpm, struct in6_rrenumreq *irr) { struct rr_pco_use *rpu, *rpulim; rpu = (struct rr_pco_use *)(rpm + 1); rpulim = (struct rr_pco_use *)((char *)rpm + len); if (rpu == rpulim) { if (rpm->rpm_code == RPM_PCO_ADD) return; irr->irr_u_uselen = 0; irr->irr_u_keeplen = 0; irr->irr_raf_mask_onlink = 0; irr->irr_raf_mask_auto = 0; irr->irr_vltime = 0; irr->irr_pltime = 0; memset(&irr->irr_flags, 0, sizeof(irr->irr_flags)); irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */ irr->irr_useprefix.sin6_family = 0; irr->irr_useprefix.sin6_addr = in6addr_any; if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && errno != EADDRNOTAVAIL) syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, strerror(errno)); return; } for (rpu = (struct rr_pco_use *)(rpm + 1), rpulim = (struct rr_pco_use *)((char *)rpm + len); rpu < rpulim; rpu += 1) { /* init in6_rrenumreq fields */ 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); irr->irr_raf_mask_auto = (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); irr->irr_vltime = rpu->rpu_vltime; irr->irr_pltime = rpu->rpu_pltime; irr->irr_raf_onlink = (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); irr->irr_raf_auto = (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); irr->irr_rrf_decrvalid = (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME); irr->irr_rrf_decrprefd = (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME); irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); irr->irr_useprefix.sin6_family = AF_INET6; irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && errno != EADDRNOTAVAIL) syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, strerror(errno)); } } /* * process a Prefix Control Operation(PCO). * return 0 on success, 1 on failure */ static int do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) { int ifindex = 0; struct in6_rrenumreq irr; if ((rr_pco_check(len, rpm) != NULL)) return 1; if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, strerror(errno)); exit(1); } memset(&irr, 0, sizeof(irr)); irr.irr_origin = PR_ORIG_RR; irr.irr_m_len = rpm->rpm_matchlen; irr.irr_m_minlen = rpm->rpm_minlen; irr.irr_m_maxlen = rpm->rpm_maxlen; irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix); 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); } if (errno == ENXIO) return 0; else if (errno) { syslog(LOG_ERR, "<%s> if_indextoname: %s", __FUNCTION__, strerror(errno)); return 1; } return 0; } /* * call do_pco() for each Prefix Control Operations(PCOs) in a received * Router Renumbering Command packet. * return 0 on success, 1 on failure */ static int do_rr(int len, struct icmp6_router_renum *rr) { struct rr_pco_match *rpm; char *cp, *lim; lim = (char *)rr + len; 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) { int rpmlen; rpm = (struct rr_pco_match *)cp; if (len < sizeof(struct rr_pco_match)) { tooshort: syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " "gabage at end of pkt?", __FUNCTION__, len); return 1; } rpmlen = rpm->rpm_len << 3; if (len < rpmlen) goto tooshort; if (do_pco(rr, rpmlen, rpm)) { syslog(LOG_WARNING, "<%s> invalid PCO", __FUNCTION__); goto next; } next: cp += rpmlen; len -= rpmlen; } return 0; } /* * check validity of a router renumbering command packet * return 0 on success, 1 on failure */ static int rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, struct in6_addr *dst) { u_char ntopbuf[INET6_ADDRSTRLEN]; /* omit rr minimal length check. hope kernel have done it. */ /* rr_command length check */ if (len < (sizeof(struct icmp6_router_renum) + sizeof(struct rr_pco_match))) { syslog(LOG_ERR, "<%s> rr_command len %d is too short", __FUNCTION__, len); return 1; } /* destination check. only for multicast. omit unicast check. */ if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && !IN6_IS_ADDR_MC_SITELOCAL(dst)) { syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", __FUNCTION__, inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN)); return 1; } /* seqnum and segnum check */ if (rro.rro_seqnum > rr->rr_seqnum) { syslog(LOG_WARNING, "<%s> rcvd old seqnum %d from %s", __FUNCTION__, (u_int32_t)ntohl(rr->rr_seqnum), inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); return 1; } if (rro.rro_seqnum == rr->rr_seqnum && (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) syslog(LOG_WARNING, "<%s> rcvd duped segnum %d from %s", __FUNCTION__, rr->rr_segnum, inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); return 0; } /* update seqnum */ if (rro.rro_seqnum != rr->rr_seqnum) { /* then must be "<" */ /* init rro_segnum_bits */ memset(rro.rro_segnum_bits, 0, sizeof(rro.rro_segnum_bits)); } rro.rro_seqnum = rr->rr_seqnum; return 0; } static void rr_command_input(int len, struct icmp6_router_renum *rr, struct in6_addr *from, struct in6_addr *dst) { /* rr_command validity check */ if (rr_command_check(len, rr, from, dst)) goto failed; if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) == ICMP6_RR_FLAGS_TEST) return; /* do router renumbering */ if (do_rr(len, rr)) { goto failed; } /* update segnum */ RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); return; failed: syslog(LOG_ERR, "<%s> received RR was invalid", __FUNCTION__); return; } void rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, struct sockaddr_in6 *from, struct in6_addr *dst) { u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; syslog(LOG_DEBUG, "<%s> RR received from %s to %s on %s", __FUNCTION__, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0], INET6_ADDRSTRLEN), inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); rr_rcvifindex = pi->ipi6_ifindex; /* TODO: some consistency check. */ switch (rr->rr_code) { case ICMP6_ROUTER_RENUMBERING_COMMAND: rr_command_input(len, rr, &from->sin6_addr, dst); /* TODO: send reply msg */ break; case ICMP6_ROUTER_RENUMBERING_RESULT: /* RESULT will be processed by rrenumd */ break; case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: /* TODO: sequence number reset */ break; default: syslog(LOG_ERR, "<%s> received unknown code %d", __FUNCTION__, rr->rr_code); break; } return; } Index: head/usr.sbin/rtadvd/rrenum.h =================================================================== --- head/usr.sbin/rtadvd/rrenum.h (revision 71332) +++ head/usr.sbin/rtadvd/rrenum.h (revision 71333) @@ -1,36 +1,35 @@ +/* $FreeBSD$ */ /* $KAME$ */ /* * 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. - * - * $FreeBSD$ */ void rr_input __P((int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, struct sockaddr_in6 *from, struct in6_addr *dst)); Index: head/usr.sbin/rtadvd/rtadvd.8 =================================================================== --- head/usr.sbin/rtadvd/rtadvd.8 (revision 71332) +++ head/usr.sbin/rtadvd/rtadvd.8 (revision 71333) @@ -1,155 +1,154 @@ +.\" $FreeBSD$ .\" $KAME: rtadvd.8,v 1.9 2000/05/27 13:37:01 jinmei Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 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. -.\" -.\" $FreeBSD$ .\" .Dd May 17, 1998 .Dt RTADVD 8 .Os .Sh NAME .Nm rtadvd .Nd router advertisement daemon .Sh SYNOPSIS .Nm .Op Fl c Ar configfile .Op Fl dDfRs .Ar interface ... .Sh DESCRIPTION .Nm sends router advertisement packets to the specified .Ar interfaces . .Pp The program will daemonize itself on invocation. It will then send router advertisement packets periodically, as well as in response to router solicitation messages sent by end hosts. .Pp Router advertisements can be configured on a per-interface basis, as described in .Xr rtadvd.conf 5 . .Pp If there is no configuration file entry for an interface, or if the configuration file does not exist altogether, .Nm sets all the parameters to their default values. In particular, .Nm reads all the interface routes from the routing table and advertises them as on-link prefixes. .Pp .Nm also watches the routing table. By default, if an interface direct route is added/deleted on an advertising interface and no static prefixes are specified by the configuration file, .Nm adds/deletes the corresponding prefix to/from its advertising list, respectively. The .Fl s option may be used to disable this behavior. Moreover, if the status of an advertising interface changes, .Nm will start or stop sending router advertisements according to the latest status. .Pp The command line options are: .Bl -tag -width indent .\" .It Fl c Specify an alternate location, .Ar configfile , for the configuration file. By default, .Pa /etc/rtadvd.conf is used. .It Fl d Print debugging information. .It Fl D Even more debugging information is printed. .It Fl f Foreground mode (useful when debugging). .\".It Fl m .\"Enables mobile IPv6 support. .\"This changes the content of router advertisement option, as well as .\"permitted configuration directives. .It Fl R Accept router renumbering requests. If you enable it, certain IPsec setup is suggested for security reasons. .It Fl s 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 . .Pp Use .Dv SIGTERM to kill .Nm gracefully. In this case, .Nm will transmit router advertisement with router lifetime 0 to all the interfaces .Pq in accordance with RFC2461 6.2.5 . .Sh RETURN VALUES The .Nm program exits 0 on success, and >0 on failures. .Sh FILES .Bl -tag -width Pa -compact .It Pa /etc/rtadvd.conf The default configuration file. .It Pa /var/run/rtadvd.pid contains the pid of the currently running .Nm . .It Pa /var/run/rtadvd.dump in which .Nm dumps its internal state. .El .Sh SEE ALSO .Xr daemon 3 , .Xr rtadvd.conf 5 , .Xr rtsol 8 .Sh HISTORY The .Nm command first appeared in WIDE Hydrangea IPv6 protocol stack kit. .Sh CAVEAT Router advertisements should only be performed downstream. Erroneous upstream advertisements will cause .Xr icmp6 4 redirect packet storms in the subnet, as (per the specification) the advertising router is assumed to become the default router for end hosts in the subnet. Index: head/usr.sbin/rtadvd/rtadvd.c =================================================================== --- head/usr.sbin/rtadvd/rtadvd.c (revision 71332) +++ head/usr.sbin/rtadvd/rtadvd.c (revision 71333) @@ -1,1503 +1,1502 @@ +/* $FreeBSD$ */ /* $KAME: rtadvd.c,v 1.30 2000/06/22 20:16:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 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. - * - * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rtadvd.h" #include "rrenum.h" #include "advcap.h" #include "timer.h" #include "if.h" #include "config.h" #include "dump.h" struct msghdr rcvmhdr; static u_char *rcvcmsgbuf; static size_t rcvcmsgbuflen; static u_char *sndcmsgbuf = NULL; static size_t sndcmsgbuflen; static int do_dump; struct msghdr sndmhdr; struct iovec rcviov[2]; struct iovec sndiov[2]; struct sockaddr_in6 from; struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6}; static char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX: should be configurable */ static char *pidfilename = "/var/run/rtadvd.pid"; /* should be configurable */ int sock, rtsock; #ifdef MIP6 int mobileip6 = 0; #endif int accept_rr = 0; int dflag = 0, sflag = 0; u_char *conffile = NULL; struct rainfo *ralist = NULL; struct nd_optlist { struct nd_optlist *next; struct nd_opt_hdr *opt; }; union nd_opts { struct nd_opt_hdr *nd_opt_array[7]; struct { struct nd_opt_hdr *zero; struct nd_opt_hdr *src_lladdr; struct nd_opt_hdr *tgt_lladdr; struct nd_opt_prefix_info *pi; struct nd_opt_rd_hdr *rh; struct nd_opt_mtu *mtu; struct nd_optlist *list; } nd_opt_each; }; #define nd_opts_src_lladdr nd_opt_each.src_lladdr #define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr #define nd_opts_pi nd_opt_each.pi #define nd_opts_rh nd_opt_each.rh #define nd_opts_mtu nd_opt_each.mtu #define nd_opts_list nd_opt_each.list #define NDOPT_FLAG_SRCLINKADDR 0x1 #define NDOPT_FLAG_TGTLINKADDR 0x2 #define NDOPT_FLAG_PREFIXINFO 0x4 #define NDOPT_FLAG_RDHDR 0x8 #define NDOPT_FLAG_MTU 0x10 u_int32_t ndopt_flags[] = { 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR, NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU }; int main __P((int, char *[])); static void die __P((int)); static void sock_open __P((void)); static void rtsock_open __P((void)); static void rtadvd_input __P((void)); static void rs_input __P((int, struct nd_router_solicit *, struct in6_pktinfo *, struct sockaddr_in6 *)); static void ra_input __P((int, struct nd_router_advert *, struct in6_pktinfo *, struct sockaddr_in6 *)); static int prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *, struct sockaddr_in6 *)); static int nd6_options __P((struct nd_opt_hdr *, int, union nd_opts *, u_int32_t)); static void free_ndopts __P((union nd_opts *)); static struct rainfo *if_indextorainfo __P((int)); static void ra_output __P((struct rainfo *)); static void rtmsg_input __P((void)); static void rtadvd_set_dump_file __P((void)); struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int)); int main(argc, argv) int argc; char *argv[]; { fd_set fdset; int maxfd = 0; struct timeval *timeout; int i, ch; int fflag = 0; FILE *pidfp; pid_t pid; openlog("rtadvd", LOG_NDELAY|LOG_PID, LOG_DAEMON); /* get command line options and arguments */ #ifdef MIP6 #define OPTIONS "c:dDfmRs" #else #define OPTIONS "c:dDfRs" #endif while ((ch = getopt(argc, argv, OPTIONS)) != -1) { #undef OPTIONS switch(ch) { case 'c': conffile = optarg; break; case 'd': dflag = 1; break; case 'D': dflag = 2; break; case 'f': fflag = 1; break; #ifdef MIP6 case 'm': mobileip6 = 1; break; #endif case 'R': accept_rr = 1; break; case 's': sflag = 1; break; } } argc -= optind; argv += optind; if (argc == 0) { fprintf(stderr, #ifdef MIP6 "usage: rtadvd [-dDfmRs] [-c conffile] " #else "usage: rtadvd [-dDfRs] [-c conffile] " #endif "interfaces...\n"); exit(1); } /* set log level */ if (dflag == 0) (void)setlogmask(LOG_UPTO(LOG_ERR)); if (dflag == 1) (void)setlogmask(LOG_UPTO(LOG_INFO)); /* timer initialization */ rtadvd_timer_init(); /* random value initialization */ srandom((u_long)time(NULL)); /* get iflist block from kernel */ init_iflist(); while (argc--) getconfig(*argv++); if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) { fprintf(stderr, "fatal: inet_pton failed\n"); exit(1); } sock_open(); if (!fflag) daemon(1, 0); /* record the current PID */ pid = getpid(); if ((pidfp = fopen(pidfilename, "w")) == NULL) syslog(LOG_ERR, "<%s> failed to open a log file(%s), run anyway.", __FUNCTION__, pidfilename); else { fprintf(pidfp, "%d\n", pid); fclose(pidfp); } FD_ZERO(&fdset); FD_SET(sock, &fdset); maxfd = sock; rtsock_open(); FD_SET(rtsock, &fdset); if (rtsock > sock) maxfd = rtsock; signal(SIGTERM, (void *)die); signal(SIGUSR1, (void *)rtadvd_set_dump_file); while (1) { struct fd_set select_fd = fdset; /* reinitialize */ if (do_dump) { /* SIGUSR1 */ do_dump = 0; rtadvd_dump_file(dumpfilename); } /* timer expiration check and reset the timer */ timeout = rtadvd_check_timer(); if (timeout != NULL) { syslog(LOG_DEBUG, "<%s> set timer to %ld:%ld. waiting for " "inputs or timeout", __FUNCTION__, (long int)timeout->tv_sec, (long int)timeout->tv_usec); } else { syslog(LOG_DEBUG, "<%s> there's no timer. waiting for inputs", __FUNCTION__); } if ((i = select(maxfd + 1, &select_fd, NULL, NULL, timeout)) < 0) { /* EINTR would occur upon SIGUSR1 for status dump */ if (errno != EINTR) syslog(LOG_ERR, "<%s> select: %s", __FUNCTION__, strerror(errno)); continue; } if (i == 0) /* timeout */ continue; if (sflag == 0 && FD_ISSET(rtsock, &select_fd)) rtmsg_input(); if (FD_ISSET(sock, &select_fd)) rtadvd_input(); } exit(0); /* NOTREACHED */ } static void rtadvd_set_dump_file() { do_dump = 1; } static void die(sig) int sig; { struct rainfo *ra; int i; const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS; if (dflag > 1) { syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n", __FUNCTION__); } for (ra = ralist; ra; ra = ra->next) { ra->lifetime = 0; make_packet(ra); } for (i = 0; i < retrans; i++) { for (ra = ralist; ra; ra = ra->next) ra_output(ra); sleep(MIN_DELAY_BETWEEN_RAS); } exit(0); /*NOTREACHED*/ } static void rtmsg_input() { int n, type, ifindex = 0, plen; size_t len; char msg[2048], *next, *lim; u_char ifname[16]; struct prefix *prefix; struct rainfo *rai; struct in6_addr *addr; char addrbuf[INET6_ADDRSTRLEN]; n = read(rtsock, msg, 2048); if (dflag > 1) { syslog(LOG_DEBUG, "<%s> received a routing message " "(type = %d, len = %d)", __FUNCTION__, rtmsg_type(msg), n); } if (n > rtmsg_len(msg)) { /* * This usually won't happen for messages received on * a routing socket. */ if (dflag > 1) syslog(LOG_DEBUG, "<%s> received data length is larger than" "1st routing message len. multiple messages?" " read %d bytes, but 1st msg len = %d", __FUNCTION__, n, rtmsg_len(msg)); #if 0 /* adjust length */ n = rtmsg_len(msg); #endif } lim = msg + n; for (next = msg; next < lim; next += len) { int oldifflags; next = get_next_msg(next, lim, 0, &len, RTADV_TYPE2BITMASK(RTM_ADD) | RTADV_TYPE2BITMASK(RTM_DELETE) | RTADV_TYPE2BITMASK(RTM_NEWADDR) | RTADV_TYPE2BITMASK(RTM_DELADDR) | RTADV_TYPE2BITMASK(RTM_IFINFO)); if (len == 0) break; type = rtmsg_type(next); switch (type) { case RTM_ADD: case RTM_DELETE: ifindex = get_rtm_ifindex(next); break; case RTM_NEWADDR: case RTM_DELADDR: ifindex = get_ifam_ifindex(next); break; case RTM_IFINFO: ifindex = get_ifm_ifindex(next); break; default: /* should not reach here */ if (dflag > 1) { syslog(LOG_DEBUG, "<%s:%d> unknown rtmsg %d on %s", __FUNCTION__, __LINE__, type, if_indextoname(ifindex, ifname)); } continue; } if ((rai = if_indextorainfo(ifindex)) == NULL) { if (dflag > 1) { syslog(LOG_DEBUG, "<%s> route changed on " "non advertising interface(%s)", __FUNCTION__, if_indextoname(ifindex, ifname)); } continue; } oldifflags = iflist[ifindex]->ifm_flags; 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 */ if (plen < 4 /* as RFC2373, prefixlen is at least 4 */ || plen > 127) { syslog(LOG_INFO, "<%s> new interface route's" "plen %d is invalid for a prefix", __FUNCTION__, plen); break; } prefix = find_prefix(rai, addr, plen); if (prefix) { if (dflag > 1) { syslog(LOG_DEBUG, "<%s> new prefix(%s/%d) " "added on %s, " "but it was already in list", __FUNCTION__, inet_ntop(AF_INET6, addr, (char *)addrbuf, INET6_ADDRSTRLEN), plen, rai->ifname); } break; } make_prefix(rai, ifindex, addr, plen); 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; addr = get_addr(msg); plen = get_prefixlen(msg); /* sanity check for plen */ if (plen < 4 /* as RFC2373, prefixlen is at least 4 */ || plen > 127) { syslog(LOG_INFO, "<%s> deleted interface" "route's" "plen %d is invalid for a prefix", __FUNCTION__, plen); break; } prefix = find_prefix(rai, addr, plen); if (prefix == NULL) { if (dflag > 1) { syslog(LOG_DEBUG, "<%s> prefix(%s/%d) was " "deleted on %s, " "but it was not in list", __FUNCTION__, inet_ntop(AF_INET6, addr, (char *)addrbuf, INET6_ADDRSTRLEN), plen, rai->ifname); } break; } delete_prefix(rai, prefix); 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 */ if (dflag > 1) { syslog(LOG_DEBUG, "<%s:%d> unknown rtmsg %d on %s", __FUNCTION__, __LINE__, type, if_indextoname(ifindex, ifname)); } return; } /* check if an interface flag is changed */ if ((oldifflags & IFF_UP) != 0 && /* UP to DOWN */ (iflist[ifindex]->ifm_flags & IFF_UP) == 0) { syslog(LOG_INFO, "<%s> interface %s becomes down. stop timer.", __FUNCTION__, rai->ifname); rtadvd_remove_timer(&rai->timer); } else if ((oldifflags & IFF_UP) == 0 && /* DOWN to UP */ (iflist[ifindex]->ifm_flags & IFF_UP) != 0) { syslog(LOG_INFO, "<%s> interface %s becomes up. restart timer.", __FUNCTION__, rai->ifname); rai->initcounter = 0; /* reset the counter */ rai->waiting = 0; /* XXX */ 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); } } return; } void rtadvd_input() { int i; int *hlimp = NULL; #ifdef OLDRAWSOCKET struct ip6_hdr *ip; #endif struct icmp6_hdr *icp; int ifindex = 0; struct cmsghdr *cm; struct in6_pktinfo *pi = NULL; u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; struct in6_addr dst = in6addr_any; /* * 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) return; /* extract optional information via Advanced API */ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO && cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); ifindex = pi->ipi6_ifindex; dst = pi->ipi6_addr; } if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT && cm->cmsg_len == CMSG_LEN(sizeof(int))) hlimp = (int *)CMSG_DATA(cm); } if (ifindex == 0) { syslog(LOG_ERR, "<%s> failed to get receiving interface", __FUNCTION__); return; } if (hlimp == NULL) { syslog(LOG_ERR, "<%s> failed to get receiving hop limit", __FUNCTION__); 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) { syslog(LOG_INFO, "<%s> received data on a disabled interface (%s)", __FUNCTION__, if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } #ifdef OLDRAWSOCKET if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) { syslog(LOG_ERR, "<%s> packet size(%d) is too short", __FUNCTION__, i); return; } ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base; icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */ #else if (i < sizeof(struct icmp6_hdr)) { syslog(LOG_ERR, "<%s> packet size(%d) is too short", __FUNCTION__, i); return; } icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; #endif switch(icp->icmp6_type) { case ND_ROUTER_SOLICIT: /* * Message verification - RFC-2461 6.1.1 * XXX: these checks must be done in the kernel as well, * but we can't completely rely on them. */ if (*hlimp != 255) { syslog(LOG_NOTICE, "<%s> RS with invalid hop limit(%d) " "received from %s on %s", __FUNCTION__, *hlimp, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } if (icp->icmp6_code) { syslog(LOG_NOTICE, "<%s> RS with invalid ICMP6 code(%d) " "received from %s on %s", __FUNCTION__, icp->icmp6_code, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } if (i < sizeof(struct nd_router_solicit)) { syslog(LOG_NOTICE, "<%s> RS from %s on %s does not have enough " "length (len = %d)", __FUNCTION__, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); return; } rs_input(i, (struct nd_router_solicit *)icp, pi, &from); break; case ND_ROUTER_ADVERT: /* * Message verification - RFC-2461 6.1.2 * XXX: there's a same dilemma as above... */ if (*hlimp != 255) { syslog(LOG_NOTICE, "<%s> RA with invalid hop limit(%d) " "received from %s on %s", __FUNCTION__, *hlimp, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } if (icp->icmp6_code) { syslog(LOG_NOTICE, "<%s> RA with invalid ICMP6 code(%d) " "received from %s on %s", __FUNCTION__, icp->icmp6_code, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } if (i < sizeof(struct nd_router_advert)) { syslog(LOG_NOTICE, "<%s> RA from %s on %s does not have enough " "length (len = %d)", __FUNCTION__, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); return; } ra_input(i, (struct nd_router_advert *)icp, pi, &from); break; case ICMP6_ROUTER_RENUMBERING: if (accept_rr == 0) { syslog(LOG_ERR, "<%s> received a router renumbering " "message, but not allowed to be accepted", __FUNCTION__); break; } rr_input(i, (struct icmp6_router_renum *)icp, pi, &from, &dst); break; default: /* * Note that this case is POSSIBLE, especially just * after invocation of the daemon. This is because we * could receive message after opening the socket and * before setting ICMP6 type filter(see sock_open()). */ syslog(LOG_ERR, "<%s> invalid icmp type(%d)", __FUNCTION__, icp->icmp6_type); return; } return; } static void rs_input(int len, struct nd_router_solicit *rs, struct in6_pktinfo *pi, struct sockaddr_in6 *from) { u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; union nd_opts ndopts; struct rainfo *ra; syslog(LOG_DEBUG, "<%s> RS received from %s on %s", __FUNCTION__, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); if (nd6_options((struct nd_opt_hdr *)(rs + 1), len - sizeof(struct nd_router_solicit), &ndopts, NDOPT_FLAG_SRCLINKADDR)) { syslog(LOG_DEBUG, "<%s> ND option check failed for an RS from %s on %s", __FUNCTION__, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } /* * If the IP source address is the unspecified address, there * must be no source link-layer address option in the message. * (RFC-2461 6.1.1) */ if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) && ndopts.nd_opts_src_lladdr) { syslog(LOG_ERR, "<%s> RS from unspecified src on %s has a link-layer" " address option", __FUNCTION__, if_indextoname(pi->ipi6_ifindex, ifnamebuf)); goto done; } ra = ralist; while (ra != NULL) { if (pi->ipi6_ifindex == ra->ifindex) break; ra = ra->next; } if (ra == NULL) { syslog(LOG_INFO, "<%s> RS received on non advertising interface(%s)", __FUNCTION__, if_indextoname(pi->ipi6_ifindex, ifnamebuf)); goto done; } ra->rsinput++; /* increment statistics */ /* * Decide whether to send RA according to the rate-limit * consideration. */ { long delay; /* must not be greater than 1000000 */ struct timeval interval, now, min_delay, tm_tmp, *rest; struct soliciter *sol; /* * record sockaddr waiting for RA, if possible */ sol = (struct soliciter *)malloc(sizeof(*sol)); if (sol) { sol->addr = *from; /*XXX RFC2553 need clarification on flowinfo */ sol->addr.sin6_flowinfo = 0; sol->next = ra->soliciter; ra->soliciter = sol->next; } /* * If there is already a waiting RS packet, don't * update the timer. */ if (ra->waiting++) goto done; /* * Compute a random delay. If the computed value * corresponds to a time later than the time the next * multicast RA is scheduled to be sent, ignore the random * delay and send the advertisement at the * already-scheduled time. RFC-2461 6.2.6 */ delay = random() % MAX_RA_DELAY_TIME; interval.tv_sec = 0; interval.tv_usec = delay; rest = rtadvd_timer_rest(ra->timer); if (TIMEVAL_LT(*rest, interval)) { syslog(LOG_DEBUG, "<%s> random delay is larger than " "the rest of normal timer", __FUNCTION__); interval = *rest; } /* * If we sent a multicast Router Advertisement within * the last MIN_DELAY_BETWEEN_RAS seconds, schedule * the advertisement to be sent at a time corresponding to * MIN_DELAY_BETWEEN_RAS plus the random value after the * previous advertisement was sent. */ gettimeofday(&now, NULL); TIMEVAL_SUB(&now, &ra->lastsent, &tm_tmp); min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS; min_delay.tv_usec = 0; if (TIMEVAL_LT(tm_tmp, min_delay)) { TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay); TIMEVAL_ADD(&min_delay, &interval, &interval); } rtadvd_set_timer(&interval, ra->timer); goto done; } done: free_ndopts(&ndopts); return; } static void ra_input(int len, struct nd_router_advert *ra, struct in6_pktinfo *pi, struct sockaddr_in6 *from) { struct rainfo *rai; u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; union nd_opts ndopts; char *on_off[] = {"OFF", "ON"}; u_int32_t reachabletime, retranstimer, mtu; int inconsistent = 0; syslog(LOG_DEBUG, "<%s> RA received from %s on %s", __FUNCTION__, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); if (nd6_options((struct nd_opt_hdr *)(ra + 1), len - sizeof(struct nd_router_advert), &ndopts, NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { syslog(LOG_ERR, "<%s> ND option check failed for an RA from %s on %s", __FUNCTION__, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } /* * RA consistency check according to RFC-2461 6.2.7 */ if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) { syslog(LOG_INFO, "<%s> received RA from %s on non-advertising" " interface(%s)", __FUNCTION__, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); goto done; } rai->rainput++; /* increment statistics */ /* Cur Hop Limit value */ if (ra->nd_ra_curhoplimit && rai->hoplimit && ra->nd_ra_curhoplimit != rai->hoplimit) { syslog(LOG_WARNING, "<%s> CurHopLimit inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, rai->ifname, ra->nd_ra_curhoplimit, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->hoplimit); inconsistent++; } /* M flag */ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != rai->managedflg) { syslog(LOG_WARNING, "<%s> M flag inconsistent on %s:" " %s from %s, %s from us", __FUNCTION__, rai->ifname, on_off[!rai->managedflg], inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), on_off[rai->managedflg]); inconsistent++; } /* O flag */ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != rai->otherflg) { syslog(LOG_WARNING, "<%s> O flag inconsistent on %s:" " %s from %s, %s from us", __FUNCTION__, rai->ifname, on_off[!rai->otherflg], inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), on_off[rai->otherflg]); inconsistent++; } /* Reachable Time */ reachabletime = ntohl(ra->nd_ra_reachable); if (reachabletime && rai->reachabletime && reachabletime != rai->reachabletime) { syslog(LOG_WARNING, "<%s> ReachableTime inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, rai->ifname, reachabletime, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->reachabletime); inconsistent++; } /* Retrans Timer */ retranstimer = ntohl(ra->nd_ra_retransmit); if (retranstimer && rai->retranstimer && retranstimer != rai->retranstimer) { syslog(LOG_WARNING, "<%s> RetranceTimer inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, rai->ifname, retranstimer, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->retranstimer); inconsistent++; } /* Values in the MTU options */ if (ndopts.nd_opts_mtu) { mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); if (mtu && rai->linkmtu && mtu != rai->linkmtu) { syslog(LOG_WARNING, "<%s> MTU option value inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, rai->ifname, mtu, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->linkmtu); inconsistent++; } } /* Preferred and Valid Lifetimes for prefixes */ { struct nd_optlist *optp = ndopts.nd_opts_list; if (ndopts.nd_opts_pi) { if (prefix_check(ndopts.nd_opts_pi, rai, from)) inconsistent++; } while (optp) { if (prefix_check((struct nd_opt_prefix_info *)optp->opt, rai, from)) inconsistent++; optp = optp->next; } } if (inconsistent) { printf("RA input %d inconsistents\n", inconsistent); rai->rainconsistent++; } done: free_ndopts(&ndopts); return; } /* return a non-zero value if the received prefix is inconsitent with ours */ static int prefix_check(struct nd_opt_prefix_info *pinfo, struct rainfo *rai, struct sockaddr_in6 *from) { u_int32_t preferred_time, valid_time; struct prefix *pp; int inconsistent = 0; u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; #if 0 /* impossible */ if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) return(0); #endif /* * log if the adveritsed prefix has link-local scope(sanity check?) */ if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) { syslog(LOG_INFO, "<%s> link-local prefix %s/%d is advertised " "from %s on %s", __FUNCTION__, inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, INET6_ADDRSTRLEN), pinfo->nd_opt_pi_prefix_len, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->ifname); } if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix, pinfo->nd_opt_pi_prefix_len)) == NULL) { syslog(LOG_INFO, "<%s> prefix %s/%d from %s on %s is not in our list", __FUNCTION__, inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, INET6_ADDRSTRLEN), pinfo->nd_opt_pi_prefix_len, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->ifname); return(0); } preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); if (preferred_time != pp->preflifetime) { syslog(LOG_WARNING, "<%s> prefeerred lifetime for %s/%d" " inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, INET6_ADDRSTRLEN), pinfo->nd_opt_pi_prefix_len, rai->ifname, preferred_time, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), pp->preflifetime); inconsistent++; } valid_time = ntohl(pinfo->nd_opt_pi_valid_time); if (valid_time != pp->validlifetime) { syslog(LOG_WARNING, "<%s> valid lifetime for %s/%d" " inconsistent on %s:" " %d from %s, %d from us", __FUNCTION__, inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, INET6_ADDRSTRLEN), pinfo->nd_opt_pi_prefix_len, rai->ifname, valid_time, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), pp->validlifetime); inconsistent++; } return(inconsistent); } struct prefix * find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen) { struct prefix *pp; int bytelen, bitlen; for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) { if (plen != pp->prefixlen) continue; bytelen = plen / 8; bitlen = plen % 8; if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen)) continue; if (prefix->s6_addr[bytelen] >> (8 - bitlen) == pp->prefix.s6_addr[bytelen] >> (8 - bitlen)) return(pp); } return(NULL); } static int nd6_options(struct nd_opt_hdr *hdr, int limit, union nd_opts *ndopts, u_int32_t optflags) { int optlen = 0; for (; limit > 0; limit -= optlen) { hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen); optlen = hdr->nd_opt_len << 3; if (hdr->nd_opt_len == 0) { syslog(LOG_ERR, "<%s> bad ND option length(0) (type = %d)", __FUNCTION__, hdr->nd_opt_type); goto bad; } if (hdr->nd_opt_type > ND_OPT_MTU) { syslog(LOG_INFO, "<%s> unknown ND option(type %d)", __FUNCTION__, hdr->nd_opt_type); continue; } if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) { syslog(LOG_INFO, "<%s> unexpected ND option(type %d)", __FUNCTION__, hdr->nd_opt_type); continue; } switch(hdr->nd_opt_type) { case ND_OPT_SOURCE_LINKADDR: case ND_OPT_TARGET_LINKADDR: case ND_OPT_REDIRECTED_HEADER: case ND_OPT_MTU: if (ndopts->nd_opt_array[hdr->nd_opt_type]) { syslog(LOG_INFO, "<%s> duplicated ND option" " (type = %d)", __FUNCTION__, hdr->nd_opt_type); } ndopts->nd_opt_array[hdr->nd_opt_type] = hdr; break; case ND_OPT_PREFIX_INFORMATION: { struct nd_optlist *pfxlist; if (ndopts->nd_opts_pi == 0) { ndopts->nd_opts_pi = (struct nd_opt_prefix_info *)hdr; continue; } if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) { syslog(LOG_ERR, "<%s> can't allocate memory", __FUNCTION__); goto bad; } pfxlist->next = ndopts->nd_opts_list; pfxlist->opt = hdr; ndopts->nd_opts_list = pfxlist; break; } default: /* impossible */ break; } } return(0); bad: free_ndopts(ndopts); return(-1); } static void free_ndopts(union nd_opts *ndopts) { struct nd_optlist *opt = ndopts->nd_opts_list, *next; while(opt) { next = opt->next; free(opt); opt = next; } } void sock_open() { struct icmp6_filter filt; struct ipv6_mreq mreq; struct rainfo *ra = ralist; int on; /* XXX: should be max MTU attached to the node */ static u_char answer[1500]; rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen); if (rcvcmsgbuf == NULL) { syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__); exit(1); } sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen); if (sndcmsgbuf == NULL) { syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__); exit(1); } if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, strerror(errno)); exit(1); } /* specify to tell receiving interface */ on = 1; #ifdef IPV6_RECVPKTINFO if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", __FUNCTION__, strerror(errno)); exit(1); } #else /* old adv. API */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", __FUNCTION__, strerror(errno)); exit(1); } #endif on = 1; /* specify to tell value of hoplimit field of received IP6 hdr */ #ifdef IPV6_RECVHOPLIMIT if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", __FUNCTION__, strerror(errno)); exit(1); } #else /* old adv. API */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s", __FUNCTION__, strerror(errno)); exit(1); } #endif ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); if (accept_rr) ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) { syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", __FUNCTION__, strerror(errno)); exit(1); } /* * join all routers multicast address on each advertising interface. */ if (inet_pton(AF_INET6, ALLROUTERS, &mreq.ipv6mr_multiaddr.s6_addr) != 1) { syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", __FUNCTION__); exit(1); } while(ra) { mreq.ipv6mr_interface = ra->ifindex; if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", __FUNCTION__, ra->ifname, strerror(errno)); exit(1); } ra = ra->next; } /* initialize msghdr for receiving packets */ rcviov[0].iov_base = (caddr_t)answer; rcviov[0].iov_len = sizeof(answer); rcvmhdr.msg_name = (caddr_t)&from; rcvmhdr.msg_namelen = sizeof(from); rcvmhdr.msg_iov = rcviov; rcvmhdr.msg_iovlen = 1; rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; rcvmhdr.msg_controllen = rcvcmsgbuflen; /* initialize msghdr for sending packets */ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); sndmhdr.msg_iov = sndiov; sndmhdr.msg_iovlen = 1; sndmhdr.msg_control = (caddr_t)sndcmsgbuf; sndmhdr.msg_controllen = sndcmsgbuflen; return; } /* open a routing socket to watch the routing table */ static void rtsock_open() { if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, strerror(errno)); exit(1); } } static struct rainfo * if_indextorainfo(int index) { struct rainfo *rai = ralist; for (rai = ralist; rai; rai = rai->next) { if (rai->ifindex == index) return(rai); } return(NULL); /* search failed */ } static void ra_output(rainfo) struct rainfo *rainfo; { int i; struct cmsghdr *cm; struct in6_pktinfo *pi; struct soliciter *sol, *nextsol; if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) { syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", __FUNCTION__, rainfo->ifname); return; } sndmhdr.msg_name = (caddr_t)&sin6_allnodes; sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data; sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen; cm = CMSG_FIRSTHDR(&sndmhdr); /* specify the outgoing interface */ cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; 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; /* specify the hop limit of the packet */ { int hoplimit = 255; cm = CMSG_NXTHDR(&sndmhdr, cm); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_HOPLIMIT; cm->cmsg_len = CMSG_LEN(sizeof(int)); memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); } syslog(LOG_DEBUG, "<%s> send RA on %s, # of waitings = %d", __FUNCTION__, rainfo->ifname, rainfo->waiting); i = sendmsg(sock, &sndmhdr, 0); if (i < 0 || i != rainfo->ra_datalen) { if (i < 0) { syslog(LOG_ERR, "<%s> sendmsg on %s: %s", __FUNCTION__, rainfo->ifname, strerror(errno)); } } /* * unicast advertisements * XXX commented out. reason: though spec does not forbit it, unicast * advert does not really help */ for (sol = rainfo->soliciter; sol; sol = nextsol) { nextsol = sol->next; #if 0 sndmhdr.msg_name = (caddr_t)&sol->addr; i = sendmsg(sock, &sndmhdr, 0); if (i < 0 || i != rainfo->ra_datalen) { if (i < 0) { syslog(LOG_ERR, "<%s> unicast sendmsg on %s: %s", __FUNCTION__, rainfo->ifname, strerror(errno)); } } #endif sol->next = NULL; free(sol); } rainfo->soliciter = NULL; /* update counter */ if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) rainfo->initcounter++; rainfo->raoutput++; /* update timestamp */ gettimeofday(&rainfo->lastsent, NULL); /* reset waiting conter */ rainfo->waiting = 0; } /* process RA timer */ void ra_timeout(void *data) { struct rainfo *rai = (struct rainfo *)data; #ifdef notyet /* if necessary, reconstruct the packet. */ #endif syslog(LOG_DEBUG, "<%s> RA timer on %s is expired", __FUNCTION__, rai->ifname); ra_output(rai); } /* update RA timer */ void ra_timer_update(void *data, struct timeval *tm) { struct rainfo *rai = (struct rainfo *)data; long interval; /* * Whenever a multicast advertisement is sent from an interface, * the timer is reset to a uniformly-distributed random value * between the interface's configured MinRtrAdvInterval and * MaxRtrAdvInterval(discovery-v2-02 6.2.4). */ interval = rai->mininterval; interval += random() % (rai->maxinterval - rai->mininterval); /* * For the first few advertisements (up to * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead. * (RFC-2461 6.2.4) */ if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && interval > MAX_INITIAL_RTR_ADVERT_INTERVAL) interval = MAX_INITIAL_RTR_ADVERT_INTERVAL; tm->tv_sec = interval; tm->tv_usec = 0; syslog(LOG_DEBUG, "<%s> RA timer on %s is set to %ld:%ld", __FUNCTION__, rai->ifname, (long int)tm->tv_sec, (long int)tm->tv_usec); return; } Index: head/usr.sbin/rtadvd/rtadvd.h =================================================================== --- head/usr.sbin/rtadvd/rtadvd.h (revision 71332) +++ head/usr.sbin/rtadvd/rtadvd.h (revision 71333) @@ -1,151 +1,150 @@ +/* $FreeBSD$ */ /* $KAME: rtadvd.h,v 1.8 2000/05/16 13:34:14 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. - * - * $FreeBSD$ */ #define ALLNODES "ff02::1" #define ALLROUTERS "ff02::2" #define ANY "::" #define RTSOLLEN 8 /* protocol constants and default values */ #define DEF_MAXRTRADVINTERVAL 600 #define DEF_ADVLINKMTU 0 #define DEF_ADVREACHABLETIME 0 #define DEF_ADVRETRANSTIMER 0 #define DEF_ADVCURHOPLIMIT 64 #define DEF_ADVVALIDLIFETIME 2592000 #define DEF_ADVPREFERREDLIFETIME 604800 /*XXX int-to-double comparison for INTERVAL items */ #ifndef MIP6 #define mobileip6 0 #endif #define MAXROUTERLIFETIME 9000 #define MIN_MAXINTERVAL (mobileip6 ? 1.5 : 4.0) #define MAX_MAXINTERVAL 1800 #define MIN_MININTERVAL (mobileip6 ? 0.5 : 3) #define MAXREACHABLETIME 3600000 #ifndef MIP6 #undef miobileip6 #endif #define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 #define MAX_INITIAL_RTR_ADVERTISEMENTS 3 #define MAX_FINAL_RTR_ADVERTISEMENTS 3 #define MIN_DELAY_BETWEEN_RAS 3 #define MAX_RA_DELAY_TIME 500000 /* usec */ #define PREFIX_FROM_KERNEL 1 #define PREFIX_FROM_CONFIG 2 #define PREFIX_FROM_DYNAMIC 3 struct prefix { struct prefix *next; /* forward link */ struct prefix *prev; /* previous link */ u_int32_t validlifetime; /* AdvValidLifetime */ u_int32_t preflifetime; /* AdvPreferredLifetime */ u_int onlinkflg; /* bool: AdvOnLinkFlag */ u_int autoconfflg; /* bool: AdvAutonomousFlag */ #ifdef MIP6 u_int routeraddr; /* bool: RouterAddress */ #endif int prefixlen; int origin; /* from kernel or cofig */ struct in6_addr prefix; }; struct soliciter { struct soliciter *next; struct sockaddr_in6 addr; }; struct rainfo { /* pointer for list */ struct rainfo *next; /* timer related parameters */ struct rtadvd_timer *timer; int initcounter; /* counter for the first few advertisements */ struct timeval lastsent; /* timestamp when the latest RA was sent */ int waiting; /* number of RS waiting for RA */ /* interface information */ int ifindex; int advlinkopt; /* bool: whether include link-layer addr opt */ struct sockaddr_dl *sdl; char ifname[16]; int phymtu; /* mtu of the physical interface */ /* Router configuration variables */ u_short lifetime; /* AdvDefaultLifetime */ u_int maxinterval; /* MaxRtrAdvInterval */ u_int mininterval; /* MinRtrAdvInterval */ int managedflg; /* AdvManagedFlag */ int otherflg; /* AdvOtherConfigFlag */ #ifdef MIP6 int haflg; /* HAFlag */ #endif u_int32_t linkmtu; /* AdvLinkMTU */ u_int32_t reachabletime; /* AdvReachableTime */ u_int32_t retranstimer; /* AdvRetransTimer */ u_int hoplimit; /* AdvCurHopLimit */ struct prefix prefix; /* AdvPrefixList(link head) */ int pfxs; /* number of prefixes */ #ifdef MIP6 u_short hapref; /* Home Agent Preference */ u_short hatime; /* Home Agent Lifetime */ #endif /* actual RA packet data and its length */ size_t ra_datalen; u_char *ra_data; /* statistics */ u_quad_t raoutput; /* number of RAs sent */ u_quad_t rainput; /* number of RAs received */ u_quad_t rainconsistent; /* number of RAs inconsistent with ours */ u_quad_t rsinput; /* number of RSs received */ /* info about soliciter */ struct soliciter *soliciter; /* recent solication source */ }; void ra_timeout __P((void *)); void ra_timer_update __P((void *, struct timeval *)); #ifdef MIP6 extern int mobileip6; #endif Index: head/usr.sbin/rtadvd/timer.c =================================================================== --- head/usr.sbin/rtadvd/timer.c (revision 71332) +++ head/usr.sbin/rtadvd/timer.c (revision 71333) @@ -1,217 +1,216 @@ +/* $FreeBSD$ */ /* $KAME: timer.c,v 1.3 2000/05/22 22:23:07 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. - * - * $FreeBSD$ */ #include #include #include #include #include #if defined(__NetBSD__) || defined(__OpenBSD__) #include #endif #include "timer.h" static struct rtadvd_timer timer_head; #define MILLION 1000000 #define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\ (t1)->tv_usec == (t2)->tv_usec) static struct timeval tm_max = {0x7fffffff, 0x7fffffff}; void rtadvd_timer_init() { memset(&timer_head, 0, sizeof(timer_head)); timer_head.next = timer_head.prev = &timer_head; timer_head.tm = tm_max; } struct rtadvd_timer * rtadvd_add_timer(void (*timeout) __P((void *)), void (*update) __P((void *, struct timeval *)), void *timeodata, void *updatedata) { struct rtadvd_timer *newtimer; if ((newtimer = malloc(sizeof(*newtimer))) == NULL) { syslog(LOG_ERR, "<%s> can't allocate memory", __FUNCTION__); exit(1); } memset(newtimer, 0, sizeof(*newtimer)); if (timeout == NULL) { syslog(LOG_ERR, "<%s> timeout function unspecfied", __FUNCTION__); exit(1); } if (update == NULL) { syslog(LOG_ERR, "<%s> update function unspecfied", __FUNCTION__); exit(1); } newtimer->expire = timeout; newtimer->update = update; newtimer->expire_data = timeodata; newtimer->update_data = updatedata; newtimer->tm = tm_max; /* link into chain */ insque(newtimer, &timer_head); return(newtimer); } void rtadvd_remove_timer(struct rtadvd_timer **timer) { remque(*timer); free(*timer); *timer = NULL; } void rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer) { struct timeval now; /* reset the timer */ gettimeofday(&now, NULL); TIMEVAL_ADD(&now, tm, &timer->tm); /* update the next expiration time */ if (TIMEVAL_LT(timer->tm, timer_head.tm)) timer_head.tm = timer->tm; return; } /* * Check expiration for each timer. If a timer is expired, * call the expire function for the timer and update the timer. * Return the next interval for select() call. */ struct timeval * rtadvd_check_timer() { static struct timeval returnval; struct timeval now; struct rtadvd_timer *tm = timer_head.next; gettimeofday(&now, NULL); timer_head.tm = tm_max; while(tm != &timer_head) { if (TIMEVAL_LEQ(tm->tm, now)) { (*tm->expire)(tm->expire_data); (*tm->update)(tm->update_data, &tm->tm); TIMEVAL_ADD(&tm->tm, &now, &tm->tm); } if (TIMEVAL_LT(tm->tm, timer_head.tm)) timer_head.tm = tm->tm; tm = tm->next; } if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) { /* no need to timeout */ return(NULL); } else if (TIMEVAL_LT(timer_head.tm, now)) { /* this may occur when the interval is too small */ returnval.tv_sec = returnval.tv_usec = 0; } else TIMEVAL_SUB(&timer_head.tm, &now, &returnval); return(&returnval); } struct timeval * rtadvd_timer_rest(struct rtadvd_timer *timer) { static struct timeval returnval, now; gettimeofday(&now, NULL); if (TIMEVAL_LEQ(timer->tm, now)) { syslog(LOG_DEBUG, "<%s> a timer must be expired, but not yet", __FUNCTION__); returnval.tv_sec = returnval.tv_usec = 0; } else TIMEVAL_SUB(&timer->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; } } Index: head/usr.sbin/rtadvd/timer.h =================================================================== --- head/usr.sbin/rtadvd/timer.h (revision 71332) +++ head/usr.sbin/rtadvd/timer.h (revision 71333) @@ -1,66 +1,65 @@ +/* $FreeBSD$ */ /* $KAME: timer.h,v 1.2 2000/05/16 13:34:14 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. - * - * $FreeBSD$ */ /* 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))) struct rtadvd_timer { struct rtadvd_timer *next; struct rtadvd_timer *prev; struct rainfo *rai; struct timeval tm; void (*expire) __P((void *)); /* expiration function */ void *expire_data; void (*update) __P((void *, struct timeval *)); /* update function */ void *update_data; }; void rtadvd_timer_init __P((void)); struct rtadvd_timer *rtadvd_add_timer __P((void (*) __P((void *)), void (*) __P((void *, struct timeval *)), void *, void *)); void rtadvd_set_timer __P((struct timeval *, struct rtadvd_timer *)); void rtadvd_remove_timer __P((struct rtadvd_timer **)); struct timeval * rtadvd_check_timer __P((void)); struct timeval * rtadvd_timer_rest __P((struct rtadvd_timer *)); void TIMEVAL_ADD __P((struct timeval *, struct timeval *, struct timeval *)); void TIMEVAL_SUB __P((struct timeval *, struct timeval *, struct timeval *));