config.c revision 113325
1151497Sru/* $FreeBSD: head/usr.sbin/rtadvd/config.c 113325 2003-04-10 07:31:34Z suz $ */ 2151497Sru/* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */ 3151497Sru 4151497Sru/* 5151497Sru * Copyright (C) 1998 WIDE Project. 6151497Sru * All rights reserved. 7151497Sru * 8151497Sru * Redistribution and use in source and binary forms, with or without 9151497Sru * modification, are permitted provided that the following conditions 10151497Sru * are met: 11151497Sru * 1. Redistributions of source code must retain the above copyright 12151497Sru * notice, this list of conditions and the following disclaimer. 13151497Sru * 2. Redistributions in binary form must reproduce the above copyright 14151497Sru * notice, this list of conditions and the following disclaimer in the 15151497Sru * documentation and/or other materials provided with the distribution. 16151497Sru * 3. Neither the name of the project nor the names of its contributors 17151497Sru * may be used to endorse or promote products derived from this software 18151497Sru * without specific prior written permission. 19151497Sru * 20151497Sru * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23151497Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24151497Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30151497Sru * SUCH DAMAGE. 31151497Sru */ 32151497Sru 33151497Sru#include <sys/param.h> 34151497Sru#include <sys/ioctl.h> 35151497Sru#include <sys/socket.h> 36151497Sru#include <sys/time.h> 37151497Sru#include <sys/sysctl.h> 38151497Sru 39151497Sru#include <net/if.h> 40151497Sru#if defined(__FreeBSD__) && __FreeBSD__ >= 3 41151497Sru#include <net/if_var.h> 42151497Sru#endif /* __FreeBSD__ >= 3 */ 43151497Sru#include <net/route.h> 44151497Sru#include <net/if_dl.h> 45151497Sru 46151497Sru#include <netinet/in.h> 47151497Sru#include <netinet/in_var.h> 48151497Sru#include <netinet/ip6.h> 49151497Sru#include <netinet6/ip6_var.h> 50151497Sru#include <netinet/icmp6.h> 51151497Sru#ifdef MIP6 52151497Sru#include <netinet6/mip6.h> 53151497Sru#endif 54151497Sru 55151497Sru#include <arpa/inet.h> 56151497Sru 57151497Sru#include <stdio.h> 58151497Sru#include <syslog.h> 59151497Sru#include <errno.h> 60151497Sru#include <string.h> 61151497Sru#include <stdlib.h> 62151497Sru#if defined(__NetBSD__) || defined(__OpenBSD__) 63151497Sru#include <search.h> 64151497Sru#endif 65151497Sru#include <unistd.h> 66151497Sru#include <ifaddrs.h> 67151497Sru 68151497Sru#include "rtadvd.h" 69151497Sru#include "advcap.h" 70151497Sru#include "timer.h" 71151497Sru#include "if.h" 72151497Sru#include "config.h" 73151497Sru 74151497Srustatic time_t prefix_timo = (60 * 120); /* 2 hours. 75151497Sru * XXX: should be configurable. */ 76151497Sruextern struct rainfo *ralist; 77151497Sru 78151497Srustatic struct rtadvd_timer *prefix_timeout __P((void *)); 79151497Srustatic void makeentry __P((char *, size_t, int, char *, int)); 80151497Srustatic void get_prefix __P((struct rainfo *)); 81151497Srustatic int getinet6sysctl __P((int)); 82151497Sru 83151497Sruvoid 84151497Srugetconfig(intface) 85151497Sru char *intface; 86151497Sru{ 87151497Sru int stat, pfxs, i; 88151497Sru char tbuf[BUFSIZ]; 89151497Sru struct rainfo *tmp; 90151497Sru long val; 91151497Sru long long val64; 92151497Sru char buf[BUFSIZ]; 93151497Sru char *bp = buf; 94151497Sru char *addr; 95151497Sru static int forwarding = -1; 96151497Sru 97151497Sru#define MUSTHAVE(var, cap) \ 98151497Sru do { \ 99151497Sru int t; \ 100151497Sru if ((t = agetnum(cap)) < 0) { \ 101151497Sru fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 102151497Sru cap, intface); \ 103151497Sru exit(1); \ 104151497Sru } \ 105151497Sru var = t; \ 106151497Sru } while (0) 107151497Sru#define MAYHAVE(var, cap, def) \ 108151497Sru do { \ 109151497Sru if ((var = agetnum(cap)) < 0) \ 110151497Sru var = def; \ 111151497Sru } while (0) 112151497Sru 113151497Sru if ((stat = agetent(tbuf, intface)) <= 0) { 114151497Sru memset(tbuf, 0, sizeof(tbuf)); 115151497Sru syslog(LOG_INFO, 116151497Sru "<%s> %s isn't defined in the configuration file" 117151497Sru " or the configuration file doesn't exist." 118151497Sru " Treat it as default", 119151497Sru __FUNCTION__, intface); 120151497Sru } 121151497Sru 122151497Sru tmp = (struct rainfo *)malloc(sizeof(*ralist)); 123151497Sru memset(tmp, 0, sizeof(*tmp)); 124151497Sru tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; 125151497Sru tmp->route.next = tmp->route.prev = &tmp->route; 126151497Sru 127151497Sru /* check if we are allowed to forward packets (if not determined) */ 128151497Sru if (forwarding < 0) { 129151497Sru if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) 130151497Sru exit(1); 131151497Sru } 132151497Sru 133151497Sru /* get interface information */ 134151497Sru if (agetflag("nolladdr")) 135151497Sru tmp->advlinkopt = 0; 136151497Sru else 137151497Sru tmp->advlinkopt = 1; 138151497Sru if (tmp->advlinkopt) { 139151497Sru if ((tmp->sdl = if_nametosdl(intface)) == NULL) { 140151497Sru syslog(LOG_ERR, 141151497Sru "<%s> can't get information of %s", 142151497Sru __FUNCTION__, intface); 143151497Sru exit(1); 144151497Sru } 145151497Sru tmp->ifindex = tmp->sdl->sdl_index; 146151497Sru } else 147151497Sru tmp->ifindex = if_nametoindex(intface); 148151497Sru strncpy(tmp->ifname, intface, sizeof(tmp->ifname)); 149151497Sru if ((tmp->phymtu = if_getmtu(intface)) == 0) { 150151497Sru tmp->phymtu = IPV6_MMTU; 151151497Sru syslog(LOG_WARNING, 152151497Sru "<%s> can't get interface mtu of %s. Treat as %d", 153151497Sru __FUNCTION__, intface, IPV6_MMTU); 154151497Sru } 155151497Sru 156151497Sru /* 157151497Sru * set router configuration variables. 158151497Sru */ 159151497Sru MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 160151497Sru if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 161151497Sru syslog(LOG_ERR, 162151497Sru "<%s> maxinterval must be between %e and %u", 163151497Sru __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 164151497Sru exit(1); 165151497Sru } 166151497Sru tmp->maxinterval = (u_int)val; 167151497Sru MAYHAVE(val, "mininterval", tmp->maxinterval/3); 168151497Sru if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { 169151497Sru syslog(LOG_ERR, 170151497Sru "<%s> mininterval must be between %e and %d", 171151497Sru __FUNCTION__, 172151497Sru MIN_MININTERVAL, 173151497Sru (tmp->maxinterval * 3) / 4); 174151497Sru exit(1); 175151497Sru } 176151497Sru tmp->mininterval = (u_int)val; 177151497Sru 178151497Sru MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 179151497Sru tmp->hoplimit = val & 0xff; 180151497Sru 181151497Sru MAYHAVE(val, "raflags", 0); 182151497Sru tmp->managedflg = val & ND_RA_FLAG_MANAGED; 183151497Sru tmp->otherflg = val & ND_RA_FLAG_OTHER; 184151497Sru#ifdef MIP6 185151497Sru if (mobileip6) 186151497Sru tmp->haflg = val & ND_RA_FLAG_HA; 187151497Sru#endif 188151497Sru#ifndef ND_RA_FLAG_RTPREF_MASK 189151497Sru#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 190151497Sru#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 191151497Sru#endif 192151497Sru tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 193151497Sru if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { 194151497Sru syslog(LOG_ERR, "<%s> invalid router preference on %s", 195151497Sru __FUNCTION__, intface); 196151497Sru exit(1); 197151497Sru } 198151497Sru 199151497Sru MAYHAVE(val, "rltime", tmp->maxinterval * 3); 200151497Sru if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { 201151497Sru syslog(LOG_ERR, 202151497Sru "<%s> router lifetime on %s must be 0 or" 203151497Sru " between %d and %d", 204151497Sru __FUNCTION__, intface, 205151497Sru tmp->maxinterval, MAXROUTERLIFETIME); 206151497Sru exit(1); 207151497Sru } 208151497Sru /* 209151497Sru * Basically, hosts MUST NOT send Router Advertisement messages at any 210151497Sru * time (RFC 2461, Section 6.2.3). However, it would sometimes be 211151497Sru * useful to allow hosts to advertise some parameters such as prefix 212151497Sru * information and link MTU. Thus, we allow hosts to invoke rtadvd 213151497Sru * only when router lifetime (on every advertising interface) is 214151497Sru * explicitly set zero. (see also the above section) 215151497Sru */ 216151497Sru if (val && forwarding == 0) { 217151497Sru syslog(LOG_WARNING, 218151497Sru "<%s> non zero router lifetime is specified for %s, " 219151497Sru "which must not be allowed for hosts.", 220151497Sru __FUNCTION__, intface); 221151497Sru exit(1); 222151497Sru } 223151497Sru tmp->lifetime = val & 0xffff; 224151497Sru 225151497Sru MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 226151497Sru if (val > MAXREACHABLETIME) { 227151497Sru syslog(LOG_ERR, 228151497Sru "<%s> reachable time must be no greater than %d", 229151497Sru __FUNCTION__, MAXREACHABLETIME); 230151497Sru exit(1); 231151497Sru } 232151497Sru tmp->reachabletime = (u_int32_t)val; 233151497Sru 234151497Sru MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 235151497Sru if (val64 < 0 || val64 > 0xffffffff) { 236151497Sru syslog(LOG_ERR, 237151497Sru "<%s> retrans time out of range", __FUNCTION__); 238151497Sru exit(1); 239151497Sru } 240151497Sru tmp->retranstimer = (u_int32_t)val64; 241151497Sru 242151497Sru#ifndef MIP6 243151497Sru if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { 244151497Sru syslog(LOG_ERR, 245151497Sru "<%s> mobile-ip6 configuration not supported", 246151497Sru __FUNCTION__); 247151497Sru exit(1); 248151497Sru } 249151497Sru#else 250151497Sru if (!mobileip6) { 251151497Sru if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { 252151497Sru syslog(LOG_ERR, 253151497Sru "<%s> mobile-ip6 configuration without " 254151497Sru "proper command line option", 255151497Sru __FUNCTION__); 256151497Sru exit(1); 257151497Sru } 258151497Sru } else { 259151497Sru tmp->hapref = 0; 260151497Sru if ((val = agetnum("hapref")) >= 0) 261151497Sru tmp->hapref = (int16_t)val; 262151497Sru if (tmp->hapref != 0) { 263151497Sru tmp->hatime = 0; 264151497Sru MUSTHAVE(val, "hatime"); 265151497Sru tmp->hatime = (u_int16_t)val; 266151497Sru if (tmp->hatime <= 0) { 267151497Sru syslog(LOG_ERR, 268151497Sru "<%s> home agent lifetime must be greater than 0", 269151497Sru __FUNCTION__); 270151497Sru exit(1); 271151497Sru } 272151497Sru } 273151497Sru } 274151497Sru#endif 275151497Sru 276151497Sru /* prefix information */ 277151497Sru 278151497Sru /* 279151497Sru * This is an implementation specific parameter to consinder 280151497Sru * link propagation delays and poorly synchronized clocks when 281151497Sru * checking consistency of advertised lifetimes. 282151497Sru */ 283151497Sru MAYHAVE(val, "clockskew", 0); 284151497Sru tmp->clockskew = val; 285151497Sru 286151497Sru if ((pfxs = agetnum("addrs")) < 0) { 287151497Sru /* auto configure prefix information */ 288151497Sru if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { 289151497Sru syslog(LOG_ERR, 290151497Sru "<%s> conflicting prefix configuration for %s: " 291151497Sru "automatic and manual config at the same time", 292151497Sru __FUNCTION__, intface); 293151497Sru exit(1); 294151497Sru } 295151497Sru get_prefix(tmp); 296151497Sru } 297151497Sru else { 298151497Sru tmp->pfxs = pfxs; 299151497Sru for (i = 0; i < pfxs; i++) { 300151497Sru struct prefix *pfx; 301151497Sru char entbuf[256]; 302151497Sru int added = (pfxs > 1) ? 1 : 0; 303151497Sru 304151497Sru /* allocate memory to store prefix information */ 305151497Sru if ((pfx = malloc(sizeof(struct prefix))) == NULL) { 306151497Sru syslog(LOG_ERR, 307151497Sru "<%s> can't allocate enough memory", 308151497Sru __FUNCTION__); 309151497Sru exit(1); 310151497Sru } 311151497Sru memset(pfx, 0, sizeof(*pfx)); 312151497Sru 313151497Sru /* link into chain */ 314151497Sru insque(pfx, &tmp->prefix); 315151497Sru pfx->rainfo = tmp; 316151497Sru 317151497Sru pfx->origin = PREFIX_FROM_CONFIG; 318151497Sru 319151497Sru makeentry(entbuf, sizeof(entbuf), i, "prefixlen", 320151497Sru added); 321151497Sru MAYHAVE(val, entbuf, 64); 322151497Sru if (val < 0 || val > 128) { 323151497Sru syslog(LOG_ERR, 324151497Sru "<%s> prefixlen out of range", 325151497Sru __FUNCTION__); 326151497Sru exit(1); 327151497Sru } 328151497Sru pfx->prefixlen = (int)val; 329151497Sru 330151497Sru makeentry(entbuf, sizeof(entbuf), i, "pinfoflags", 331151497Sru added); 332151497Sru#ifdef MIP6 333151497Sru if (mobileip6) 334151497Sru { 335151497Sru MAYHAVE(val, entbuf, 336151497Sru (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| 337151497Sru ND_OPT_PI_FLAG_ROUTER)); 338151497Sru } else 339151497Sru#endif 340151497Sru { 341151497Sru MAYHAVE(val, entbuf, 342151497Sru (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 343151497Sru } 344151497Sru pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 345151497Sru pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 346151497Sru#ifdef MIP6 347151497Sru pfx->routeraddr = val & ND_OPT_PI_FLAG_ROUTER; 348151497Sru#endif 349151497Sru 350151497Sru makeentry(entbuf, sizeof(entbuf), i, "vltime", added); 351151497Sru MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 352151497Sru if (val64 < 0 || val64 > 0xffffffff) { 353151497Sru syslog(LOG_ERR, 354151497Sru "<%s> vltime out of range", 355151497Sru __FUNCTION__); 356151497Sru exit(1); 357151497Sru } 358151497Sru pfx->validlifetime = (u_int32_t)val64; 359151497Sru 360151497Sru makeentry(entbuf, sizeof(entbuf), i, "vltimedecr", 361151497Sru added); 362151497Sru if (agetflag(entbuf)) { 363151497Sru struct timeval now; 364151497Sru gettimeofday(&now, 0); 365151497Sru pfx->vltimeexpire = 366151497Sru now.tv_sec + pfx->validlifetime; 367151497Sru } 368151497Sru 369151497Sru makeentry(entbuf, sizeof(entbuf), i, "pltime", added); 370151497Sru MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 371151497Sru if (val64 < 0 || val64 > 0xffffffff) { 372151497Sru syslog(LOG_ERR, 373151497Sru "<%s> pltime out of range", 374151497Sru __FUNCTION__); 375151497Sru exit(1); 376151497Sru } 377151497Sru pfx->preflifetime = (u_int32_t)val64; 378151497Sru 379151497Sru makeentry(entbuf, sizeof(entbuf), i, "pltimedecr", 380151497Sru added); 381151497Sru if (agetflag(entbuf)) { 382151497Sru struct timeval now; 383151497Sru gettimeofday(&now, 0); 384151497Sru pfx->pltimeexpire = 385151497Sru now.tv_sec + pfx->preflifetime; 386151497Sru } 387151497Sru 388151497Sru makeentry(entbuf, sizeof(entbuf), i, "addr", added); 389151497Sru addr = (char *)agetstr(entbuf, &bp); 390151497Sru if (addr == NULL) { 391151497Sru syslog(LOG_ERR, 392151497Sru "<%s> need %s as a prefix for " 393151497Sru "interface %s", 394151497Sru __FUNCTION__, entbuf, intface); 395151497Sru exit(1); 396151497Sru } 397151497Sru if (inet_pton(AF_INET6, addr, 398151497Sru &pfx->prefix) != 1) { 399151497Sru syslog(LOG_ERR, 400151497Sru "<%s> inet_pton failed for %s", 401151497Sru __FUNCTION__, addr); 402151497Sru exit(1); 403151497Sru } 404151497Sru if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { 405151497Sru syslog(LOG_ERR, 406151497Sru "<%s> multicast prefix(%s) must " 407151497Sru "not be advertised (IF=%s)", 408151497Sru __FUNCTION__, addr, intface); 409151497Sru exit(1); 410151497Sru } 411151497Sru if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) 412151497Sru syslog(LOG_NOTICE, 413151497Sru "<%s> link-local prefix(%s) will be" 414151497Sru " advertised on %s", 415151497Sru __FUNCTION__, addr, intface); 416151497Sru } 417151497Sru } 418151497Sru 419151497Sru MAYHAVE(val, "mtu", 0); 420151497Sru if (val < 0 || val > 0xffffffff) { 421151497Sru syslog(LOG_ERR, 422151497Sru "<%s> mtu out of range", __FUNCTION__); 423151497Sru exit(1); 424151497Sru } 425151497Sru tmp->linkmtu = (u_int32_t)val; 426151497Sru if (tmp->linkmtu == 0) { 427151497Sru char *mtustr; 428151497Sru 429151497Sru if ((mtustr = (char *)agetstr("mtu", &bp)) && 430151497Sru strcmp(mtustr, "auto") == 0) 431151497Sru tmp->linkmtu = tmp->phymtu; 432151497Sru } 433151497Sru else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { 434151497Sru syslog(LOG_ERR, 435151497Sru "<%s> advertised link mtu must be between" 436151497Sru " least MTU and physical link MTU", 437151497Sru __FUNCTION__); 438151497Sru exit(1); 439151497Sru } 440151497Sru 441151497Sru /* route information */ 442151497Sru 443151497Sru MAYHAVE(val, "routes", 0); 444151497Sru if (val < 0 || val > 0xffffffff) { 445151497Sru syslog(LOG_ERR, 446151497Sru "<%s> number of route information improper", __FUNCTION__); 447151497Sru exit(1); 448151497Sru } 449151497Sru tmp->routes = val; 450151497Sru for (i = 0; i < tmp->routes; i++) { 451151497Sru struct rtinfo *rti; 452151497Sru char entbuf[256]; 453151497Sru int added = (tmp->routes > 1) ? 1 : 0; 454151497Sru 455151497Sru /* allocate memory to store prefix information */ 456151497Sru if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { 457151497Sru syslog(LOG_ERR, 458151497Sru "<%s> can't allocate enough memory", 459151497Sru __FUNCTION__); 460151497Sru exit(1); 461151497Sru } 462151497Sru memset(rti, 0, sizeof(*rti)); 463151497Sru 464151497Sru /* link into chain */ 465151497Sru insque(rti, &tmp->route); 466151497Sru 467151497Sru makeentry(entbuf, sizeof(entbuf), i, "rtrplen", added); 468151497Sru MAYHAVE(val, entbuf, 64); 469151497Sru if (val < 0 || val > 128) { 470151497Sru syslog(LOG_ERR, 471151497Sru "<%s> prefixlen out of range", 472151497Sru __FUNCTION__); 473151497Sru exit(1); 474151497Sru } 475151497Sru rti->prefixlen = (int)val; 476151497Sru 477151497Sru makeentry(entbuf, sizeof(entbuf), i, "rtrflags", added); 478151497Sru MAYHAVE(val, entbuf, 0); 479151497Sru rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; 480151497Sru if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { 481151497Sru syslog(LOG_ERR, "<%s> invalid route preference", 482151497Sru __FUNCTION__); 483151497Sru exit(1); 484151497Sru } 485151497Sru 486151497Sru makeentry(entbuf, sizeof(entbuf), i, "rtrltime", added); 487151497Sru /* 488151497Sru * XXX: since default value of route lifetime is not defined in 489151497Sru * draft-draves-route-selection-01.txt, I took the default 490151497Sru * value of valid lifetime of prefix as its default. 491151497Sru * It need be much considered. 492151497Sru */ 493151497Sru MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 494151497Sru if (val64 < 0 || val64 > 0xffffffff) { 495151497Sru syslog(LOG_ERR, 496151497Sru "<%s> rtrltime out of range", 497151497Sru __FUNCTION__); 498151497Sru exit(1); 499151497Sru } 500151497Sru rti->ltime = (u_int32_t)val64; 501151497Sru 502151497Sru makeentry(entbuf, sizeof(entbuf), i, "rtrprefix", added); 503151497Sru addr = (char *)agetstr(entbuf, &bp); 504151497Sru if (addr == NULL) { 505151497Sru syslog(LOG_ERR, 506151497Sru "<%s> need %s as a route for " 507151497Sru "interface %s", 508151497Sru __FUNCTION__, entbuf, intface); 509151497Sru exit(1); 510151497Sru } 511151497Sru if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { 512151497Sru syslog(LOG_ERR, 513151497Sru "<%s> inet_pton failed for %s", 514151497Sru __FUNCTION__, addr); 515151497Sru exit(1); 516151497Sru } 517151497Sru#if 0 518151497Sru /* 519151497Sru * XXX: currently there's no restriction in route information 520151497Sru * prefix according to draft-draves-route-selection-01.txt, 521151497Sru * however I think the similar restriction be necessary. 522151497Sru */ 523151497Sru MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 524151497Sru if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 525151497Sru syslog(LOG_ERR, 526151497Sru "<%s> multicast route (%s) must " 527151497Sru "not be advertised (IF=%s)", 528151497Sru __FUNCTION__, addr, intface); 529151497Sru exit(1); 530151497Sru } 531151497Sru if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 532151497Sru syslog(LOG_NOTICE, 533151497Sru "<%s> link-local route (%s) must " 534151497Sru "not be advertised on %s", 535151497Sru __FUNCTION__, addr, intface); 536151497Sru exit(1); 537151497Sru } 538151497Sru#endif 539151497Sru } 540151497Sru 541151497Sru /* okey */ 542151497Sru tmp->next = ralist; 543151497Sru ralist = tmp; 544151497Sru 545151497Sru /* construct the sending packet */ 546151497Sru make_packet(tmp); 547151497Sru 548151497Sru /* set timer */ 549151497Sru tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 550151497Sru tmp, tmp); 551151497Sru ra_timer_update((void *)tmp, &tmp->timer->tm); 552151497Sru rtadvd_set_timer(&tmp->timer->tm, tmp->timer); 553151497Sru} 554151497Sru 555151497Srustatic void 556151497Sruget_prefix(struct rainfo *rai) 557151497Sru{ 558151497Sru struct ifaddrs *ifap, *ifa; 559151497Sru struct prefix *pp; 560151497Sru struct in6_addr *a; 561151497Sru u_char *p, *ep, *m, *lim; 562151497Sru u_char ntopbuf[INET6_ADDRSTRLEN]; 563151497Sru 564151497Sru if (getifaddrs(&ifap) < 0) { 565151497Sru syslog(LOG_ERR, 566151497Sru "<%s> can't get interface addresses", 567151497Sru __FUNCTION__); 568151497Sru exit(1); 569151497Sru } 570151497Sru for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 571151497Sru int plen; 572151497Sru 573151497Sru if (strcmp(ifa->ifa_name, rai->ifname) != 0) 574151497Sru continue; 575151497Sru if (ifa->ifa_addr->sa_family != AF_INET6) 576151497Sru continue; 577151497Sru a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 578151497Sru if (IN6_IS_ADDR_LINKLOCAL(a)) 579151497Sru continue; 580151497Sru 581151497Sru /* get prefix length */ 582151497Sru m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 583151497Sru lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 584151497Sru plen = prefixlen(m, lim); 585151497Sru if (plen < 0 || plen > 128) { 586151497Sru syslog(LOG_ERR, "<%s> failed to get prefixlen " 587151497Sru "or prefix is invalid", 588151497Sru __FUNCTION__); 589151497Sru exit(1); 590151497Sru } 591151497Sru if (find_prefix(rai, a, plen)) { 592151497Sru /* ignore a duplicated prefix. */ 593151497Sru continue; 594151497Sru } 595151497Sru 596151497Sru /* allocate memory to store prefix info. */ 597151497Sru if ((pp = malloc(sizeof(*pp))) == NULL) { 598151497Sru syslog(LOG_ERR, 599151497Sru "<%s> can't get allocate buffer for prefix", 600151497Sru __FUNCTION__); 601151497Sru exit(1); 602151497Sru } 603151497Sru memset(pp, 0, sizeof(*pp)); 604151497Sru 605151497Sru /* set prefix, sweep bits outside of prefixlen */ 606151497Sru pp->prefixlen = plen; 607151497Sru memcpy(&pp->prefix, a, sizeof(*a)); 608151497Sru p = (u_char *)&pp->prefix; 609151497Sru ep = (u_char *)(&pp->prefix + 1); 610151497Sru while (m < lim) 611151497Sru *p++ &= *m++; 612151497Sru while (p < ep) 613151497Sru *p++ = 0x00; 614151497Sru 615151497Sru if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, 616151497Sru sizeof(ntopbuf))) { 617151497Sru syslog(LOG_ERR, "<%s> inet_ntop failed", __FUNCTION__); 618151497Sru exit(1); 619151497Sru } 620151497Sru syslog(LOG_DEBUG, 621151497Sru "<%s> add %s/%d to prefix list on %s", 622151497Sru __FUNCTION__, ntopbuf, pp->prefixlen, rai->ifname); 623151497Sru 624151497Sru /* set other fields with protocol defaults */ 625151497Sru pp->validlifetime = DEF_ADVVALIDLIFETIME; 626151497Sru pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 627151497Sru pp->onlinkflg = 1; 628151497Sru pp->autoconfflg = 1; 629151497Sru pp->origin = PREFIX_FROM_KERNEL; 630151497Sru 631151497Sru /* link into chain */ 632151497Sru insque(pp, &rai->prefix); 633151497Sru pp->rainfo = rai; 634151497Sru 635151497Sru /* counter increment */ 636151497Sru rai->pfxs++; 637151497Sru } 638151497Sru 639151497Sru freeifaddrs(ifap); 640151497Sru} 641151497Sru 642151497Srustatic void 643151497Srumakeentry(buf, len, id, string, add) 644151497Sru char *buf; 645151497Sru size_t len; 646151497Sru int id; 647151497Sru char *string; 648151497Sru int add; 649151497Sru{ 650151497Sru char *ep = buf + len; 651151497Sru 652151497Sru strcpy(buf, string); 653151497Sru if (add) { 654151497Sru char *cp; 655151497Sru 656151497Sru cp = (char *)index(buf, '\0'); 657151497Sru snprintf(cp, ep - cp, "%d", id); 658151497Sru } 659151497Sru} 660151497Sru 661151497Sru/* 662151497Sru * Add a prefix to the list of specified interface and reconstruct 663151497Sru * the outgoing packet. 664151497Sru * The prefix must not be in the list. 665151497Sru * XXX: other parameter of the prefix(e.g. lifetime) shoule be 666151497Sru * able to be specified. 667151497Sru */ 668151497Srustatic void 669151497Sruadd_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 670151497Sru{ 671151497Sru struct prefix *prefix; 672151497Sru u_char ntopbuf[INET6_ADDRSTRLEN]; 673151497Sru 674151497Sru if ((prefix = malloc(sizeof(*prefix))) == NULL) { 675151497Sru syslog(LOG_ERR, "<%s> memory allocation failed", 676151497Sru __FUNCTION__); 677151497Sru return; /* XXX: error or exit? */ 678151497Sru } 679151497Sru memset(prefix, 0, sizeof(*prefix)); 680151497Sru prefix->prefix = ipr->ipr_prefix.sin6_addr; 681151497Sru prefix->prefixlen = ipr->ipr_plen; 682151497Sru prefix->validlifetime = ipr->ipr_vltime; 683151497Sru prefix->preflifetime = ipr->ipr_pltime; 684151497Sru prefix->onlinkflg = ipr->ipr_raf_onlink; 685151497Sru prefix->autoconfflg = ipr->ipr_raf_auto; 686151497Sru prefix->origin = PREFIX_FROM_DYNAMIC; 687151497Sru 688151497Sru insque(prefix, &rai->prefix); 689151497Sru prefix->rainfo = rai; 690151497Sru 691151497Sru syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 692151497Sru __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 693151497Sru ntopbuf, INET6_ADDRSTRLEN), 694151497Sru ipr->ipr_plen, rai->ifname); 695151497Sru 696151497Sru /* free the previous packet */ 697151497Sru free(rai->ra_data); 698151497Sru rai->ra_data = NULL; 699151497Sru 700151497Sru /* reconstruct the packet */ 701151497Sru rai->pfxs++; 702151497Sru make_packet(rai); 703151497Sru 704151497Sru /* 705151497Sru * reset the timer so that the new prefix will be advertised quickly. 706151497Sru */ 707151497Sru rai->initcounter = 0; 708151497Sru ra_timer_update((void *)rai, &rai->timer->tm); 709151497Sru rtadvd_set_timer(&rai->timer->tm, rai->timer); 710151497Sru} 711151497Sru 712151497Sru/* 713151497Sru * Delete a prefix to the list of specified interface and reconstruct 714151497Sru * the outgoing packet. 715151497Sru * The prefix must be in the list. 716151497Sru */ 717151497Sruvoid 718151497Srudelete_prefix(struct prefix *prefix) 719151497Sru{ 720151497Sru u_char ntopbuf[INET6_ADDRSTRLEN]; 721151497Sru struct rainfo *rai = prefix->rainfo; 722151497Sru 723151497Sru remque(prefix); 724151497Sru syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 725151497Sru __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, 726151497Sru ntopbuf, INET6_ADDRSTRLEN), 727151497Sru prefix->prefixlen, rai->ifname); 728151497Sru if (prefix->timer) 729151497Sru rtadvd_remove_timer(&prefix->timer); 730151497Sru free(prefix); 731151497Sru rai->pfxs--; 732151497Sru} 733151497Sru 734151497Sruvoid 735151497Sruinvalidate_prefix(struct prefix *prefix) 736151497Sru{ 737151497Sru u_char ntopbuf[INET6_ADDRSTRLEN]; 738151497Sru struct timeval timo; 739151497Sru struct rainfo *rai = prefix->rainfo; 740151497Sru 741151497Sru if (prefix->timer) { /* sanity check */ 742151497Sru syslog(LOG_ERR, 743151497Sru "<%s> assumption failure: timer already exists", 744151497Sru __FUNCTION__); 745151497Sru exit(1); 746151497Sru } 747151497Sru 748151497Sru syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " 749151497Sru "will expire in %ld seconds", __FUNCTION__, 750151497Sru inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), 751151497Sru prefix->prefixlen, rai->ifname, (long)prefix_timo); 752151497Sru 753151497Sru /* set the expiration timer */ 754151497Sru prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL); 755151497Sru if (prefix->timer == NULL) { 756151497Sru syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. " 757151497Sru "remove the prefix", __FUNCTION__); 758151497Sru delete_prefix(prefix); 759151497Sru } 760151497Sru timo.tv_sec = prefix_timo; 761151497Sru timo.tv_usec = 0; 762151497Sru rtadvd_set_timer(&timo, prefix->timer); 763151497Sru} 764151497Sru 765151497Srustatic struct rtadvd_timer * 766151497Sruprefix_timeout(void *arg) 767151497Sru{ 768151497Sru struct prefix *prefix = (struct prefix *)arg; 769151497Sru 770151497Sru delete_prefix(prefix); 771151497Sru 772151497Sru return(NULL); 773151497Sru} 774151497Sru 775151497Sruvoid 776151497Sruupdate_prefix(struct prefix * prefix) 777151497Sru{ 778151497Sru u_char ntopbuf[INET6_ADDRSTRLEN]; 779151497Sru struct rainfo *rai = prefix->rainfo; 780151497Sru 781151497Sru if (prefix->timer == NULL) { /* sanity check */ 782151497Sru syslog(LOG_ERR, 783151497Sru "<%s> assumption failure: timer does not exist", 784151497Sru __FUNCTION__); 785151497Sru exit(1); 786151497Sru } 787151497Sru 788151497Sru syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", 789151497Sru __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, 790151497Sru INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname); 791151497Sru 792151497Sru /* stop the expiration timer */ 793151497Sru rtadvd_remove_timer(&prefix->timer); 794151497Sru} 795151497Sru 796151497Sru/* 797151497Sru * Try to get an in6_prefixreq contents for a prefix which matches 798151497Sru * ipr->ipr_prefix and ipr->ipr_plen and belongs to 799151497Sru * the interface whose name is ipr->ipr_name[]. 800151497Sru */ 801151497Srustatic int 802151497Sruinit_prefix(struct in6_prefixreq *ipr) 803151497Sru{ 804151497Sru#if 0 805151497Sru int s; 806151497Sru 807151497Sru if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 808151497Sru syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, 809151497Sru strerror(errno)); 810151497Sru exit(1); 811151497Sru } 812151497Sru 813151497Sru if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 814151497Sru syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__, 815151497Sru strerror(errno)); 816151497Sru 817151497Sru ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 818151497Sru ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 819151497Sru ipr->ipr_raf_onlink = 1; 820151497Sru ipr->ipr_raf_auto = 1; 821151497Sru /* omit other field initialization */ 822151497Sru } 823151497Sru else if (ipr->ipr_origin < PR_ORIG_RR) { 824151497Sru u_char ntopbuf[INET6_ADDRSTRLEN]; 825151497Sru 826151497Sru syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 827151497Sru "lower than PR_ORIG_RR(router renumbering)." 828151497Sru "This should not happen if I am router", __FUNCTION__, 829151497Sru inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 830151497Sru sizeof(ntopbuf)), ipr->ipr_origin); 831151497Sru close(s); 832151497Sru return 1; 833151497Sru } 834151497Sru 835151497Sru close(s); 836151497Sru return 0; 837151497Sru#else 838151497Sru ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 839151497Sru ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 840151497Sru ipr->ipr_raf_onlink = 1; 841151497Sru ipr->ipr_raf_auto = 1; 842151497Sru return 0; 843151497Sru#endif 844151497Sru} 845151497Sru 846151497Sruvoid 847151497Srumake_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 848151497Sru{ 849151497Sru struct in6_prefixreq ipr; 850151497Sru 851151497Sru memset(&ipr, 0, sizeof(ipr)); 852151497Sru if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 853151497Sru syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 854151497Sru "exist. This should not happen! %s", __FUNCTION__, 855151497Sru ifindex, strerror(errno)); 856151497Sru exit(1); 857151497Sru } 858151497Sru ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 859151497Sru ipr.ipr_prefix.sin6_family = AF_INET6; 860151497Sru ipr.ipr_prefix.sin6_addr = *addr; 861151497Sru ipr.ipr_plen = plen; 862151497Sru 863151497Sru if (init_prefix(&ipr)) 864151497Sru return; /* init failed by some error */ 865151497Sru add_prefix(rai, &ipr); 866151497Sru} 867151497Sru 868151497Sruvoid 869151497Srumake_packet(struct rainfo *rainfo) 870151497Sru{ 871151497Sru size_t packlen, lladdroptlen = 0; 872151497Sru char *buf; 873151497Sru struct nd_router_advert *ra; 874151497Sru struct nd_opt_prefix_info *ndopt_pi; 875151497Sru struct nd_opt_mtu *ndopt_mtu; 876151497Sru#ifdef MIP6 877151497Sru struct nd_opt_advinterval *ndopt_advint; 878151497Sru struct nd_opt_homeagent_info *ndopt_hai; 879151497Sru#endif 880151497Sru struct nd_opt_route_info *ndopt_rti; 881151497Sru struct prefix *pfx; 882151497Sru struct rtinfo *rti; 883151497Sru 884151497Sru /* calculate total length */ 885151497Sru packlen = sizeof(struct nd_router_advert); 886151497Sru if (rainfo->advlinkopt) { 887151497Sru if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 888151497Sru syslog(LOG_INFO, 889151497Sru "<%s> link-layer address option has" 890151497Sru " null length on %s." 891151497Sru " Treat as not included.", 892151497Sru __FUNCTION__, rainfo->ifname); 893151497Sru rainfo->advlinkopt = 0; 894151497Sru } 895151497Sru packlen += lladdroptlen; 896151497Sru } 897151497Sru if (rainfo->pfxs) 898151497Sru packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 899151497Sru if (rainfo->linkmtu) 900151497Sru packlen += sizeof(struct nd_opt_mtu); 901151497Sru#ifdef MIP6 902151497Sru if (mobileip6 && rainfo->maxinterval) 903151497Sru packlen += sizeof(struct nd_opt_advinterval); 904151497Sru if (mobileip6 && rainfo->hatime) 905151497Sru packlen += sizeof(struct nd_opt_homeagent_info); 906151497Sru#endif 907151497Sru#ifdef ND_OPT_ROUTE_INFO 908151497Sru for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) 909151497Sru packlen += sizeof(struct nd_opt_route_info) + 910151497Sru ((rti->prefixlen + 0x3f) >> 6) * 8; 911151497Sru#endif 912151497Sru 913151497Sru /* allocate memory for the packet */ 914151497Sru if ((buf = malloc(packlen)) == NULL) { 915151497Sru syslog(LOG_ERR, 916151497Sru "<%s> can't get enough memory for an RA packet", 917151497Sru __FUNCTION__); 918151497Sru exit(1); 919151497Sru } 920151497Sru if (rainfo->ra_data) { 921151497Sru /* free the previous packet */ 922151497Sru free(rainfo->ra_data); 923151497Sru rainfo->ra_data = NULL; 924151497Sru } 925151497Sru rainfo->ra_data = buf; 926151497Sru /* XXX: what if packlen > 576? */ 927151497Sru rainfo->ra_datalen = packlen; 928151497Sru 929151497Sru /* 930151497Sru * construct the packet 931151497Sru */ 932151497Sru ra = (struct nd_router_advert *)buf; 933151497Sru ra->nd_ra_type = ND_ROUTER_ADVERT; 934151497Sru ra->nd_ra_code = 0; 935151497Sru ra->nd_ra_cksum = 0; 936151497Sru ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); 937151497Sru ra->nd_ra_flags_reserved = 0; /* just in case */ 938151497Sru /* 939151497Sru * XXX: the router preference field, which is a 2-bit field, should be 940151497Sru * initialized before other fields. 941151497Sru */ 942151497Sru ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; 943151497Sru ra->nd_ra_flags_reserved |= 944151497Sru rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 945151497Sru ra->nd_ra_flags_reserved |= 946151497Sru rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 947151497Sru#ifdef MIP6 948151497Sru ra->nd_ra_flags_reserved |= 949151497Sru rainfo->haflg ? ND_RA_FLAG_HA : 0; 950151497Sru#endif 951151497Sru ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 952151497Sru ra->nd_ra_reachable = htonl(rainfo->reachabletime); 953151497Sru ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 954151497Sru buf += sizeof(*ra); 955151497Sru 956151497Sru if (rainfo->advlinkopt) { 957151497Sru lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 958151497Sru buf += lladdroptlen; 959151497Sru } 960151497Sru 961151497Sru if (rainfo->linkmtu) { 962151497Sru ndopt_mtu = (struct nd_opt_mtu *)buf; 963151497Sru ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 964151497Sru ndopt_mtu->nd_opt_mtu_len = 1; 965151497Sru ndopt_mtu->nd_opt_mtu_reserved = 0; 966151497Sru ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); 967151497Sru buf += sizeof(struct nd_opt_mtu); 968151497Sru } 969151497Sru 970151497Sru#ifdef MIP6 971151497Sru if (mobileip6 && rainfo->maxinterval) { 972151497Sru ndopt_advint = (struct nd_opt_advinterval *)buf; 973151497Sru ndopt_advint->nd_opt_adv_type = ND_OPT_ADVINTERVAL; 974151497Sru ndopt_advint->nd_opt_adv_len = 1; 975151497Sru ndopt_advint->nd_opt_adv_reserved = 0; 976151497Sru ndopt_advint->nd_opt_adv_interval = htonl(rainfo->maxinterval * 977151497Sru 1000); 978151497Sru buf += sizeof(struct nd_opt_advinterval); 979151497Sru } 980151497Sru#endif 981151497Sru 982151497Sru#ifdef MIP6 983151497Sru if (rainfo->hatime) { 984151497Sru ndopt_hai = (struct nd_opt_homeagent_info *)buf; 985151497Sru ndopt_hai->nd_opt_hai_type = ND_OPT_HOMEAGENT_INFO; 986151497Sru ndopt_hai->nd_opt_hai_len = 1; 987151497Sru ndopt_hai->nd_opt_hai_reserved = 0; 988151497Sru ndopt_hai->nd_opt_hai_preference = htons(rainfo->hapref); 989151497Sru ndopt_hai->nd_opt_hai_lifetime = htons(rainfo->hatime); 990151497Sru buf += sizeof(struct nd_opt_homeagent_info); 991151497Sru } 992151497Sru#endif 993151497Sru 994151497Sru for (pfx = rainfo->prefix.next; 995151497Sru pfx != &rainfo->prefix; pfx = pfx->next) { 996151497Sru u_int32_t vltime, pltime; 997151497Sru struct timeval now; 998151497Sru 999151497Sru ndopt_pi = (struct nd_opt_prefix_info *)buf; 1000151497Sru ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 1001151497Sru ndopt_pi->nd_opt_pi_len = 4; 1002151497Sru ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 1003151497Sru ndopt_pi->nd_opt_pi_flags_reserved = 0; 1004151497Sru if (pfx->onlinkflg) 1005151497Sru ndopt_pi->nd_opt_pi_flags_reserved |= 1006151497Sru ND_OPT_PI_FLAG_ONLINK; 1007151497Sru if (pfx->autoconfflg) 1008151497Sru ndopt_pi->nd_opt_pi_flags_reserved |= 1009151497Sru ND_OPT_PI_FLAG_AUTO; 1010151497Sru#ifdef MIP6 1011151497Sru if (pfx->routeraddr) 1012151497Sru ndopt_pi->nd_opt_pi_flags_reserved |= 1013151497Sru ND_OPT_PI_FLAG_ROUTER; 1014151497Sru#endif 1015151497Sru if (pfx->timer) 1016151497Sru vltime = 0; 1017151497Sru else { 1018151497Sru if (pfx->vltimeexpire || pfx->pltimeexpire) 1019151497Sru gettimeofday(&now, NULL); 1020151497Sru if (pfx->vltimeexpire == 0) 1021151497Sru vltime = pfx->validlifetime; 1022151497Sru else 1023151497Sru vltime = (pfx->vltimeexpire > now.tv_sec) ? 1024151497Sru pfx->vltimeexpire - now.tv_sec : 0; 1025151497Sru } 1026151497Sru if (pfx->timer) 1027151497Sru pltime = 0; 1028151497Sru else { 1029151497Sru if (pfx->pltimeexpire == 0) 1030151497Sru pltime = pfx->preflifetime; 1031151497Sru else 1032151497Sru pltime = (pfx->pltimeexpire > now.tv_sec) ? 1033151497Sru pfx->pltimeexpire - now.tv_sec : 0; 1034151497Sru } 1035151497Sru if (vltime < pltime) { 1036151497Sru /* 1037151497Sru * this can happen if vltime is decrement but pltime 1038151497Sru * is not. 1039151497Sru */ 1040151497Sru pltime = vltime; 1041151497Sru } 1042151497Sru ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 1043151497Sru ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 1044151497Sru ndopt_pi->nd_opt_pi_reserved2 = 0; 1045151497Sru ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 1046151497Sru 1047151497Sru buf += sizeof(struct nd_opt_prefix_info); 1048151497Sru } 1049151497Sru 1050151497Sru#ifdef ND_OPT_ROUTE_INFO 1051151497Sru for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { 1052151497Sru u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; 1053151497Sru 1054151497Sru ndopt_rti = (struct nd_opt_route_info *)buf; 1055151497Sru ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 1056151497Sru ndopt_rti->nd_opt_rti_len = 1 + psize; 1057151497Sru ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; 1058151497Sru ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; 1059151497Sru ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime); 1060151497Sru memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); 1061151497Sru buf += sizeof(struct nd_opt_route_info) + psize * 8; 1062151497Sru } 1063151497Sru#endif 1064151497Sru 1065151497Sru return; 1066151497Sru} 1067151497Sru 1068151497Srustatic int 1069151497Srugetinet6sysctl(int code) 1070151497Sru{ 1071151497Sru int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 1072151497Sru int value; 1073151497Sru size_t size; 1074151497Sru 1075151497Sru mib[3] = code; 1076151497Sru size = sizeof(value); 1077151497Sru if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 1078151497Sru < 0) { 1079151497Sru syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 1080151497Sru __FUNCTION__, code, 1081151497Sru strerror(errno)); 1082151497Sru return(-1); 1083151497Sru } 1084151497Sru else 1085151497Sru return(value); 1086151497Sru} 1087151497Sru