config.c revision 97709
14Srgrimes/* $FreeBSD: head/usr.sbin/rtadvd/config.c 97709 2002-06-01 16:50:21Z ume $ */ 24Srgrimes/* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */ 34Srgrimes 44Srgrimes/* 54Srgrimes * Copyright (C) 1998 WIDE Project. 64Srgrimes * All rights reserved. 74Srgrimes * 84Srgrimes * Redistribution and use in source and binary forms, with or without 94Srgrimes * modification, are permitted provided that the following conditions 104Srgrimes * are met: 114Srgrimes * 1. Redistributions of source code must retain the above copyright 124Srgrimes * notice, this list of conditions and the following disclaimer. 134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 144Srgrimes * notice, this list of conditions and the following disclaimer in the 154Srgrimes * documentation and/or other materials provided with the distribution. 164Srgrimes * 3. Neither the name of the project nor the names of its contributors 174Srgrimes * may be used to endorse or promote products derived from this software 184Srgrimes * without specific prior written permission. 194Srgrimes * 204Srgrimes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 214Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 244Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304Srgrimes * SUCH DAMAGE. 314Srgrimes */ 324Srgrimes 334Srgrimes#include <sys/param.h> 344Srgrimes#include <sys/ioctl.h> 354Srgrimes#include <sys/socket.h> 36619Srgrimes#include <sys/time.h> 3750477Speter#include <sys/sysctl.h> 384Srgrimes 394Srgrimes#include <net/if.h> 403185Ssos#if defined(__FreeBSD__) && __FreeBSD__ >= 3 4119173Sbde#include <net/if_var.h> 4219173Sbde#endif /* __FreeBSD__ >= 3 */ 4319173Sbde#include <net/route.h> 4419173Sbde#include <net/if_dl.h> 453185Ssos 463185Ssos#include <netinet/in.h> 473185Ssos#include <netinet/in_var.h> 483185Ssos#include <netinet/ip6.h> 492913Sache#include <netinet6/ip6_var.h> 502913Sache#include <netinet/icmp6.h> 5116299Spst#ifdef MIP6 5233929Sphk#include <netinet6/mip6.h> 5313228Swollman#endif 542056Swollman 552056Swollman#include <arpa/inet.h> 5661994Smsmith 5767356Sjhb#include <stdio.h> 5867356Sjhb#include <syslog.h> 5965557Sjasone#include <errno.h> 602056Swollman#include <string.h> 6158377Sphk#include <stdlib.h> 622056Swollman#if defined(__NetBSD__) || defined(__OpenBSD__) 6331253Sbde#include <search.h> 6431253Sbde#endif 6531253Sbde#include <unistd.h> 6615508Sbde#include <ifaddrs.h> 6749558Sphk 6815508Sbde#include "rtadvd.h" 694180Sbde#include "advcap.h" 7015508Sbde#include "timer.h" 7115508Sbde#include "if.h" 7230805Sbde#include "config.h" 732056Swollman 7428551Sbdestatic void makeentry __P((char *, size_t, int, char *, int)); 7532054Sphkstatic void get_prefix __P((struct rainfo *)); 7647588Sbdestatic int getinet6sysctl __P((int)); 7730805Sbde 7830805Sbdeextern struct rainfo *ralist; 7930805Sbde 8028921Sfsmpvoid 8126949Sfsmpgetconfig(intface) 8228921Sfsmp char *intface; 8332054Sphk{ 8415508Sbde int stat, pfxs, i; 852056Swollman char tbuf[BUFSIZ]; 862056Swollman struct rainfo *tmp; 8747642Sdfr long val; 8861994Smsmith long long val64; 892056Swollman char buf[BUFSIZ]; 904Srgrimes char *bp = buf; 9145897Speter char *addr; 9228487Sfsmp static int forwarding = -1; 9350823Smdodd 9450823Smdodd#define MUSTHAVE(var, cap) \ 9550823Smdodd do { \ 9650823Smdodd int t; \ 9750823Smdodd if ((t = agetnum(cap)) < 0) { \ 9834571Stegge fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 9934571Stegge cap, intface); \ 10034058Stegge exit(1); \ 10134058Stegge } \ 10234571Stegge var = t; \ 10334571Stegge } while (0) 10434571Stegge#define MAYHAVE(var, cap, def) \ 10528921Sfsmp do { \ 1062873Sbde if ((var = agetnum(cap)) < 0) \ 1072873Sbde var = def; \ 1082873Sbde } while (0) 1092873Sbde 1102873Sbde if ((stat = agetent(tbuf, intface)) <= 0) { 1112913Sache memset(tbuf, 0, sizeof(tbuf)); 1122873Sbde syslog(LOG_INFO, 11315508Sbde "<%s> %s isn't defined in the configuration file" 1144Srgrimes " or the configuration file doesn't exist." 1154180Sbde " Treat it as default", 1164180Sbde __FUNCTION__, intface); 1174180Sbde } 1184180Sbde 1194180Sbde tmp = (struct rainfo *)malloc(sizeof(*ralist)); 1204180Sbde memset(tmp, 0, sizeof(*tmp)); 1214180Sbde tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; 1224180Sbde tmp->route.next = tmp->route.prev = &tmp->route; 1234180Sbde 1244180Sbde /* check if we are allowed to forward packets (if not determined) */ 12517236Sjoerg if (forwarding < 0) { 12617231Sjoerg if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) 12733690Sphk exit(1); 1284180Sbde } 12917231Sjoerg 1304180Sbde /* get interface information */ 13141787Smckay if (agetflag("nolladdr")) 13247588Sbde tmp->advlinkopt = 0; 13315045Sache else 13432052Sphk tmp->advlinkopt = 1; 13533690Sphk if (tmp->advlinkopt) { 13633690Sphk if ((tmp->sdl = if_nametosdl(intface)) == NULL) { 13733690Sphk syslog(LOG_ERR, 13832052Sphk "<%s> can't get information of %s", 13932052Sphk __FUNCTION__, intface); 14032005Sphk exit(1); 14147592Sphk } 14241787Smckay tmp->ifindex = tmp->sdl->sdl_index; 14367356Sjhb } else 1441390Ssos tmp->ifindex = if_nametoindex(intface); 1454180Sbde strncpy(tmp->ifname, intface, sizeof(tmp->ifname)); 1464180Sbde if ((tmp->phymtu = if_getmtu(intface)) == 0) { 14719173Sbde tmp->phymtu = IPV6_MMTU; 14833690Sphk syslog(LOG_WARNING, 14933690Sphk "<%s> can't get interface mtu of %s. Treat as %d", 15033690Sphk __FUNCTION__, intface, IPV6_MMTU); 1514180Sbde } 1524180Sbde 1534180Sbde /* 15454890Speter * set router configuration variables. 1554180Sbde */ 1564180Sbde MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 15719173Sbde if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 15819173Sbde syslog(LOG_ERR, 1594180Sbde "<%s> maxinterval must be between %e and %u", 16015345Snate __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 16133690Sphk exit(1); 16217231Sjoerg } 16317231Sjoerg tmp->maxinterval = (u_int)val; 16417236Sjoerg MAYHAVE(val, "mininterval", tmp->maxinterval/3); 16517236Sjoerg if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { 16617236Sjoerg syslog(LOG_ERR, 16717236Sjoerg "<%s> mininterval must be between %e and %d", 16817231Sjoerg __FUNCTION__, 16917231Sjoerg MIN_MININTERVAL, 17017231Sjoerg (tmp->maxinterval * 3) / 4); 17119173Sbde exit(1); 17233690Sphk } 1734180Sbde tmp->mininterval = (u_int)val; 17436719Sphk 17536719Sphk MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 17621783Sbde tmp->hoplimit = val & 0xff; 17717353Sbde 17840610Sphk MAYHAVE(val, "raflags", 0); 17933690Sphk tmp->managedflg = val & ND_RA_FLAG_MANAGED; 18036741Sphk tmp->otherflg = val & ND_RA_FLAG_OTHER; 18136198Sphk#ifdef MIP6 18233690Sphk if (mobileip6) 18333690Sphk tmp->haflg = val & ND_RA_FLAG_HA; 18433690Sphk#endif 18533690Sphk#ifndef ND_RA_FLAG_RTPREF_MASK 18633690Sphk#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 18740610Sphk#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 18833690Sphk#endif 18940610Sphk tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 19033690Sphk if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { 19136741Sphk syslog(LOG_ERR, "<%s> invalid router preference on %s", 19236198Sphk __FUNCTION__, intface); 19333690Sphk exit(1); 19433690Sphk } 19533690Sphk 19633690Sphk MAYHAVE(val, "rltime", tmp->maxinterval * 3); 19733690Sphk if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { 19840610Sphk syslog(LOG_ERR, 19933690Sphk "<%s> router lifetime on %s must be 0 or" 20012724Sphk " between %d and %d", 2013185Ssos __FUNCTION__, intface, 2022074Swollman tmp->maxinterval, MAXROUTERLIFETIME); 20365557Sjasone exit(1); 20439503Sbde } 20566716Sjhb /* 20647588Sbde * Basically, hosts MUST NOT send Router Advertisement messages at any 20739503Sbde * time (RFC 2461, Section 6.2.3). However, it would sometimes be 20847588Sbde * useful to allow hosts to advertise some parameters such as prefix 20939503Sbde * information and link MTU. Thus, we allow hosts to invoke rtadvd 21039503Sbde * only when router lifetime (on every advertising interface) is 21139503Sbde * explicitly set zero. (see also the above section) 21247588Sbde */ 21366716Sjhb if (val && forwarding == 0) { 21439503Sbde syslog(LOG_WARNING, 2151549Srgrimes "<%s> non zero router lifetime is specified for %s, " 2161442Ssos "which must not be allowed for hosts.", 21717236Sjoerg __FUNCTION__, intface); 21817231Sjoerg exit(1); 2198448Sbde } 2201442Ssos tmp->lifetime = val & 0xffff; 22117236Sjoerg 22217231Sjoerg MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 2234180Sbde if (val > MAXREACHABLETIME) { 2244180Sbde syslog(LOG_ERR, 22533309Sbde "<%s> reachable time must be no greater than %d", 2261549Srgrimes __FUNCTION__, MAXREACHABLETIME); 2278448Sbde exit(1); 2281390Ssos } 2291442Ssos tmp->reachabletime = (u_int32_t)val; 23017236Sjoerg 23117231Sjoerg MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 23266716Sjhb if (val64 < 0 || val64 > 0xffffffff) { 23348889Sbde syslog(LOG_ERR, 23448889Sbde "<%s> retrans time out of range", __FUNCTION__); 2354180Sbde exit(1); 2364180Sbde } 2374180Sbde tmp->retranstimer = (u_int32_t)val64; 2384180Sbde 23966716Sjhb#ifndef MIP6 2401442Ssos if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { 24117231Sjoerg syslog(LOG_ERR, 24248889Sbde "<%s> mobile-ip6 configuration not supported", 2431442Ssos __FUNCTION__); 24417236Sjoerg exit(1); 24517231Sjoerg } 2464180Sbde#else 2474180Sbde if (!mobileip6) { 24866716Sjhb if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { 24948889Sbde syslog(LOG_ERR, 25048889Sbde "<%s> mobile-ip6 configuration without " 2515291Sbde "proper command line option", 2524180Sbde __FUNCTION__); 2534180Sbde exit(1); 2544180Sbde } 2554180Sbde } else { 25666716Sjhb tmp->hapref = 0; 2574180Sbde if ((val = agetnum("hapref")) >= 0) 25817231Sjoerg tmp->hapref = (int16_t)val; 25917231Sjoerg if (tmp->hapref != 0) { 26048889Sbde tmp->hatime = 0; 26148889Sbde MUSTHAVE(val, "hatime"); 2621442Ssos tmp->hatime = (u_int16_t)val; 2631442Ssos if (tmp->hatime <= 0) { 2641442Ssos syslog(LOG_ERR, 26550823Smdodd "<%s> home agent lifetime must be greater than 0", 26650823Smdodd __FUNCTION__); 26750823Smdodd exit(1); 26850823Smdodd } 26950823Smdodd } 2701390Ssos } 2711390Ssos#endif 27217231Sjoerg 27317236Sjoerg /* prefix information */ 27417231Sjoerg 2751390Ssos /* 2764180Sbde * This is an implementation specific parameter to consinder 2771390Ssos * link propagation delays and poorly synchronized clocks when 27817231Sjoerg * checking consistency of advertised lifetimes. 27917231Sjoerg */ 28017231Sjoerg MAYHAVE(val, "clockskew", 0); 28117231Sjoerg tmp->clockskew = val; 28217231Sjoerg 28317231Sjoerg if ((pfxs = agetnum("addrs")) < 0) { 28417236Sjoerg /* auto configure prefix information */ 28517236Sjoerg if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { 28617236Sjoerg syslog(LOG_ERR, 28717231Sjoerg "<%s> conflicting prefix configuration for %s: " 28817236Sjoerg "automatic and manual config at the same time", 28917236Sjoerg __FUNCTION__, intface); 29017236Sjoerg exit(1); 29117236Sjoerg } 29217236Sjoerg get_prefix(tmp); 29317236Sjoerg } 29417236Sjoerg else { 29517236Sjoerg tmp->pfxs = pfxs; 29617236Sjoerg for (i = 0; i < pfxs; i++) { 29717236Sjoerg struct prefix *pfx; 29817236Sjoerg char entbuf[256]; 29917236Sjoerg int added = (pfxs > 1) ? 1 : 0; 30017236Sjoerg 30117236Sjoerg /* allocate memory to store prefix information */ 30217231Sjoerg if ((pfx = malloc(sizeof(struct prefix))) == NULL) { 3031442Ssos syslog(LOG_ERR, 30417231Sjoerg "<%s> can't allocate enough memory", 30517231Sjoerg __FUNCTION__); 3061390Ssos exit(1); 3071390Ssos } 3081390Ssos memset(pfx, 0, sizeof(*pfx)); 3091390Ssos 3101390Ssos /* link into chain */ 31117231Sjoerg insque(pfx, &tmp->prefix); 31217231Sjoerg 31317231Sjoerg pfx->origin = PREFIX_FROM_CONFIG; 31417231Sjoerg 31517236Sjoerg makeentry(entbuf, sizeof(entbuf), i, "prefixlen", 31617236Sjoerg added); 31717236Sjoerg MAYHAVE(val, entbuf, 64); 31817236Sjoerg if (val < 0 || val > 128) { 31917236Sjoerg syslog(LOG_ERR, 32017236Sjoerg "<%s> prefixlen out of range", 32117236Sjoerg __FUNCTION__); 32217236Sjoerg exit(1); 32317236Sjoerg } 32417236Sjoerg pfx->prefixlen = (int)val; 32517231Sjoerg 3261390Ssos makeentry(entbuf, sizeof(entbuf), i, "pinfoflags", 3271390Ssos added); 3281390Ssos#ifdef MIP6 3291390Ssos if (mobileip6) 3301390Ssos { 33117231Sjoerg MAYHAVE(val, entbuf, 33217231Sjoerg (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| 33317236Sjoerg ND_OPT_PI_FLAG_ROUTER)); 33417236Sjoerg } else 33517236Sjoerg#endif 33617231Sjoerg { 33717236Sjoerg MAYHAVE(val, entbuf, 33817236Sjoerg (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 33917236Sjoerg } 34017236Sjoerg pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 34117236Sjoerg pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 34217236Sjoerg#ifdef MIP6 34317236Sjoerg pfx->routeraddr = val & ND_OPT_PI_FLAG_ROUTER; 34417231Sjoerg#endif 34517231Sjoerg 3461390Ssos makeentry(entbuf, sizeof(entbuf), i, "vltime", added); 3471390Ssos MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 3481390Ssos if (val64 < 0 || val64 > 0xffffffff) { 3491390Ssos syslog(LOG_ERR, 3501390Ssos "<%s> vltime out of range", 35117231Sjoerg __FUNCTION__); 35217231Sjoerg exit(1); 35317231Sjoerg } 35417231Sjoerg pfx->validlifetime = (u_int32_t)val64; 35517236Sjoerg 35617231Sjoerg makeentry(entbuf, sizeof(entbuf), i, "vltimedecr", 3571390Ssos added); 3581390Ssos if (agetflag(entbuf)) { 3593185Ssos struct timeval now; 3603185Ssos gettimeofday(&now, 0); 3613185Ssos pfx->vltimeexpire = 3623185Ssos now.tv_sec + pfx->validlifetime; 3633185Ssos } 3643185Ssos 3653185Ssos makeentry(entbuf, sizeof(entbuf), i, "pltime", added); 3663185Ssos MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 3673185Ssos if (val64 < 0 || val64 > 0xffffffff) { 3683185Ssos syslog(LOG_ERR, 3693185Ssos "<%s> pltime out of range", 3703185Ssos __FUNCTION__); 37124676Smckay exit(1); 37224676Smckay } 37324676Smckay pfx->preflifetime = (u_int32_t)val64; 37424676Smckay 37524676Smckay makeentry(entbuf, sizeof(entbuf), i, "pltimedecr", 37624676Smckay added); 37724676Smckay if (agetflag(entbuf)) { 37824676Smckay struct timeval now; 3793185Ssos gettimeofday(&now, 0); 38012724Sphk pfx->pltimeexpire = 3813185Ssos now.tv_sec + pfx->preflifetime; 3823185Ssos } 38324676Smckay 3843185Ssos makeentry(entbuf, sizeof(entbuf), i, "addr", added); 3853185Ssos addr = (char *)agetstr(entbuf, &bp); 3861390Ssos if (addr == NULL) { 38718297Sbde syslog(LOG_ERR, 3885291Sbde "<%s> need %s as an prefix for " 38918297Sbde "interface %s", 39018297Sbde __FUNCTION__, entbuf, intface); 39118297Sbde exit(1); 3923185Ssos } 3935291Sbde if (inet_pton(AF_INET6, addr, 3945291Sbde &pfx->prefix) != 1) { 3955291Sbde syslog(LOG_ERR, 3965291Sbde "<%s> inet_pton failed for %s", 3973185Ssos __FUNCTION__, addr); 39818297Sbde exit(1); 3993185Ssos } 4001390Ssos if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { 40110268Sbde syslog(LOG_ERR, 4021390Ssos "<%s> multicast prefix(%s) must " 40366716Sjhb "not be advertised (IF=%s)", 4041390Ssos __FUNCTION__, addr, intface); 40566716Sjhb exit(1); 40616428Sbde } 40716428Sbde if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) 40819173Sbde syslog(LOG_NOTICE, 40916428Sbde "<%s> link-local prefix(%s) will be" 4101390Ssos " advertised on %s", 4111390Ssos __FUNCTION__, addr, intface); 41216428Sbde } 41366716Sjhb } 4141390Ssos 4151390Ssos MAYHAVE(val, "mtu", 0); 4161390Ssos if (val < 0 || val > 0xffffffff) { 4172017Swollman syslog(LOG_ERR, 4181390Ssos "<%s> mtu out of range", __FUNCTION__); 41915508Sbde exit(1); 4201390Ssos } 4211390Ssos tmp->linkmtu = (u_int32_t)val; 4221390Ssos if (tmp->linkmtu == 0) { 4231390Ssos char *mtustr; 4241390Ssos 42522106Sbde if ((mtustr = (char *)agetstr("mtu", &bp)) && 4261390Ssos strcmp(mtustr, "auto") == 0) 4271390Ssos tmp->linkmtu = tmp->phymtu; 4281390Ssos } 4291390Ssos else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { 4301390Ssos syslog(LOG_ERR, 4311390Ssos "<%s> advertised link mtu must be between" 4321390Ssos " least MTU and physical link MTU", 4331390Ssos __FUNCTION__); 4341390Ssos exit(1); 4351390Ssos } 4361390Ssos 4371390Ssos /* route information */ 4381390Ssos 4391390Ssos MAYHAVE(val, "routes", 0); 4401390Ssos if (val < 0 || val > 0xffffffff) { 4411390Ssos syslog(LOG_ERR, 44221783Sbde "<%s> number of route information improper", __FUNCTION__); 44321783Sbde exit(1); 44421783Sbde } 44521783Sbde tmp->routes = val; 44621783Sbde for (i = 0; i < tmp->routes; i++) { 44721783Sbde struct rtinfo *rti; 44821783Sbde char entbuf[256]; 4491390Ssos int added = (tmp->routes > 1) ? 1 : 0; 4501390Ssos 4511390Ssos /* allocate memory to store prefix information */ 4521390Ssos if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { 4531390Ssos syslog(LOG_ERR, 4541390Ssos "<%s> can't allocate enough memory", 45510268Sbde __FUNCTION__); 45622106Sbde exit(1); 4571390Ssos } 45815508Sbde memset(rti, 0, sizeof(*rti)); 4591390Ssos 4601390Ssos /* link into chain */ 46122106Sbde insque(rti, &tmp->route); 46222106Sbde 46322106Sbde makeentry(entbuf, sizeof(entbuf), i, "rtrplen", added); 46422106Sbde MAYHAVE(val, entbuf, 64); 46522106Sbde if (val < 0 || val > 128) { 46622106Sbde syslog(LOG_ERR, 46722106Sbde "<%s> prefixlen out of range", 46822106Sbde __FUNCTION__); 46922106Sbde exit(1); 47022106Sbde } 47122106Sbde rti->prefixlen = (int)val; 47222106Sbde 47322106Sbde makeentry(entbuf, sizeof(entbuf), i, "rtrflags", added); 47422106Sbde MAYHAVE(val, entbuf, 0); 47522106Sbde rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 47622106Sbde if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { 47722106Sbde syslog(LOG_ERR, "<%s> invalid router preference", 47822106Sbde __FUNCTION__); 47922106Sbde exit(1); 4801390Ssos } 4811390Ssos 48210268Sbde makeentry(entbuf, sizeof(entbuf), i, "rtrltime", added); 4831390Ssos /* 4841390Ssos * XXX: since default value of route lifetime is not defined in 4851390Ssos * draft-draves-route-selection-01.txt, I took the default 48621783Sbde * value of valid lifetime of prefix as its default. 4871390Ssos * It need be much considered. 48821783Sbde */ 48921783Sbde MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 49021783Sbde if (val64 < 0 || val64 > 0xffffffff) { 49121783Sbde syslog(LOG_ERR, 49221783Sbde "<%s> rtrltime out of range", 49321783Sbde __FUNCTION__); 49421783Sbde exit(1); 49521783Sbde } 49621783Sbde rti->ltime = (u_int32_t)val64; 49721783Sbde 49821783Sbde makeentry(entbuf, sizeof(entbuf), i, "rtrprefix", added); 49921783Sbde addr = (char *)agetstr(entbuf, &bp); 5001390Ssos if (addr == NULL) { 5011390Ssos syslog(LOG_ERR, 5021390Ssos "<%s> need %s as an route for " 5031390Ssos "interface %s", 5041390Ssos __FUNCTION__, entbuf, intface); 5051390Ssos exit(1); 5061390Ssos } 5071390Ssos if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { 5081390Ssos syslog(LOG_ERR, 5093185Ssos "<%s> inet_pton failed for %s", 5101390Ssos __FUNCTION__, addr); 5111390Ssos exit(1); 5121390Ssos } 5131390Ssos#if 0 5141390Ssos /* 5151390Ssos * XXX: currently there's no restriction in route information 5168876Srgrimes * prefix according to draft-draves-route-selection-01.txt, 5171390Ssos * however I think the similar restriction be necessary. 5181390Ssos */ 51917231Sjoerg MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 5201390Ssos if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 5218876Srgrimes syslog(LOG_ERR, 52217231Sjoerg "<%s> multicast route (%s) must " 52317231Sjoerg "not be advertised (IF=%s)", 52417231Sjoerg __FUNCTION__, addr, intface); 52517231Sjoerg exit(1); 52617231Sjoerg } 52766716Sjhb if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 5281390Ssos syslog(LOG_NOTICE, 5291390Ssos "<%s> link-local route (%s) must " 53066716Sjhb "not be advertised on %s", 5311390Ssos __FUNCTION__, addr, intface); 53217231Sjoerg exit(1); 53317231Sjoerg } 5341390Ssos#endif 5352873Sbde } 5361390Ssos 53717231Sjoerg /* okey */ 53817231Sjoerg tmp->next = ralist; 5391390Ssos ralist = tmp; 5401390Ssos 5412913Sache /* construct the sending packet */ 5422913Sache make_packet(tmp); 5432913Sache 5442913Sache /* set timer */ 54514943Sbde tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 54614943Sbde tmp, tmp); 54714943Sbde ra_timer_update((void *)tmp, &tmp->timer->tm); 54814943Sbde rtadvd_set_timer(&tmp->timer->tm, tmp->timer); 54955098Sbde} 55014943Sbde 55114943Sbdestatic void 55255098Sbdeget_prefix(struct rainfo *rai) 55314943Sbde{ 55414943Sbde struct ifaddrs *ifap, *ifa; 55514943Sbde struct prefix *pp; 55614943Sbde struct in6_addr *a; 55755098Sbde u_char *p, *ep, *m, *lim; 55814943Sbde u_char ntopbuf[INET6_ADDRSTRLEN]; 55914943Sbde 56014943Sbde if (getifaddrs(&ifap) < 0) { 56113445Sphk syslog(LOG_ERR, 5625291Sbde "<%s> can't get interface addresses", 5632913Sache __FUNCTION__); 56455098Sbde exit(1); 56555098Sbde } 56655098Sbde for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 56733309Sbde if (strcmp(ifa->ifa_name, rai->ifname) != 0) 5685291Sbde continue; 56933309Sbde if (ifa->ifa_addr->sa_family != AF_INET6) 5705291Sbde continue; 57133309Sbde a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 57255098Sbde if (IN6_IS_ADDR_LINKLOCAL(a)) 5732913Sache continue; 5742913Sache 57513445Sphk /* allocate memory to store prefix info. */ 5762913Sache if ((pp = malloc(sizeof(*pp))) == NULL) { 5772913Sache syslog(LOG_ERR, 57813445Sphk "<%s> can't get allocate buffer for prefix", 5792913Sache __FUNCTION__); 5802913Sache exit(1); 58115508Sbde } 58215508Sbde memset(pp, 0, sizeof(*pp)); 58315508Sbde 58448160Sgreen /* set prefix length */ 58515508Sbde m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 58615508Sbde lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 58715508Sbde pp->prefixlen = prefixlen(m, lim); 58823393Sbde if (pp->prefixlen < 0 || pp->prefixlen > 128) { 58923393Sbde syslog(LOG_ERR, 59015508Sbde "<%s> failed to get prefixlen " 59115508Sbde "or prefix is invalid", 59215508Sbde __FUNCTION__); 59315508Sbde exit(1); 59415508Sbde } 59515508Sbde 59615508Sbde /* set prefix, sweep bits outside of prefixlen */ 59715508Sbde memcpy(&pp->prefix, a, sizeof(*a)); 59815508Sbde p = (u_char *)&pp->prefix; 59915508Sbde ep = (u_char *)(&pp->prefix + 1); 60015508Sbde while (m < lim) 60115508Sbde *p++ &= *m++; 60215508Sbde while (p < ep) 60315508Sbde *p++ = 0x00; 60415508Sbde 60515508Sbde if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, 60615508Sbde sizeof(ntopbuf))) { 60715508Sbde syslog(LOG_ERR, "<%s> inet_ntop failed", __FUNCTION__); 60815508Sbde exit(1); 60915508Sbde } 61015508Sbde syslog(LOG_DEBUG, 61115508Sbde "<%s> add %s/%d to prefix list on %s", 61215508Sbde __FUNCTION__, ntopbuf, pp->prefixlen, rai->ifname); 61315508Sbde 61415508Sbde /* set other fields with protocol defaults */ 61515508Sbde pp->validlifetime = DEF_ADVVALIDLIFETIME; 61615508Sbde pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 61715508Sbde pp->onlinkflg = 1; 61815508Sbde pp->autoconfflg = 1; 61915508Sbde pp->origin = PREFIX_FROM_KERNEL; 62015508Sbde 62115508Sbde /* link into chain */ 62232054Sphk insque(pp, &rai->prefix); 62348160Sgreen 62448266Speter /* counter increment */ 62548266Speter rai->pfxs++; 62615508Sbde } 62715508Sbde 62815508Sbde freeifaddrs(ifap); 62915508Sbde} 63015508Sbde 63115508Sbdestatic void 63215508Sbdemakeentry(buf, len, id, string, add) 63315508Sbde char *buf; 63415508Sbde size_t len; 63515508Sbde int id; 63615508Sbde char *string; 63715508Sbde int add; 63815508Sbde{ 63915508Sbde char *ep = buf + len; 64015508Sbde 64115508Sbde strcpy(buf, string); 64215508Sbde if (add) { 64315508Sbde char *cp; 64415508Sbde 64515508Sbde cp = (char *)index(buf, '\0'); 64615508Sbde snprintf(cp, ep - cp, "%d", id); 64715508Sbde } 64815508Sbde} 64915508Sbde 65015508Sbde/* 65115508Sbde * Add a prefix to the list of specified interface and reconstruct 65215508Sbde * the outgoing packet. 65315508Sbde * The prefix must not be in the list. 65415508Sbde * XXX: other parameter of the prefix(e.g. lifetime) shoule be 65515508Sbde * able to be specified. 65615508Sbde */ 65715508Sbdestatic void 65815508Sbdeadd_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 65933690Sphk{ 66048160Sgreen struct prefix *prefix; 66133690Sphk u_char ntopbuf[INET6_ADDRSTRLEN]; 66233690Sphk 66333690Sphk if ((prefix = malloc(sizeof(*prefix))) == NULL) { 66432005Sphk syslog(LOG_ERR, "<%s> memory allocation failed", 66533929Sphk __FUNCTION__); 66615508Sbde return; /* XXX: error or exit? */ 66715508Sbde } 66815508Sbde memset(prefix, 0, sizeof(*prefix)); 66915508Sbde prefix->prefix = ipr->ipr_prefix.sin6_addr; 67023393Sbde prefix->prefixlen = ipr->ipr_plen; 67123393Sbde prefix->validlifetime = ipr->ipr_vltime; 67223393Sbde prefix->preflifetime = ipr->ipr_pltime; 67315508Sbde prefix->onlinkflg = ipr->ipr_raf_onlink; 67415508Sbde prefix->autoconfflg = ipr->ipr_raf_auto; 67515508Sbde prefix->origin = PREFIX_FROM_DYNAMIC; 67615508Sbde 67715508Sbde insque(prefix, &rai->prefix); 67815508Sbde 67933309Sbde syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 68015508Sbde __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 68166716Sjhb ntopbuf, INET6_ADDRSTRLEN), 68215508Sbde ipr->ipr_plen, rai->ifname); 68333309Sbde 68433309Sbde /* free the previous packet */ 68533309Sbde free(rai->ra_data); 68633309Sbde rai->ra_data = NULL; 68733309Sbde 68833309Sbde /* reconstruct the packet */ 68933309Sbde rai->pfxs++; 69066716Sjhb make_packet(rai); 69115508Sbde 69215508Sbde /* 6935291Sbde * reset the timer so that the new prefix will be advertised quickly. 69452669Siwasaki */ 69552669Siwasaki rai->initcounter = 0; 69652669Siwasaki ra_timer_update((void *)rai, &rai->timer->tm); 69752669Siwasaki rtadvd_set_timer(&rai->timer->tm, rai->timer); 69852669Siwasaki} 69952669Siwasaki 70052669Siwasaki/* 70152669Siwasaki * Delete a prefix to the list of specified interface and reconstruct 70252669Siwasaki * the outgoing packet. 70352669Siwasaki * The prefix must be in the list. 70452669Siwasaki */ 70566716Sjhbvoid 70652669Siwasakidelete_prefix(struct rainfo *rai, struct prefix *prefix) 70752669Siwasaki{ 70852669Siwasaki u_char ntopbuf[INET6_ADDRSTRLEN]; 70966716Sjhb 71052669Siwasaki remque(prefix); 71152669Siwasaki syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 71252669Siwasaki __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, 71333690Sphk ntopbuf, INET6_ADDRSTRLEN), 7145291Sbde prefix->prefixlen, rai->ifname); 7155291Sbde free(prefix); 7161390Ssos rai->pfxs--; 7178876Srgrimes make_packet(rai); 718798Swollman} 71915508Sbde 72015508Sbde/* 72132054Sphk * Try to get an in6_prefixreq contents for a prefix which matches 72232054Sphk * ipr->ipr_prefix and ipr->ipr_plen and belongs to 72332054Sphk * the interface whose name is ipr->ipr_name[]. 72432054Sphk */ 72532054Sphkstatic int 72615508Sbdeinit_prefix(struct in6_prefixreq *ipr) 72715508Sbde{ 72815508Sbde int s; 72916874Sbde 73015508Sbde if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 73115508Sbde syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, 73215508Sbde strerror(errno)); 73315508Sbde exit(1); 73415508Sbde } 73518288Sbde 73615508Sbde if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 73715508Sbde syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__, 73815508Sbde strerror(errno)); 73915508Sbde 74015508Sbde ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 74115508Sbde ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 74215508Sbde ipr->ipr_raf_onlink = 1; 74315508Sbde ipr->ipr_raf_auto = 1; 74415508Sbde /* omit other field initialization */ 74515508Sbde } 74615508Sbde else if (ipr->ipr_origin < PR_ORIG_RR) { 74715508Sbde u_char ntopbuf[INET6_ADDRSTRLEN]; 74816300Spst 74919173Sbde syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 75015508Sbde "lower than PR_ORIG_RR(router renumbering)." 75115508Sbde "This should not happen if I am router", __FUNCTION__, 75215508Sbde inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 75315508Sbde sizeof(ntopbuf)), ipr->ipr_origin); 75415508Sbde close(s); 75523393Sbde return 1; 75623393Sbde } 75723393Sbde 75823393Sbde close(s); 75932005Sphk return 0; 76015508Sbde} 76115508Sbde 76215508Sbdevoid 76340610Sphkmake_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 76458377Sphk{ 76515508Sbde struct in6_prefixreq ipr; 76632005Sphk 76732005Sphk memset(&ipr, 0, sizeof(ipr)); 76816300Spst if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 76919173Sbde syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 77032005Sphk "exist. This should not happen! %s", __FUNCTION__, 77132005Sphk ifindex, strerror(errno)); 77215508Sbde exit(1); 77315508Sbde } 77432054Sphk ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 77515508Sbde ipr.ipr_prefix.sin6_family = AF_INET6; 77615508Sbde ipr.ipr_prefix.sin6_addr = *addr; 77715508Sbde ipr.ipr_plen = plen; 77815508Sbde 77915508Sbde if (init_prefix(&ipr)) 78048160Sgreen return; /* init failed by some error */ 78148160Sgreen add_prefix(rai, &ipr); 78215508Sbde} 78348160Sgreen 78432054Sphkvoid 78523393Sbdemake_packet(struct rainfo *rainfo) 78633690Sphk{ 78716300Spst size_t packlen, lladdroptlen = 0; 78815508Sbde char *buf; 78934617Sphk struct nd_router_advert *ra; 79034617Sphk struct nd_opt_prefix_info *ndopt_pi; 79134617Sphk struct nd_opt_mtu *ndopt_mtu; 79234617Sphk#ifdef MIP6 79334617Sphk struct nd_opt_advinterval *ndopt_advint; 79434617Sphk struct nd_opt_homeagent_info *ndopt_hai; 79534617Sphk#endif 79634617Sphk struct nd_opt_route_info *ndopt_rti; 79734617Sphk struct prefix *pfx; 79834617Sphk struct rtinfo *rti; 79934617Sphk 80049186Smsmith /* calculate total length */ 80149186Smsmith packlen = sizeof(struct nd_router_advert); 80234617Sphk if (rainfo->advlinkopt) { 80334617Sphk if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 80434617Sphk syslog(LOG_INFO, 80534617Sphk "<%s> link-layer address option has" 80649186Smsmith " null length on %s." 80749186Smsmith " Treat as not included.", 80834617Sphk __FUNCTION__, rainfo->ifname); 80964031Sphk rainfo->advlinkopt = 0; 81064031Sphk } 81164031Sphk packlen += lladdroptlen; 81264031Sphk } 81364031Sphk if (rainfo->pfxs) 81464031Sphk packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 81534617Sphk if (rainfo->linkmtu) 81634617Sphk packlen += sizeof(struct nd_opt_mtu); 81747592Sphk#ifdef MIP6 81840610Sphk if (mobileip6 && rainfo->maxinterval) 81958377Sphk packlen += sizeof(struct nd_opt_advinterval); 82033690Sphk if (mobileip6 && rainfo->hatime) 82134617Sphk packlen += sizeof(struct nd_opt_homeagent_info); 82234617Sphk#endif 8234Srgrimes#ifdef ND_OPT_ROUTE_INFO 8244Srgrimes for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) 8252913Sache packlen += sizeof(struct nd_opt_route_info) + 82641787Smckay ((rti->prefixlen + 0x3f) >> 6) * 8; 82741787Smckay#endif 8282913Sache 8292913Sache /* allocate memory for the packet */ 8303185Ssos if ((buf = malloc(packlen)) == NULL) { 8314Srgrimes syslog(LOG_ERR, 8322913Sache "<%s> can't get enough memory for an RA packet", 8332913Sache __FUNCTION__); 8342913Sache exit(1); 8352913Sache } 83633690Sphk if (rainfo->ra_data) { 8374Srgrimes /* free the previous packet */ 83832850Sphk free(rainfo->ra_data); 83932850Sphk rainfo->ra_data = NULL; 84033690Sphk } 84133690Sphk rainfo->ra_data = buf; 84258377Sphk /* XXX: what if packlen > 576? */ 84332850Sphk rainfo->ra_datalen = packlen; 84432850Sphk 8451390Ssos /* 84641787Smckay * construct the packet 8479202Srgrimes */ 8482913Sache ra = (struct nd_router_advert *)buf; 8494Srgrimes ra->nd_ra_type = ND_ROUTER_ADVERT; 85041787Smckay ra->nd_ra_code = 0; 85141787Smckay ra->nd_ra_cksum = 0; 85255098Sbde ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); 85355098Sbde ra->nd_ra_flags_reserved = 0; /* just in case */ 85455098Sbde /* 85555098Sbde * XXX: the router preference field, which is a 2-bit field, should be 85655098Sbde * initialized before other fields. 8574Srgrimes */ 8582913Sache ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; 8593355Sache ra->nd_ra_flags_reserved |= 86041787Smckay rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 8613355Sache ra->nd_ra_flags_reserved |= 8623355Sache rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 8632913Sache#ifdef MIP6 8643355Sache ra->nd_ra_flags_reserved |= 8653355Sache rainfo->haflg ? ND_RA_FLAG_HA : 0; 86655098Sbde#endif 86755098Sbde ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 8682913Sache ra->nd_ra_reachable = htonl(rainfo->reachabletime); 86955098Sbde ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 87041787Smckay buf += sizeof(*ra); 87141787Smckay 87241787Smckay if (rainfo->advlinkopt) { 87341787Smckay lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 8742913Sache buf += lladdroptlen; 87541787Smckay } 8762913Sache 8772913Sache if (rainfo->linkmtu) { 87841787Smckay ndopt_mtu = (struct nd_opt_mtu *)buf; 8792913Sache ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 8802913Sache ndopt_mtu->nd_opt_mtu_len = 1; 8812913Sache ndopt_mtu->nd_opt_mtu_reserved = 0; 8822913Sache ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); 88341787Smckay buf += sizeof(struct nd_opt_mtu); 88441787Smckay } 8851390Ssos 88615054Sache#ifdef MIP6 8874Srgrimes if (mobileip6 && rainfo->maxinterval) { 88834961Sphk ndopt_advint = (struct nd_opt_advinterval *)buf; 88933690Sphk ndopt_advint->nd_opt_adv_type = ND_OPT_ADVINTERVAL; 89033690Sphk ndopt_advint->nd_opt_adv_len = 1; 89133690Sphk ndopt_advint->nd_opt_adv_reserved = 0; 89233690Sphk ndopt_advint->nd_opt_adv_interval = htonl(rainfo->maxinterval * 89358377Sphk 1000); 89433690Sphk buf += sizeof(struct nd_opt_advinterval); 89555098Sbde } 8962913Sache#endif 8972913Sache 8982913Sache#ifdef MIP6 89941787Smckay if (rainfo->hatime) { 90041787Smckay ndopt_hai = (struct nd_opt_homeagent_info *)buf; 9014Srgrimes ndopt_hai->nd_opt_hai_type = ND_OPT_HOMEAGENT_INFO; 9024Srgrimes ndopt_hai->nd_opt_hai_len = 1; 9034Srgrimes ndopt_hai->nd_opt_hai_reserved = 0; 90441787Smckay ndopt_hai->nd_opt_hai_preference = htons(rainfo->hapref); 9054Srgrimes ndopt_hai->nd_opt_hai_lifetime = htons(rainfo->hatime); 9064180Sbde buf += sizeof(struct nd_opt_homeagent_info); 9074180Sbde } 9084Srgrimes#endif 9092913Sache 91011872Sphk for (pfx = rainfo->prefix.next; 9114Srgrimes pfx != &rainfo->prefix; pfx = pfx->next) { 9123366Sache u_int32_t vltime, pltime; 9133366Sache struct timeval now; 9143366Sache 9152913Sache ndopt_pi = (struct nd_opt_prefix_info *)buf; 91634961Sphk ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 9172913Sache ndopt_pi->nd_opt_pi_len = 4; 9184Srgrimes ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 9195291Sbde ndopt_pi->nd_opt_pi_flags_reserved = 0; 9202913Sache if (pfx->onlinkflg) 9214Srgrimes ndopt_pi->nd_opt_pi_flags_reserved |= 92241787Smckay ND_OPT_PI_FLAG_ONLINK; 9231390Ssos if (pfx->autoconfflg) 92415054Sache ndopt_pi->nd_opt_pi_flags_reserved |= 9252913Sache ND_OPT_PI_FLAG_AUTO; 92613445Sphk#ifdef MIP6 92713445Sphk if (pfx->routeraddr) 92813445Sphk ndopt_pi->nd_opt_pi_flags_reserved |= 9292913Sache ND_OPT_PI_FLAG_ROUTER; 93041787Smckay#endif 9312913Sache if (pfx->vltimeexpire || pfx->pltimeexpire) 93213350Sache gettimeofday(&now, NULL); 93313350Sache if (pfx->vltimeexpire == 0) 93413350Sache vltime = pfx->validlifetime; 93513350Sache else 9362913Sache vltime = (pfx->vltimeexpire > now.tv_sec) ? 9372913Sache pfx->vltimeexpire - now.tv_sec : 0; 93813453Sache if (pfx->pltimeexpire == 0) 93913350Sache pltime = pfx->preflifetime; 94013445Sphk else 9413355Sache pltime = (pfx->pltimeexpire > now.tv_sec) ? 94213402Sbde pfx->pltimeexpire - now.tv_sec : 0; 94313402Sbde if (vltime < pltime) { 9442913Sache /* 94513402Sbde * this can happen if vltime is decrement but pltime 94613402Sbde * is not. 94713402Sbde */ 94813402Sbde pltime = vltime; 94913402Sbde } 95013402Sbde ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 95113402Sbde ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 95213402Sbde ndopt_pi->nd_opt_pi_reserved2 = 0; 95313445Sphk ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 95413445Sphk 9552913Sache buf += sizeof(struct nd_opt_prefix_info); 9565291Sbde } 95715345Snate 9584Srgrimes#ifdef ND_OPT_ROUTE_INFO 9594Srgrimes for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { 96027560Sfsmp u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; 9614Srgrimes 9625291Sbde ndopt_rti = (struct nd_opt_route_info *)buf; 9634Srgrimes ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 9645291Sbde ndopt_rti->nd_opt_rti_len = 1 + psize; 9655291Sbde ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; 9664Srgrimes ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; 9675291Sbde ndopt_rti->nd_opt_rti_lifetime = rti->ltime; 96826949Sfsmp memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); 96966716Sjhb buf += sizeof(struct nd_opt_route_info) + psize * 8; 97066716Sjhb } 97125164Speter#endif 9724Srgrimes 97315345Snate return; 97415345Snate} 97515345Snate 97615345Snatestatic int 97715345Snategetinet6sysctl(int code) 97815345Snate{ 97915345Snate int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 98015345Snate int value; 98115345Snate size_t size; 98215345Snate 98315345Snate mib[3] = code; 98415345Snate size = sizeof(value); 98515345Snate if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 9864Srgrimes < 0) { 9875291Sbde syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 98826949Sfsmp __FUNCTION__, code, 98927563Sfsmp strerror(errno)); 99038888Stegge return(-1); 99134571Stegge } 99234571Stegge else 99334571Stegge return(value); 99434571Stegge} 99534571Stegge