config.c revision 118968
171333Sitojun/* $FreeBSD: head/usr.sbin/rtadvd/config.c 118968 2003-08-15 19:13:53Z ume $ */ 2118968Sume/* $KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $ */ 362656Skris 455505Sshin/* 555505Sshin * Copyright (C) 1998 WIDE Project. 655505Sshin * All rights reserved. 762656Skris * 855505Sshin * Redistribution and use in source and binary forms, with or without 955505Sshin * modification, are permitted provided that the following conditions 1055505Sshin * are met: 1155505Sshin * 1. Redistributions of source code must retain the above copyright 1255505Sshin * notice, this list of conditions and the following disclaimer. 1355505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1455505Sshin * notice, this list of conditions and the following disclaimer in the 1555505Sshin * documentation and/or other materials provided with the distribution. 1655505Sshin * 3. Neither the name of the project nor the names of its contributors 1755505Sshin * may be used to endorse or promote products derived from this software 1855505Sshin * without specific prior written permission. 1962656Skris * 2055505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2155505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2455505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2555505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2655505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2755505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2855505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2955505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3055505Sshin * SUCH DAMAGE. 3155505Sshin */ 3255505Sshin 3355505Sshin#include <sys/param.h> 3455505Sshin#include <sys/ioctl.h> 3555505Sshin#include <sys/socket.h> 3655505Sshin#include <sys/time.h> 3778064Sume#include <sys/sysctl.h> 3855505Sshin 3955505Sshin#include <net/if.h> 4055505Sshin#include <net/if_var.h> 4155505Sshin#include <net/route.h> 4255505Sshin#include <net/if_dl.h> 4355505Sshin 4455505Sshin#include <netinet/in.h> 4555505Sshin#include <netinet/in_var.h> 4657120Sshin#include <netinet/ip6.h> 4755505Sshin#include <netinet6/ip6_var.h> 4857120Sshin#include <netinet/icmp6.h> 4955505Sshin 5055505Sshin#include <arpa/inet.h> 5155505Sshin 5255505Sshin#include <stdio.h> 5355505Sshin#include <syslog.h> 5455505Sshin#include <errno.h> 5555505Sshin#include <string.h> 5655505Sshin#include <stdlib.h> 5755505Sshin#include <unistd.h> 5878064Sume#include <ifaddrs.h> 5955505Sshin 6055505Sshin#include "rtadvd.h" 6155505Sshin#include "advcap.h" 6255505Sshin#include "timer.h" 6355505Sshin#include "if.h" 6455505Sshin#include "config.h" 6555505Sshin 6698172Sumestatic time_t prefix_timo = (60 * 120); /* 2 hours. 6798172Sume * XXX: should be configurable. */ 6898172Sumeextern struct rainfo *ralist; 6998172Sume 7098172Sumestatic struct rtadvd_timer *prefix_timeout __P((void *)); 71118968Sumestatic void makeentry __P((char *, size_t, int, char *)); 7278064Sumestatic int getinet6sysctl __P((int)); 7355505Sshin 7455505Sshinvoid 7555505Sshingetconfig(intface) 7655505Sshin char *intface; 7755505Sshin{ 78118968Sume int stat, i; 7955505Sshin char tbuf[BUFSIZ]; 8055505Sshin struct rainfo *tmp; 8155505Sshin long val; 82118784Sume int64_t val64; 8355505Sshin char buf[BUFSIZ]; 8455505Sshin char *bp = buf; 85118968Sume char *addr, *flagstr; 8678064Sume static int forwarding = -1; 8755505Sshin 8862656Skris#define MUSTHAVE(var, cap) \ 8962656Skris do { \ 90118784Sume int64_t t; \ 9155505Sshin if ((t = agetnum(cap)) < 0) { \ 9255505Sshin fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 9355505Sshin cap, intface); \ 9455505Sshin exit(1); \ 9555505Sshin } \ 9655505Sshin var = t; \ 9762656Skris } while (0) 9862656Skris#define MAYHAVE(var, cap, def) \ 9962656Skris do { \ 10055505Sshin if ((var = agetnum(cap)) < 0) \ 10155505Sshin var = def; \ 10262656Skris } while (0) 10355505Sshin 10455505Sshin if ((stat = agetent(tbuf, intface)) <= 0) { 10555505Sshin memset(tbuf, 0, sizeof(tbuf)); 10655505Sshin syslog(LOG_INFO, 10755505Sshin "<%s> %s isn't defined in the configuration file" 10855505Sshin " or the configuration file doesn't exist." 10955505Sshin " Treat it as default", 110118660Sume __func__, intface); 11155505Sshin } 11255505Sshin 11355505Sshin tmp = (struct rainfo *)malloc(sizeof(*ralist)); 114118831Sume if (tmp == NULL) { 115118831Sume syslog(LOG_INFO, "<%s> %s: can't allocate enough memory", 116118831Sume __func__, intface); 117118831Sume exit(1); 118118831Sume } 11955505Sshin memset(tmp, 0, sizeof(*tmp)); 12055505Sshin tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; 121118968Sume#ifdef ROUTEINFO 12278064Sume tmp->route.next = tmp->route.prev = &tmp->route; 123118968Sume#endif 12455505Sshin 12578064Sume /* check if we are allowed to forward packets (if not determined) */ 12678064Sume if (forwarding < 0) { 12778064Sume if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) 12878064Sume exit(1); 12978064Sume } 13078064Sume 13155505Sshin /* get interface information */ 13255505Sshin if (agetflag("nolladdr")) 13355505Sshin tmp->advlinkopt = 0; 13455505Sshin else 13555505Sshin tmp->advlinkopt = 1; 13655505Sshin if (tmp->advlinkopt) { 13755505Sshin if ((tmp->sdl = if_nametosdl(intface)) == NULL) { 13855505Sshin syslog(LOG_ERR, 13955505Sshin "<%s> can't get information of %s", 140118660Sume __func__, intface); 14155505Sshin exit(1); 14255505Sshin } 14355505Sshin tmp->ifindex = tmp->sdl->sdl_index; 14455505Sshin } else 14555505Sshin tmp->ifindex = if_nametoindex(intface); 14655505Sshin strncpy(tmp->ifname, intface, sizeof(tmp->ifname)); 14755505Sshin if ((tmp->phymtu = if_getmtu(intface)) == 0) { 14855505Sshin tmp->phymtu = IPV6_MMTU; 14955505Sshin syslog(LOG_WARNING, 15055505Sshin "<%s> can't get interface mtu of %s. Treat as %d", 151118660Sume __func__, intface, IPV6_MMTU); 15255505Sshin } 15355505Sshin 15455505Sshin /* 15555505Sshin * set router configuration variables. 15655505Sshin */ 15755505Sshin MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 15855505Sshin if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 15955505Sshin syslog(LOG_ERR, 160118968Sume "<%s> maxinterval (%ld) on %s is invalid " 161118968Sume "(must be between %u and %u)", __func__, val, 162118968Sume intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 16355505Sshin exit(1); 16455505Sshin } 16555505Sshin tmp->maxinterval = (u_int)val; 16655505Sshin MAYHAVE(val, "mininterval", tmp->maxinterval/3); 16755505Sshin if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { 16855505Sshin syslog(LOG_ERR, 169118968Sume "<%s> mininterval (%ld) on %s is invalid " 170118968Sume "(must be between %d and %d)", 171118968Sume __func__, val, intface, MIN_MININTERVAL, 17255505Sshin (tmp->maxinterval * 3) / 4); 17355505Sshin exit(1); 17455505Sshin } 17555505Sshin tmp->mininterval = (u_int)val; 17655505Sshin 17755505Sshin MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 17855505Sshin tmp->hoplimit = val & 0xff; 17955505Sshin 180118968Sume if ((flagstr = (char *)agetstr("raflags", &bp))) { 181118968Sume val = 0; 182118968Sume if (strchr(flagstr, 'm')) 183118968Sume val |= ND_RA_FLAG_MANAGED; 184118968Sume if (strchr(flagstr, 'o')) 185118968Sume val |= ND_RA_FLAG_OTHER; 186118968Sume if (strchr(flagstr, 'h')) 187118968Sume val |= ND_RA_FLAG_RTPREF_HIGH; 188118968Sume if (strchr(flagstr, 'l')) { 189118968Sume if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 190118968Sume syslog(LOG_ERR, "<%s> the \'h\' and \'l\'" 191118968Sume " router flags are exclusive", __func__); 192118968Sume exit(1); 193118968Sume } 194118968Sume val |= ND_RA_FLAG_RTPREF_LOW; 195118968Sume } 196118968Sume } else { 197118968Sume MAYHAVE(val, "raflags", 0); 198118968Sume } 19978064Sume tmp->managedflg = val & ND_RA_FLAG_MANAGED; 20055505Sshin tmp->otherflg = val & ND_RA_FLAG_OTHER; 20178064Sume#ifndef ND_RA_FLAG_RTPREF_MASK 20278064Sume#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 20378064Sume#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 20478064Sume#endif 20578064Sume tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 20678064Sume if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { 207118968Sume syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s", 208118968Sume __func__, tmp->rtpref, intface); 20978064Sume exit(1); 21078064Sume } 21155505Sshin 21255505Sshin MAYHAVE(val, "rltime", tmp->maxinterval * 3); 21355505Sshin if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { 21455505Sshin syslog(LOG_ERR, 215118968Sume "<%s> router lifetime (%ld) on %s is invalid " 216118968Sume "(must be 0 or between %d and %d)", 217118968Sume __func__, val, intface, 218118968Sume tmp->maxinterval, 219118968Sume MAXROUTERLIFETIME); 22055505Sshin exit(1); 22155505Sshin } 22278064Sume /* 22378064Sume * Basically, hosts MUST NOT send Router Advertisement messages at any 22478064Sume * time (RFC 2461, Section 6.2.3). However, it would sometimes be 22578064Sume * useful to allow hosts to advertise some parameters such as prefix 22678064Sume * information and link MTU. Thus, we allow hosts to invoke rtadvd 22778064Sume * only when router lifetime (on every advertising interface) is 22878064Sume * explicitly set zero. (see also the above section) 22978064Sume */ 23078064Sume if (val && forwarding == 0) { 231118968Sume syslog(LOG_ERR, 23278064Sume "<%s> non zero router lifetime is specified for %s, " 233118968Sume "which must not be allowed for hosts. you must " 234118968Sume "change router lifetime or enable IPv6 forwarding.", 235118660Sume __func__, intface); 23678064Sume exit(1); 23778064Sume } 23855505Sshin tmp->lifetime = val & 0xffff; 23955505Sshin 24055505Sshin MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 241118968Sume if (val < 0 || val > MAXREACHABLETIME) { 24255505Sshin syslog(LOG_ERR, 243118968Sume "<%s> reachable time (%ld) on %s is invalid " 244118968Sume "(must be no greater than %d)", 245118968Sume __func__, val, intface, MAXREACHABLETIME); 24655505Sshin exit(1); 24755505Sshin } 24855505Sshin tmp->reachabletime = (u_int32_t)val; 24955505Sshin 25078064Sume MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 25178064Sume if (val64 < 0 || val64 > 0xffffffff) { 252118968Sume syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range", 253118968Sume __func__, (long long)val64, intface); 25455505Sshin exit(1); 25555505Sshin } 25678064Sume tmp->retranstimer = (u_int32_t)val64; 25755505Sshin 258118968Sume if (agetnum("hapref") != -1 || agetnum("hatime") != -1) { 25978064Sume syslog(LOG_ERR, 26078064Sume "<%s> mobile-ip6 configuration not supported", 261118660Sume __func__); 26278064Sume exit(1); 26378064Sume } 26455505Sshin /* prefix information */ 26578064Sume 26678064Sume /* 267118664Sume * This is an implementation specific parameter to consider 26878064Sume * link propagation delays and poorly synchronized clocks when 26978064Sume * checking consistency of advertised lifetimes. 27078064Sume */ 27178064Sume MAYHAVE(val, "clockskew", 0); 27278064Sume tmp->clockskew = val; 27378064Sume 274118968Sume tmp->pfxs = 0; 275118968Sume for (i = -1; i < MAXPREFIX; i++) { 276118968Sume struct prefix *pfx; 277118968Sume char entbuf[256]; 278118968Sume 279118968Sume makeentry(entbuf, sizeof(entbuf), i, "addr"); 280118968Sume addr = (char *)agetstr(entbuf, &bp); 281118968Sume if (addr == NULL) 282118968Sume continue; 283118968Sume 284118968Sume /* allocate memory to store prefix information */ 285118968Sume if ((pfx = malloc(sizeof(struct prefix))) == NULL) { 28655505Sshin syslog(LOG_ERR, 287118968Sume "<%s> can't allocate enough memory", 288118968Sume __func__); 28955505Sshin exit(1); 29055505Sshin } 291118968Sume memset(pfx, 0, sizeof(*pfx)); 29255505Sshin 293118968Sume /* link into chain */ 294118968Sume insque(pfx, &tmp->prefix); 295118968Sume tmp->pfxs++; 296118968Sume pfx->rainfo = tmp; 29771437Sume 298118968Sume pfx->origin = PREFIX_FROM_CONFIG; 29955505Sshin 300118968Sume if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) { 301118968Sume syslog(LOG_ERR, 302118968Sume "<%s> inet_pton failed for %s", 303118968Sume __func__, addr); 304118968Sume exit(1); 305118968Sume } 306118968Sume if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { 307118968Sume syslog(LOG_ERR, 308118968Sume "<%s> multicast prefix (%s) must " 309118968Sume "not be advertised on %s", 310118968Sume __func__, addr, intface); 311118968Sume exit(1); 312118968Sume } 313118968Sume if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) 314118968Sume syslog(LOG_NOTICE, 315118968Sume "<%s> link-local prefix (%s) will be" 316118968Sume " advertised on %s", 317118968Sume __func__, addr, intface); 31862656Skris 319118968Sume makeentry(entbuf, sizeof(entbuf), i, "prefixlen"); 320118968Sume MAYHAVE(val, entbuf, 64); 321118968Sume if (val < 0 || val > 128) { 322118968Sume syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s " 323118968Sume "on %s out of range", 324118968Sume __func__, val, addr, intface); 325118968Sume exit(1); 326118968Sume } 327118968Sume pfx->prefixlen = (int)val; 32855505Sshin 329118968Sume makeentry(entbuf, sizeof(entbuf), i, "pinfoflags"); 330118968Sume if ((flagstr = (char *)agetstr(entbuf, &bp))) { 331118968Sume val = 0; 332118968Sume if (strchr(flagstr, 'l')) 333118968Sume val |= ND_OPT_PI_FLAG_ONLINK; 334118968Sume if (strchr(flagstr, 'a')) 335118968Sume val |= ND_OPT_PI_FLAG_AUTO; 336118968Sume } else { 337118968Sume MAYHAVE(val, entbuf, 338118968Sume (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 339118968Sume } 340118968Sume pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 341118968Sume pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 34255505Sshin 343118968Sume makeentry(entbuf, sizeof(entbuf), i, "vltime"); 344118968Sume MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 345118968Sume if (val64 < 0 || val64 > 0xffffffff) { 346118968Sume syslog(LOG_ERR, "<%s> vltime (%lld) for " 347118968Sume "%s/%d on %s is out of range", 348118968Sume __func__, (long long)val64, 349118968Sume addr, pfx->prefixlen, intface); 350118968Sume exit(1); 351118968Sume } 352118968Sume pfx->validlifetime = (u_int32_t)val64; 35355505Sshin 354118968Sume makeentry(entbuf, sizeof(entbuf), i, "vltimedecr"); 355118968Sume if (agetflag(entbuf)) { 356118968Sume struct timeval now; 357118968Sume gettimeofday(&now, 0); 358118968Sume pfx->vltimeexpire = 359118968Sume now.tv_sec + pfx->validlifetime; 360118968Sume } 36178064Sume 362118968Sume makeentry(entbuf, sizeof(entbuf), i, "pltime"); 363118968Sume MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 364118968Sume if (val64 < 0 || val64 > 0xffffffff) { 365118968Sume syslog(LOG_ERR, 366118968Sume "<%s> pltime (%lld) for %s/%d on %s " 367118968Sume "is out of range", 368118968Sume __func__, (long long)val64, 369118968Sume addr, pfx->prefixlen, intface); 370118968Sume exit(1); 371118968Sume } 372118968Sume pfx->preflifetime = (u_int32_t)val64; 37355505Sshin 374118968Sume makeentry(entbuf, sizeof(entbuf), i, "pltimedecr"); 375118968Sume if (agetflag(entbuf)) { 376118968Sume struct timeval now; 377118968Sume gettimeofday(&now, 0); 378118968Sume pfx->pltimeexpire = 379118968Sume now.tv_sec + pfx->preflifetime; 38055505Sshin } 38155505Sshin } 382118968Sume if (tmp->pfxs == 0) 383118968Sume get_prefix(tmp); 38455505Sshin 38555505Sshin MAYHAVE(val, "mtu", 0); 38655505Sshin if (val < 0 || val > 0xffffffff) { 38755505Sshin syslog(LOG_ERR, 388118968Sume "<%s> mtu (%ld) on %s out of range", 389118968Sume __func__, val, intface); 39055505Sshin exit(1); 39155505Sshin } 39255505Sshin tmp->linkmtu = (u_int32_t)val; 39355505Sshin if (tmp->linkmtu == 0) { 39455505Sshin char *mtustr; 39555505Sshin 39655505Sshin if ((mtustr = (char *)agetstr("mtu", &bp)) && 39755505Sshin strcmp(mtustr, "auto") == 0) 39855505Sshin tmp->linkmtu = tmp->phymtu; 39955505Sshin } 40055505Sshin else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { 40155505Sshin syslog(LOG_ERR, 402118968Sume "<%s> advertised link mtu (%lu) on %s is invalid (must " 403118968Sume "be between least MTU (%d) and physical link MTU (%d)", 404118968Sume __func__, (unsigned long)tmp->linkmtu, intface, 405118968Sume IPV6_MMTU, tmp->phymtu); 40655505Sshin exit(1); 40755505Sshin } 40855505Sshin 40978064Sume /* route information */ 410118968Sume#ifdef ROUTEINFO 411118968Sume tmp->routes = 0; 412118968Sume for (i = -1; i < MAXROUTE; i++) { 41378064Sume struct rtinfo *rti; 414118968Sume char entbuf[256], oentbuf[256]; 41578064Sume 416118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtprefix"); 417118968Sume addr = (char *)agetstr(entbuf, &bp); 418118968Sume if (addr == NULL) { 419118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix"); 420118968Sume addr = (char *)agetstr(oentbuf, &bp); 421118968Sume if (addr) { 422118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 423118968Sume oentbuf, entbuf); 424118968Sume } 425118968Sume } 426118968Sume if (addr == NULL) 427118968Sume continue; 428118968Sume 42978064Sume /* allocate memory to store prefix information */ 43078064Sume if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { 43178064Sume syslog(LOG_ERR, 43278064Sume "<%s> can't allocate enough memory", 433118660Sume __func__); 43478064Sume exit(1); 43578064Sume } 43678064Sume memset(rti, 0, sizeof(*rti)); 43778064Sume 43878064Sume /* link into chain */ 43978064Sume insque(rti, &tmp->route); 440118968Sume tmp->routes++; 44178064Sume 44278064Sume if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { 443118968Sume syslog(LOG_ERR, "<%s> inet_pton failed for %s", 444118660Sume __func__, addr); 44578064Sume exit(1); 44678064Sume } 44778064Sume#if 0 44878064Sume /* 44978064Sume * XXX: currently there's no restriction in route information 450118968Sume * prefix according to 451118968Sume * draft-ietf-ipngwg-router-selection-00.txt. 452118968Sume * However, I think the similar restriction be necessary. 45378064Sume */ 45478064Sume MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 45578064Sume if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 45678064Sume syslog(LOG_ERR, 45778064Sume "<%s> multicast route (%s) must " 458118968Sume "not be advertised on %s", 459118660Sume __func__, addr, intface); 46078064Sume exit(1); 46178064Sume } 46278064Sume if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 46378064Sume syslog(LOG_NOTICE, 464118968Sume "<%s> link-local route (%s) will " 465118968Sume "be advertised on %s", 466118660Sume __func__, addr, intface); 46778064Sume exit(1); 46878064Sume } 46978064Sume#endif 470118968Sume 471118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtplen"); 472118968Sume /* XXX: 256 is a magic number for compatibility check. */ 473118968Sume MAYHAVE(val, entbuf, 256); 474118968Sume if (val == 256) { 475118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen"); 476118968Sume MAYHAVE(val, oentbuf, 256); 477118968Sume if (val != 256) { 478118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 479118968Sume oentbuf, entbuf); 480118968Sume } else 481118968Sume val = 64; 482118968Sume } 483118968Sume if (val < 0 || val > 128) { 484118968Sume syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s " 485118968Sume "out of range", 486118968Sume __func__, val, addr, intface); 487118968Sume exit(1); 488118968Sume } 489118968Sume rti->prefixlen = (int)val; 490118968Sume 491118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtflags"); 492118968Sume if ((flagstr = (char *)agetstr(entbuf, &bp))) { 493118968Sume val = 0; 494118968Sume if (strchr(flagstr, 'h')) 495118968Sume val |= ND_RA_FLAG_RTPREF_HIGH; 496118968Sume if (strchr(flagstr, 'l')) { 497118968Sume if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 498118968Sume syslog(LOG_ERR, 499118968Sume "<%s> the \'h\' and \'l\' route" 500118968Sume " preferences are exclusive", 501118968Sume __func__); 502118968Sume exit(1); 503118968Sume } 504118968Sume val |= ND_RA_FLAG_RTPREF_LOW; 505118968Sume } 506118968Sume } else 507118968Sume MAYHAVE(val, entbuf, 256); /* XXX */ 508118968Sume if (val == 256) { 509118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags"); 510118968Sume MAYHAVE(val, oentbuf, 256); 511118968Sume if (val != 256) { 512118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 513118968Sume oentbuf, entbuf); 514118968Sume } else 515118968Sume val = 0; 516118968Sume } 517118968Sume rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 518118968Sume if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { 519118968Sume syslog(LOG_ERR, "<%s> invalid route preference (%02x) " 520118968Sume "for %s/%d on %s", 521118968Sume __func__, rti->rtpref, addr, 522118968Sume rti->prefixlen, intface); 523118968Sume exit(1); 524118968Sume } 525118968Sume 526118968Sume /* 527118968Sume * Since the spec does not a default value, we should make 528118968Sume * this entry mandatory. However, FreeBSD 4.4 has shipped 529118968Sume * with this field being optional, we use the router lifetime 530118968Sume * as an ad-hoc default value with a warning message. 531118968Sume */ 532118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtltime"); 533118968Sume MAYHAVE(val64, entbuf, -1); 534118968Sume if (val64 == -1) { 535118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime"); 536118968Sume MAYHAVE(val64, oentbuf, -1); 537118968Sume if (val64 != -1) { 538118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 539118968Sume oentbuf, entbuf); 540118968Sume } else { 541118968Sume fprintf(stderr, "%s should be specified " 542118968Sume "for interface %s.\n", 543118968Sume entbuf, intface); 544118968Sume val64 = tmp->lifetime; 545118968Sume } 546118968Sume } 547118968Sume if (val64 < 0 || val64 > 0xffffffff) { 548118968Sume syslog(LOG_ERR, "<%s> route lifetime (%lld) for " 549118968Sume "%s/%d on %s out of range", __func__, 550118968Sume (long long)val64, addr, rti->prefixlen, intface); 551118968Sume exit(1); 552118968Sume } 553118968Sume rti->ltime = (u_int32_t)val64; 55478064Sume } 555118968Sume#endif 55678064Sume 55755505Sshin /* okey */ 55855505Sshin tmp->next = ralist; 55955505Sshin ralist = tmp; 56055505Sshin 56155505Sshin /* construct the sending packet */ 56255505Sshin make_packet(tmp); 56355505Sshin 56455505Sshin /* set timer */ 56555505Sshin tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 56655505Sshin tmp, tmp); 56755505Sshin ra_timer_update((void *)tmp, &tmp->timer->tm); 56855505Sshin rtadvd_set_timer(&tmp->timer->tm, tmp->timer); 56955505Sshin} 57055505Sshin 571118968Sumevoid 57255505Sshinget_prefix(struct rainfo *rai) 57355505Sshin{ 57478064Sume struct ifaddrs *ifap, *ifa; 57578064Sume struct prefix *pp; 57678064Sume struct in6_addr *a; 57778064Sume u_char *p, *ep, *m, *lim; 57855505Sshin u_char ntopbuf[INET6_ADDRSTRLEN]; 57955505Sshin 58078064Sume if (getifaddrs(&ifap) < 0) { 58155505Sshin syslog(LOG_ERR, 58278064Sume "<%s> can't get interface addresses", 583118660Sume __func__); 58455505Sshin exit(1); 58555505Sshin } 586118664Sume 58778064Sume for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 58897719Sume int plen; 58997719Sume 59078064Sume if (strcmp(ifa->ifa_name, rai->ifname) != 0) 59178064Sume continue; 59278064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 59378064Sume continue; 59478064Sume a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 59578064Sume if (IN6_IS_ADDR_LINKLOCAL(a)) 59678064Sume continue; 59797719Sume /* get prefix length */ 59897719Sume m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 59997719Sume lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 60097719Sume plen = prefixlen(m, lim); 601118968Sume if (plen <= 0 || plen > 128) { 60297719Sume syslog(LOG_ERR, "<%s> failed to get prefixlen " 60397719Sume "or prefix is invalid", 604118660Sume __func__); 60597719Sume exit(1); 60697719Sume } 607118968Sume if (plen == 128) /* XXX */ 608118968Sume continue; 60997719Sume if (find_prefix(rai, a, plen)) { 61097719Sume /* ignore a duplicated prefix. */ 61197719Sume continue; 61297719Sume } 61397719Sume 61455505Sshin /* allocate memory to store prefix info. */ 61555505Sshin if ((pp = malloc(sizeof(*pp))) == NULL) { 61655505Sshin syslog(LOG_ERR, 61755505Sshin "<%s> can't get allocate buffer for prefix", 618118660Sume __func__); 61955505Sshin exit(1); 62055505Sshin } 62155505Sshin memset(pp, 0, sizeof(*pp)); 62255505Sshin 62378064Sume /* set prefix, sweep bits outside of prefixlen */ 62497719Sume pp->prefixlen = plen; 62578064Sume memcpy(&pp->prefix, a, sizeof(*a)); 62678064Sume p = (u_char *)&pp->prefix; 62778064Sume ep = (u_char *)(&pp->prefix + 1); 62878064Sume while (m < lim) 62978064Sume *p++ &= *m++; 63078064Sume while (p < ep) 63178064Sume *p++ = 0x00; 63278064Sume if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, 63378064Sume sizeof(ntopbuf))) { 634118660Sume syslog(LOG_ERR, "<%s> inet_ntop failed", __func__); 63578064Sume exit(1); 63678064Sume } 63755505Sshin syslog(LOG_DEBUG, 63855505Sshin "<%s> add %s/%d to prefix list on %s", 639118660Sume __func__, ntopbuf, pp->prefixlen, rai->ifname); 64055505Sshin 64155505Sshin /* set other fields with protocol defaults */ 64255505Sshin pp->validlifetime = DEF_ADVVALIDLIFETIME; 64355505Sshin pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 64455505Sshin pp->onlinkflg = 1; 64555505Sshin pp->autoconfflg = 1; 64662656Skris pp->origin = PREFIX_FROM_KERNEL; 647118968Sume pp->rainfo = rai; 64855505Sshin 64955505Sshin /* link into chain */ 65055505Sshin insque(pp, &rai->prefix); 65155505Sshin 65255505Sshin /* counter increment */ 65355505Sshin rai->pfxs++; 65455505Sshin } 65555505Sshin 65678064Sume freeifaddrs(ifap); 65755505Sshin} 65855505Sshin 65955505Sshinstatic void 660118968Sumemakeentry(buf, len, id, string) 66197709Sume char *buf; 66297709Sume size_t len; 66397709Sume int id; 66497709Sume char *string; 66555505Sshin{ 66697709Sume 667118968Sume if (id < 0) 668118968Sume strlcpy(buf, string, len); 669118968Sume else 670118968Sume snprintf(buf, len, "%s%d", string, id); 67155505Sshin} 67255505Sshin 67355505Sshin/* 67455505Sshin * Add a prefix to the list of specified interface and reconstruct 67555505Sshin * the outgoing packet. 67655505Sshin * The prefix must not be in the list. 677118968Sume * XXX: other parameters of the prefix (e.g. lifetime) shoule be 67855505Sshin * able to be specified. 67955505Sshin */ 68055505Sshinstatic void 68155505Sshinadd_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 68255505Sshin{ 68355505Sshin struct prefix *prefix; 68455505Sshin u_char ntopbuf[INET6_ADDRSTRLEN]; 68555505Sshin 68655505Sshin if ((prefix = malloc(sizeof(*prefix))) == NULL) { 68755505Sshin syslog(LOG_ERR, "<%s> memory allocation failed", 688118660Sume __func__); 68955505Sshin return; /* XXX: error or exit? */ 69055505Sshin } 69178064Sume memset(prefix, 0, sizeof(*prefix)); 69255505Sshin prefix->prefix = ipr->ipr_prefix.sin6_addr; 69355505Sshin prefix->prefixlen = ipr->ipr_plen; 69455505Sshin prefix->validlifetime = ipr->ipr_vltime; 69555505Sshin prefix->preflifetime = ipr->ipr_pltime; 69655505Sshin prefix->onlinkflg = ipr->ipr_raf_onlink; 69755505Sshin prefix->autoconfflg = ipr->ipr_raf_auto; 69862656Skris prefix->origin = PREFIX_FROM_DYNAMIC; 69955505Sshin 70055505Sshin insque(prefix, &rai->prefix); 70198172Sume prefix->rainfo = rai; 70255505Sshin 70355505Sshin syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 704118660Sume __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 70555505Sshin ntopbuf, INET6_ADDRSTRLEN), 70655505Sshin ipr->ipr_plen, rai->ifname); 70755505Sshin 70855505Sshin /* free the previous packet */ 70955505Sshin free(rai->ra_data); 71078064Sume rai->ra_data = NULL; 71155505Sshin 71255505Sshin /* reconstruct the packet */ 71355505Sshin rai->pfxs++; 71455505Sshin make_packet(rai); 71555505Sshin} 71655505Sshin 71755505Sshin/* 71855505Sshin * Delete a prefix to the list of specified interface and reconstruct 71955505Sshin * the outgoing packet. 72062656Skris * The prefix must be in the list. 72155505Sshin */ 72255505Sshinvoid 72398172Sumedelete_prefix(struct prefix *prefix) 72455505Sshin{ 72555505Sshin u_char ntopbuf[INET6_ADDRSTRLEN]; 72698172Sume struct rainfo *rai = prefix->rainfo; 72755505Sshin 72855505Sshin remque(prefix); 72955505Sshin syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 730118660Sume __func__, inet_ntop(AF_INET6, &prefix->prefix, 73155505Sshin ntopbuf, INET6_ADDRSTRLEN), 73255505Sshin prefix->prefixlen, rai->ifname); 73398172Sume if (prefix->timer) 73498172Sume rtadvd_remove_timer(&prefix->timer); 73555505Sshin free(prefix); 73655505Sshin rai->pfxs--; 73755505Sshin} 73855505Sshin 73998172Sumevoid 74098172Sumeinvalidate_prefix(struct prefix *prefix) 74198172Sume{ 74298172Sume u_char ntopbuf[INET6_ADDRSTRLEN]; 74398172Sume struct timeval timo; 74498172Sume struct rainfo *rai = prefix->rainfo; 74598172Sume 74698172Sume if (prefix->timer) { /* sanity check */ 74798172Sume syslog(LOG_ERR, 74898172Sume "<%s> assumption failure: timer already exists", 749118660Sume __func__); 75098172Sume exit(1); 75198172Sume } 75298172Sume 75398172Sume syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " 754118660Sume "will expire in %ld seconds", __func__, 75598172Sume inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), 75698172Sume prefix->prefixlen, rai->ifname, (long)prefix_timo); 75798172Sume 75898172Sume /* set the expiration timer */ 75998172Sume prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL); 76098172Sume if (prefix->timer == NULL) { 76198172Sume syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. " 762118660Sume "remove the prefix", __func__); 76398172Sume delete_prefix(prefix); 76498172Sume } 76598172Sume timo.tv_sec = prefix_timo; 76698172Sume timo.tv_usec = 0; 76798172Sume rtadvd_set_timer(&timo, prefix->timer); 76898172Sume} 76998172Sume 77098172Sumestatic struct rtadvd_timer * 77198172Sumeprefix_timeout(void *arg) 77298172Sume{ 77398172Sume struct prefix *prefix = (struct prefix *)arg; 77498172Sume 77598172Sume delete_prefix(prefix); 77698172Sume 77798172Sume return(NULL); 77898172Sume} 77998172Sume 78098172Sumevoid 78198172Sumeupdate_prefix(struct prefix * prefix) 78298172Sume{ 78398172Sume u_char ntopbuf[INET6_ADDRSTRLEN]; 78498172Sume struct rainfo *rai = prefix->rainfo; 78598172Sume 78698172Sume if (prefix->timer == NULL) { /* sanity check */ 78798172Sume syslog(LOG_ERR, 78898172Sume "<%s> assumption failure: timer does not exist", 789118660Sume __func__); 79098172Sume exit(1); 79198172Sume } 79298172Sume 79398172Sume syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", 794118660Sume __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, 79598172Sume INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); 79698172Sume 79798172Sume /* stop the expiration timer */ 79898172Sume rtadvd_remove_timer(&prefix->timer); 79998172Sume} 80098172Sume 80155505Sshin/* 80255505Sshin * Try to get an in6_prefixreq contents for a prefix which matches 80355505Sshin * ipr->ipr_prefix and ipr->ipr_plen and belongs to 80455505Sshin * the interface whose name is ipr->ipr_name[]. 80555505Sshin */ 80655505Sshinstatic int 80755505Sshininit_prefix(struct in6_prefixreq *ipr) 80855505Sshin{ 80998262Sume#if 0 81055505Sshin int s; 81155505Sshin 81255505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 813118660Sume syslog(LOG_ERR, "<%s> socket: %s", __func__, 81455505Sshin strerror(errno)); 81555505Sshin exit(1); 81655505Sshin } 81755505Sshin 81855505Sshin if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 819118660Sume syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__, 82055505Sshin strerror(errno)); 82155505Sshin 82255505Sshin ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 82355505Sshin ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 82455505Sshin ipr->ipr_raf_onlink = 1; 82555505Sshin ipr->ipr_raf_auto = 1; 82655505Sshin /* omit other field initialization */ 82755505Sshin } 82855505Sshin else if (ipr->ipr_origin < PR_ORIG_RR) { 82955505Sshin u_char ntopbuf[INET6_ADDRSTRLEN]; 83055505Sshin 83155505Sshin syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 83255505Sshin "lower than PR_ORIG_RR(router renumbering)." 833118660Sume "This should not happen if I am router", __func__, 83455505Sshin inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 83555505Sshin sizeof(ntopbuf)), ipr->ipr_origin); 83657852Sshin close(s); 83755505Sshin return 1; 83855505Sshin } 83955505Sshin 84055505Sshin close(s); 84155505Sshin return 0; 84298262Sume#else 84398262Sume ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 84498262Sume ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 84598262Sume ipr->ipr_raf_onlink = 1; 84698262Sume ipr->ipr_raf_auto = 1; 847118664Sume return 0; 84898262Sume#endif 84955505Sshin} 85055505Sshin 85155505Sshinvoid 85255505Sshinmake_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 85355505Sshin{ 85455505Sshin struct in6_prefixreq ipr; 85555505Sshin 85655505Sshin memset(&ipr, 0, sizeof(ipr)); 85755505Sshin if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 85855505Sshin syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 859118660Sume "exist. This should not happen! %s", __func__, 86055505Sshin ifindex, strerror(errno)); 86155505Sshin exit(1); 86255505Sshin } 86355505Sshin ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 86455505Sshin ipr.ipr_prefix.sin6_family = AF_INET6; 86555505Sshin ipr.ipr_prefix.sin6_addr = *addr; 86655505Sshin ipr.ipr_plen = plen; 86755505Sshin 86855505Sshin if (init_prefix(&ipr)) 86955505Sshin return; /* init failed by some error */ 87055505Sshin add_prefix(rai, &ipr); 87155505Sshin} 87255505Sshin 87362656Skrisvoid 87455505Sshinmake_packet(struct rainfo *rainfo) 87555505Sshin{ 87655505Sshin size_t packlen, lladdroptlen = 0; 87755505Sshin char *buf; 87855505Sshin struct nd_router_advert *ra; 87955505Sshin struct nd_opt_prefix_info *ndopt_pi; 88055505Sshin struct nd_opt_mtu *ndopt_mtu; 881118968Sume#ifdef ROUTEINFO 88278064Sume struct nd_opt_route_info *ndopt_rti; 883118968Sume struct rtinfo *rti; 884118968Sume#endif 88555505Sshin struct prefix *pfx; 88655505Sshin 88755505Sshin /* calculate total length */ 88855505Sshin packlen = sizeof(struct nd_router_advert); 88955505Sshin if (rainfo->advlinkopt) { 89055505Sshin if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 89155505Sshin syslog(LOG_INFO, 89255505Sshin "<%s> link-layer address option has" 893118664Sume " null length on %s. Treat as not included.", 894118660Sume __func__, rainfo->ifname); 89555505Sshin rainfo->advlinkopt = 0; 89655505Sshin } 89755505Sshin packlen += lladdroptlen; 89855505Sshin } 89955505Sshin if (rainfo->pfxs) 90055505Sshin packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 90155505Sshin if (rainfo->linkmtu) 90255505Sshin packlen += sizeof(struct nd_opt_mtu); 903118968Sume#ifdef ROUTEINFO 90478064Sume for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) 90578064Sume packlen += sizeof(struct nd_opt_route_info) + 90678064Sume ((rti->prefixlen + 0x3f) >> 6) * 8; 90778064Sume#endif 90855505Sshin 90955505Sshin /* allocate memory for the packet */ 91055505Sshin if ((buf = malloc(packlen)) == NULL) { 91155505Sshin syslog(LOG_ERR, 91255505Sshin "<%s> can't get enough memory for an RA packet", 913118660Sume __func__); 91455505Sshin exit(1); 91555505Sshin } 91678064Sume if (rainfo->ra_data) { 91778064Sume /* free the previous packet */ 91878064Sume free(rainfo->ra_data); 91978064Sume rainfo->ra_data = NULL; 92078064Sume } 92155505Sshin rainfo->ra_data = buf; 92255505Sshin /* XXX: what if packlen > 576? */ 92355505Sshin rainfo->ra_datalen = packlen; 92455505Sshin 92555505Sshin /* 92655505Sshin * construct the packet 92755505Sshin */ 92855505Sshin ra = (struct nd_router_advert *)buf; 92955505Sshin ra->nd_ra_type = ND_ROUTER_ADVERT; 93055505Sshin ra->nd_ra_code = 0; 93155505Sshin ra->nd_ra_cksum = 0; 93255505Sshin ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); 93378064Sume ra->nd_ra_flags_reserved = 0; /* just in case */ 93478064Sume /* 93578064Sume * XXX: the router preference field, which is a 2-bit field, should be 93678064Sume * initialized before other fields. 93778064Sume */ 93878064Sume ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; 93955505Sshin ra->nd_ra_flags_reserved |= 94055505Sshin rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 94155505Sshin ra->nd_ra_flags_reserved |= 94255505Sshin rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 94355505Sshin ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 94455505Sshin ra->nd_ra_reachable = htonl(rainfo->reachabletime); 94555505Sshin ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 94655505Sshin buf += sizeof(*ra); 94755505Sshin 94855505Sshin if (rainfo->advlinkopt) { 94955505Sshin lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 95055505Sshin buf += lladdroptlen; 95155505Sshin } 95255505Sshin 95355505Sshin if (rainfo->linkmtu) { 95455505Sshin ndopt_mtu = (struct nd_opt_mtu *)buf; 95555505Sshin ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 95655505Sshin ndopt_mtu->nd_opt_mtu_len = 1; 95755505Sshin ndopt_mtu->nd_opt_mtu_reserved = 0; 95878064Sume ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); 95955505Sshin buf += sizeof(struct nd_opt_mtu); 96055505Sshin } 96155505Sshin 96255505Sshin for (pfx = rainfo->prefix.next; 96355505Sshin pfx != &rainfo->prefix; pfx = pfx->next) { 96478064Sume u_int32_t vltime, pltime; 96578064Sume struct timeval now; 96678064Sume 96755505Sshin ndopt_pi = (struct nd_opt_prefix_info *)buf; 96855505Sshin ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 96955505Sshin ndopt_pi->nd_opt_pi_len = 4; 97055505Sshin ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 97155505Sshin ndopt_pi->nd_opt_pi_flags_reserved = 0; 97255505Sshin if (pfx->onlinkflg) 97355505Sshin ndopt_pi->nd_opt_pi_flags_reserved |= 97455505Sshin ND_OPT_PI_FLAG_ONLINK; 97555505Sshin if (pfx->autoconfflg) 97655505Sshin ndopt_pi->nd_opt_pi_flags_reserved |= 97755505Sshin ND_OPT_PI_FLAG_AUTO; 97898172Sume if (pfx->timer) 97998172Sume vltime = 0; 98098172Sume else { 98198172Sume if (pfx->vltimeexpire || pfx->pltimeexpire) 98298172Sume gettimeofday(&now, NULL); 98398172Sume if (pfx->vltimeexpire == 0) 98498172Sume vltime = pfx->validlifetime; 98598172Sume else 98698172Sume vltime = (pfx->vltimeexpire > now.tv_sec) ? 98798172Sume pfx->vltimeexpire - now.tv_sec : 0; 98898172Sume } 98998172Sume if (pfx->timer) 99098172Sume pltime = 0; 99198172Sume else { 99298172Sume if (pfx->pltimeexpire == 0) 99398172Sume pltime = pfx->preflifetime; 99498172Sume else 99598172Sume pltime = (pfx->pltimeexpire > now.tv_sec) ? 99698172Sume pfx->pltimeexpire - now.tv_sec : 0; 99798172Sume } 99878064Sume if (vltime < pltime) { 99978064Sume /* 100078064Sume * this can happen if vltime is decrement but pltime 100178064Sume * is not. 100278064Sume */ 100378064Sume pltime = vltime; 100478064Sume } 100578064Sume ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 100678064Sume ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 100755505Sshin ndopt_pi->nd_opt_pi_reserved2 = 0; 100855505Sshin ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 100955505Sshin 101055505Sshin buf += sizeof(struct nd_opt_prefix_info); 101155505Sshin } 101255505Sshin 1013118968Sume#ifdef ROUTEINFO 101478064Sume for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { 101578064Sume u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; 101678064Sume 101778064Sume ndopt_rti = (struct nd_opt_route_info *)buf; 101878064Sume ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 101978064Sume ndopt_rti->nd_opt_rti_len = 1 + psize; 102078064Sume ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; 102178064Sume ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; 1022113325Ssuz ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime); 102378064Sume memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); 102478064Sume buf += sizeof(struct nd_opt_route_info) + psize * 8; 102578064Sume } 102678064Sume#endif 102778064Sume 102855505Sshin return; 102955505Sshin} 103078064Sume 103178064Sumestatic int 103278064Sumegetinet6sysctl(int code) 103378064Sume{ 103478064Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 103578064Sume int value; 103678064Sume size_t size; 103778064Sume 103878064Sume mib[3] = code; 103978064Sume size = sizeof(value); 104078064Sume if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 104178064Sume < 0) { 104278064Sume syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 1043118660Sume __func__, code, 104478064Sume strerror(errno)); 104578064Sume return(-1); 104678064Sume } 104778064Sume else 104878064Sume return(value); 104978064Sume} 1050