171333Sitojun/* $FreeBSD: releng/10.3/usr.sbin/rtadvd/config.c 254955 2013-08-27 11:50:33Z hrs $ */ 2118968Sume/* $KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $ */ 362656Skris 455505Sshin/* 555505Sshin * Copyright (C) 1998 WIDE Project. 6224144Shrs * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 755505Sshin * All rights reserved. 8222732Shrs * 955505Sshin * Redistribution and use in source and binary forms, with or without 1055505Sshin * modification, are permitted provided that the following conditions 1155505Sshin * are met: 1255505Sshin * 1. Redistributions of source code must retain the above copyright 1355505Sshin * notice, this list of conditions and the following disclaimer. 1455505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1555505Sshin * notice, this list of conditions and the following disclaimer in the 1655505Sshin * documentation and/or other materials provided with the distribution. 1755505Sshin * 3. Neither the name of the project nor the names of its contributors 1855505Sshin * may be used to endorse or promote products derived from this software 1955505Sshin * without specific prior written permission. 20222732Shrs * 2155505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2255505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2555505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155505Sshin * SUCH DAMAGE. 3255505Sshin */ 3355505Sshin 3455505Sshin#include <sys/param.h> 3555505Sshin#include <sys/ioctl.h> 3655505Sshin#include <sys/socket.h> 3755505Sshin 3855505Sshin#include <net/if.h> 3955505Sshin#include <net/if_var.h> 4055505Sshin#include <net/route.h> 4155505Sshin#include <net/if_dl.h> 4255505Sshin 4355505Sshin#include <netinet/in.h> 4455505Sshin#include <netinet/in_var.h> 4557120Sshin#include <netinet/ip6.h> 4655505Sshin#include <netinet6/ip6_var.h> 4757120Sshin#include <netinet/icmp6.h> 48151468Ssuz#include <netinet6/nd6.h> 4955505Sshin 5055505Sshin#include <arpa/inet.h> 5155505Sshin 5255505Sshin#include <stdio.h> 5355505Sshin#include <syslog.h> 5455505Sshin#include <errno.h> 55224144Shrs#include <inttypes.h> 56222732Shrs#include <netdb.h> 5755505Sshin#include <string.h> 58136764Ssuz#include <search.h> 5955505Sshin#include <stdlib.h> 60253970Shrs#include <time.h> 6155505Sshin#include <unistd.h> 6278064Sume#include <ifaddrs.h> 6355505Sshin 6455505Sshin#include "rtadvd.h" 6555505Sshin#include "advcap.h" 6655505Sshin#include "timer.h" 6755505Sshin#include "if.h" 6855505Sshin#include "config.h" 6955505Sshin 70222732Shrs/* label of tcapcode + number + domain name + zero octet */ 71222732Shrsstatic char entbuf[10 + 3 + NI_MAXHOST + 1]; 72222732Shrsstatic char oentbuf[10 + 3 + NI_MAXHOST + 1]; 73222732Shrsstatic char abuf[DNAME_LABELENC_MAXLEN]; 74222732Shrs 7598172Sumestatic time_t prefix_timo = (60 * 120); /* 2 hours. 7698172Sume * XXX: should be configurable. */ 7798172Sume 78173412Skevlostatic struct rtadvd_timer *prefix_timeout(void *); 79222732Shrsstatic void makeentry(char *, size_t, int, const char *); 80222732Shrsstatic size_t dname_labelenc(char *, const char *); 8155505Sshin 82222732Shrs/* Encode domain name label encoding in RFC 1035 Section 3.1 */ 83222732Shrsstatic size_t 84222732Shrsdname_labelenc(char *dst, const char *src) 8555505Sshin{ 86222732Shrs char *dst_origin; 87222732Shrs char *p; 88222732Shrs size_t len; 8955505Sshin 90222732Shrs dst_origin = dst; 91222732Shrs len = strlen(src); 92222732Shrs 93222732Shrs /* Length fields per 63 octets + '\0' (<= DNAME_LABELENC_MAXLEN) */ 94222732Shrs memset(dst, 0, len + len / 64 + 1 + 1); 95222732Shrs 96222732Shrs syslog(LOG_DEBUG, "<%s> labelenc = %s", __func__, src); 97222732Shrs while (src && (len = strlen(src)) != 0) { 98222732Shrs /* Put a length field with 63 octet limitation first. */ 99222732Shrs p = strchr(src, '.'); 100222732Shrs if (p == NULL) 101222732Shrs *dst++ = len = MIN(63, len); 102222732Shrs else 103222732Shrs *dst++ = len = MIN(63, p - src); 104222732Shrs /* Copy 63 octets at most. */ 105222732Shrs memcpy(dst, src, len); 106222732Shrs dst += len; 107222732Shrs if (p == NULL) /* the last label */ 108222732Shrs break; 109222732Shrs src = p + 1; 110222732Shrs } 111222732Shrs /* Always need a 0-length label at the tail. */ 112222732Shrs *dst++ = '\0'; 113222732Shrs 114222743Shrs syslog(LOG_DEBUG, "<%s> labellen = %td", __func__, dst - dst_origin); 115222732Shrs return (dst - dst_origin); 116222732Shrs} 117222732Shrs 118222732Shrs#define MUSTHAVE(var, cap) \ 11962656Skris do { \ 120118784Sume int64_t t; \ 12155505Sshin if ((t = agetnum(cap)) < 0) { \ 12255505Sshin fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 12355505Sshin cap, intface); \ 12455505Sshin exit(1); \ 12555505Sshin } \ 12655505Sshin var = t; \ 12762656Skris } while (0) 128222732Shrs 129222732Shrs#define MAYHAVE(var, cap, def) \ 13062656Skris do { \ 13155505Sshin if ((var = agetnum(cap)) < 0) \ 13255505Sshin var = def; \ 13362656Skris } while (0) 13455505Sshin 135224144Shrsint 136224144Shrsloadconfig_index(int idx) 137224144Shrs{ 138224144Shrs char ifname[IFNAMSIZ]; 139222732Shrs 140224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 141224144Shrs 142224144Shrs if (if_indextoname(idx, ifname) != NULL) 143224144Shrs return (loadconfig_ifname(ifname)); 144224144Shrs else 145224144Shrs return (1); 146224144Shrs} 147224144Shrs 148222732Shrsint 149224144Shrsloadconfig_ifname(char *ifname) 150222972Shrs{ 151224144Shrs struct ifinfo *ifi; 152222972Shrs 153224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 154224144Shrs 155224144Shrs update_ifinfo(&ifilist, UPDATE_IFINFO_ALL); 156224144Shrs TAILQ_FOREACH(ifi, &ifilist, ifi_next) { 157224144Shrs /* NULL means all IFs will be processed. */ 158224144Shrs if (ifname != NULL && 159224144Shrs strcmp(ifi->ifi_ifname, ifname) != 0) 160224144Shrs continue; 161224144Shrs 162224144Shrs if (!ifi->ifi_persist) { 163224144Shrs syslog(LOG_INFO, 164224144Shrs "<%s> %s is not a target interface. " 165224144Shrs "Ignored at this moment.", __func__, 166224144Shrs ifi->ifi_ifname); 167224144Shrs continue; 168224144Shrs 169224144Shrs } 170224144Shrs if (ifi->ifi_ifindex == 0) { 171222972Shrs syslog(LOG_ERR, 172224144Shrs "<%s> %s not found. " 173224144Shrs "Ignored at this moment.", __func__, 174224144Shrs ifi->ifi_ifname); 175222972Shrs continue; 176222972Shrs } 177224144Shrs if (getconfig(ifi) == NULL) { 178222972Shrs syslog(LOG_ERR, 179222972Shrs "<%s> invalid configuration for %s. " 180224144Shrs "Ignored at this moment.", __func__, 181224144Shrs ifi->ifi_ifname); 182224144Shrs continue; 183224144Shrs } 184222972Shrs } 185224144Shrs return (0); 186224144Shrs} 187222972Shrs 188224144Shrsint 189224144Shrsrm_ifinfo_index(int idx) 190224144Shrs{ 191224144Shrs struct ifinfo *ifi; 192224144Shrs 193224144Shrs ifi = if_indextoifinfo(idx); 194224144Shrs if (ifi == NULL) { 195224144Shrs syslog(LOG_ERR, "<%s>: ifinfo not found (idx=%d)", 196224144Shrs __func__, idx); 197224144Shrs return (-1); 198224144Shrs } 199224144Shrs 200224144Shrs return (rm_ifinfo(ifi)); 201224144Shrs} 202224144Shrs 203224144Shrsint 204224144Shrsrm_ifinfo(struct ifinfo *ifi) 205224144Shrs{ 206224144Shrs int error; 207224144Shrs 208224144Shrs syslog(LOG_DEBUG, "<%s> enter (%s).", __func__, ifi->ifi_ifname); 209224144Shrs switch (ifi->ifi_state) { 210224144Shrs case IFI_STATE_UNCONFIGURED: 211224144Shrs return (0); 212224144Shrs break; 213224144Shrs default: 214224144Shrs ifi->ifi_state = IFI_STATE_UNCONFIGURED; 215224144Shrs syslog(LOG_DEBUG, 216224144Shrs "<%s> ifname=%s marked as UNCONFIGURED.", 217224144Shrs __func__, ifi->ifi_ifname); 218224144Shrs 219228990Suqs /* XXX: No MC leaving here because index is disappeared */ 220224144Shrs 221224144Shrs /* Inactivate timer */ 222224144Shrs rtadvd_remove_timer(ifi->ifi_ra_timer); 223224144Shrs ifi->ifi_ra_timer = NULL; 224224144Shrs break; 225224144Shrs } 226224144Shrs 227224144Shrs /* clean up ifi */ 228224144Shrs if (!ifi->ifi_persist) { 229224144Shrs TAILQ_REMOVE(&ifilist, ifi, ifi_next); 230224144Shrs syslog(LOG_DEBUG, "<%s>: ifinfo (idx=%d) removed.", 231224144Shrs __func__, ifi->ifi_ifindex); 232224144Shrs free(ifi); 233224144Shrs } else { 234224144Shrs /* recreate an empty entry */ 235224144Shrs update_persist_ifinfo(&ifilist, ifi->ifi_ifname); 236224144Shrs syslog(LOG_DEBUG, "<%s>: ifname=%s is persistent.", 237224144Shrs __func__, ifi->ifi_ifname); 238224144Shrs } 239224144Shrs 240224144Shrs /* clean up rai if any */ 241224144Shrs switch (ifi->ifi_state) { 242224144Shrs case IFI_STATE_CONFIGURED: 243224144Shrs if (ifi->ifi_rainfo != NULL) { 244224144Shrs error = rm_rainfo(ifi->ifi_rainfo); 245224144Shrs if (error) 246224144Shrs return (error); 247224144Shrs ifi->ifi_rainfo = NULL; 248224144Shrs } 249224144Shrs break; 250224144Shrs case IFI_STATE_TRANSITIVE: 251224144Shrs if (ifi->ifi_rainfo == ifi->ifi_rainfo_trans) { 252224144Shrs if (ifi->ifi_rainfo != NULL) { 253224144Shrs error = rm_rainfo(ifi->ifi_rainfo); 254224144Shrs if (error) 255224144Shrs return (error); 256224144Shrs ifi->ifi_rainfo = NULL; 257224144Shrs ifi->ifi_rainfo_trans = NULL; 258224144Shrs } 259224144Shrs } else { 260224144Shrs if (ifi->ifi_rainfo != NULL) { 261224144Shrs error = rm_rainfo(ifi->ifi_rainfo); 262224144Shrs if (error) 263224144Shrs return (error); 264224144Shrs ifi->ifi_rainfo = NULL; 265224144Shrs } 266224144Shrs if (ifi->ifi_rainfo_trans != NULL) { 267224144Shrs error = rm_rainfo(ifi->ifi_rainfo_trans); 268224144Shrs if (error) 269224144Shrs return (error); 270224144Shrs ifi->ifi_rainfo_trans = NULL; 271224144Shrs } 272224144Shrs } 273224144Shrs } 274224144Shrs 275224144Shrs syslog(LOG_DEBUG, "<%s> leave (%s).", __func__, ifi->ifi_ifname); 276222972Shrs return (0); 277222972Shrs} 278222972Shrs 279222972Shrsint 280224144Shrsrm_rainfo(struct rainfo *rai) 281222732Shrs{ 282222732Shrs struct prefix *pfx; 283222732Shrs struct soliciter *sol; 284222732Shrs struct rdnss *rdn; 285222732Shrs struct rdnss_addr *rdna; 286222732Shrs struct dnssl *dns; 287222732Shrs struct rtinfo *rti; 288222732Shrs 289224144Shrs syslog(LOG_DEBUG, "<%s>: enter", __func__); 290222732Shrs 291222732Shrs TAILQ_REMOVE(&railist, rai, rai_next); 292224144Shrs if (rai->rai_ifinfo != NULL) 293224144Shrs syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.", 294224144Shrs __func__, rai->rai_ifinfo->ifi_ifindex); 295222732Shrs 296222732Shrs if (rai->rai_ra_data != NULL) 297222732Shrs free(rai->rai_ra_data); 298222732Shrs 299254955Shrs while ((pfx = TAILQ_FIRST(&rai->rai_prefix)) != NULL) 300254955Shrs delete_prefix(pfx); 301222732Shrs while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) { 302222732Shrs TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next); 303222732Shrs free(sol); 304222732Shrs } 305222732Shrs while ((rdn = TAILQ_FIRST(&rai->rai_rdnss)) != NULL) { 306222732Shrs TAILQ_REMOVE(&rai->rai_rdnss, rdn, rd_next); 307222732Shrs while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) { 308222732Shrs TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next); 309222732Shrs free(rdna); 310222732Shrs } 311222732Shrs free(rdn); 312222732Shrs } 313222732Shrs while ((dns = TAILQ_FIRST(&rai->rai_dnssl)) != NULL) { 314222732Shrs TAILQ_REMOVE(&rai->rai_dnssl, dns, dn_next); 315222732Shrs free(dns); 316222732Shrs } 317222732Shrs while ((rti = TAILQ_FIRST(&rai->rai_route)) != NULL) { 318222732Shrs TAILQ_REMOVE(&rai->rai_route, rti, rti_next); 319222732Shrs free(rti); 320222732Shrs } 321222732Shrs free(rai); 322224144Shrs syslog(LOG_DEBUG, "<%s>: leave", __func__); 323224144Shrs 324222732Shrs return (0); 325222732Shrs} 326222732Shrs 327224144Shrsstruct ifinfo * 328224144Shrsgetconfig(struct ifinfo *ifi) 329222732Shrs{ 330222732Shrs int stat, i; 331224144Shrs int error; 332222732Shrs char tbuf[BUFSIZ]; 333222732Shrs struct rainfo *rai; 334222972Shrs struct rainfo *rai_old; 335224144Shrs int32_t val; 336222732Shrs int64_t val64; 337222732Shrs char buf[BUFSIZ]; 338222732Shrs char *bp = buf; 339222732Shrs char *addr, *flagstr; 340222732Shrs 341224144Shrs if (ifi == NULL) /* if does not exist */ 342224144Shrs return (NULL); 343224144Shrs 344224144Shrs if (ifi->ifi_state == IFI_STATE_TRANSITIVE && 345224144Shrs ifi->ifi_rainfo == NULL) { 346224144Shrs syslog(LOG_INFO, "<%s> %s is shutting down. Skipped.", 347224144Shrs __func__, ifi->ifi_ifname); 348224144Shrs return (NULL); 349222732Shrs } 350222732Shrs 351224144Shrs if ((stat = agetent(tbuf, ifi->ifi_ifname)) <= 0) { 35255505Sshin memset(tbuf, 0, sizeof(tbuf)); 35355505Sshin syslog(LOG_INFO, 354222732Shrs "<%s> %s isn't defined in the configuration file" 355222732Shrs " or the configuration file doesn't exist." 356222732Shrs " Treat it as default", 357224144Shrs __func__, ifi->ifi_ifname); 35855505Sshin } 35955505Sshin 360222820Shrs ELM_MALLOC(rai, exit(1)); 361222732Shrs TAILQ_INIT(&rai->rai_prefix); 362222732Shrs TAILQ_INIT(&rai->rai_route); 363222732Shrs TAILQ_INIT(&rai->rai_rdnss); 364222732Shrs TAILQ_INIT(&rai->rai_dnssl); 365222732Shrs TAILQ_INIT(&rai->rai_soliciter); 366224144Shrs rai->rai_ifinfo = ifi; 36755505Sshin 368222732Shrs /* gather on-link prefixes from the network interfaces. */ 369222732Shrs if (agetflag("noifprefix")) 370222732Shrs rai->rai_advifprefix = 0; 371222732Shrs else 372222732Shrs rai->rai_advifprefix = 1; 37378064Sume 37455505Sshin /* get interface information */ 37555505Sshin if (agetflag("nolladdr")) 376222732Shrs rai->rai_advlinkopt = 0; 37755505Sshin else 378222732Shrs rai->rai_advlinkopt = 1; 379222732Shrs if (rai->rai_advlinkopt) { 380224144Shrs if (ifi->ifi_sdl.sdl_type == 0) { 38155505Sshin syslog(LOG_ERR, 382222732Shrs "<%s> can't get information of %s", 383224144Shrs __func__, ifi->ifi_ifname); 384222972Shrs goto getconfig_free_rai; 38555505Sshin } 38655505Sshin } 38755505Sshin 38855505Sshin /* 38955505Sshin * set router configuration variables. 39055505Sshin */ 39155505Sshin MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 39255505Sshin if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 39355505Sshin syslog(LOG_ERR, 394224144Shrs "<%s> maxinterval (%" PRIu32 ") on %s is invalid " 395222732Shrs "(must be between %u and %u)", __func__, val, 396224144Shrs ifi->ifi_ifname, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 397222972Shrs goto getconfig_free_rai; 39855505Sshin } 399224144Shrs rai->rai_maxinterval = (uint16_t)val; 400222732Shrs 401222732Shrs MAYHAVE(val, "mininterval", rai->rai_maxinterval/3); 402224144Shrs if ((uint16_t)val < MIN_MININTERVAL || 403224144Shrs (uint16_t)val > (rai->rai_maxinterval * 3) / 4) { 40455505Sshin syslog(LOG_ERR, 405224144Shrs "<%s> mininterval (%" PRIu32 ") on %s is invalid " 406222732Shrs "(must be between %d and %d)", 407224144Shrs __func__, val, ifi->ifi_ifname, MIN_MININTERVAL, 408222732Shrs (rai->rai_maxinterval * 3) / 4); 409222972Shrs goto getconfig_free_rai; 41055505Sshin } 411224144Shrs rai->rai_mininterval = (uint16_t)val; 41255505Sshin 41355505Sshin MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 414222732Shrs rai->rai_hoplimit = val & 0xff; 41555505Sshin 416118968Sume if ((flagstr = (char *)agetstr("raflags", &bp))) { 417118968Sume val = 0; 418118968Sume if (strchr(flagstr, 'm')) 419118968Sume val |= ND_RA_FLAG_MANAGED; 420118968Sume if (strchr(flagstr, 'o')) 421118968Sume val |= ND_RA_FLAG_OTHER; 422118968Sume if (strchr(flagstr, 'h')) 423118968Sume val |= ND_RA_FLAG_RTPREF_HIGH; 424118968Sume if (strchr(flagstr, 'l')) { 425118968Sume if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 426118968Sume syslog(LOG_ERR, "<%s> the \'h\' and \'l\'" 427118968Sume " router flags are exclusive", __func__); 428222972Shrs goto getconfig_free_rai; 429118968Sume } 430118968Sume val |= ND_RA_FLAG_RTPREF_LOW; 431118968Sume } 432222732Shrs } else 433118968Sume MAYHAVE(val, "raflags", 0); 434222732Shrs 435222732Shrs rai->rai_managedflg = val & ND_RA_FLAG_MANAGED; 436222732Shrs rai->rai_otherflg = val & ND_RA_FLAG_OTHER; 43778064Sume#ifndef ND_RA_FLAG_RTPREF_MASK 43878064Sume#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 43978064Sume#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 44078064Sume#endif 441222732Shrs rai->rai_rtpref = val & ND_RA_FLAG_RTPREF_MASK; 442222732Shrs if (rai->rai_rtpref == ND_RA_FLAG_RTPREF_RSV) { 443118968Sume syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s", 444224144Shrs __func__, rai->rai_rtpref, ifi->ifi_ifname); 445222972Shrs goto getconfig_free_rai; 44678064Sume } 44755505Sshin 448222732Shrs MAYHAVE(val, "rltime", rai->rai_maxinterval * 3); 449224144Shrs if ((uint16_t)val && ((uint16_t)val < rai->rai_maxinterval || 450224144Shrs (uint16_t)val > MAXROUTERLIFETIME)) { 45155505Sshin syslog(LOG_ERR, 452224144Shrs "<%s> router lifetime (%" PRIu32 ") on %s is invalid " 453222732Shrs "(must be 0 or between %d and %d)", 454224144Shrs __func__, val, ifi->ifi_ifname, rai->rai_maxinterval, 455222732Shrs MAXROUTERLIFETIME); 456222972Shrs goto getconfig_free_rai; 45755505Sshin } 458222732Shrs rai->rai_lifetime = val & 0xffff; 45955505Sshin 46055505Sshin MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 461118968Sume if (val < 0 || val > MAXREACHABLETIME) { 46255505Sshin syslog(LOG_ERR, 463224144Shrs "<%s> reachable time (%" PRIu32 ") on %s is invalid " 464222732Shrs "(must be no greater than %d)", 465224144Shrs __func__, val, ifi->ifi_ifname, MAXREACHABLETIME); 466222972Shrs goto getconfig_free_rai; 46755505Sshin } 468224144Shrs rai->rai_reachabletime = (uint32_t)val; 46955505Sshin 47078064Sume MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 47178064Sume if (val64 < 0 || val64 > 0xffffffff) { 472224144Shrs syslog(LOG_ERR, "<%s> retrans time (%" PRIu64 ") on %s out of range", 473224144Shrs __func__, val64, ifi->ifi_ifname); 474222972Shrs goto getconfig_free_rai; 47555505Sshin } 476224144Shrs rai->rai_retranstimer = (uint32_t)val64; 47755505Sshin 478118968Sume if (agetnum("hapref") != -1 || agetnum("hatime") != -1) { 47978064Sume syslog(LOG_ERR, 480222732Shrs "<%s> mobile-ip6 configuration not supported", 481222732Shrs __func__); 482222972Shrs goto getconfig_free_rai; 48378064Sume } 48455505Sshin /* prefix information */ 48578064Sume 48678064Sume /* 487118664Sume * This is an implementation specific parameter to consider 48878064Sume * link propagation delays and poorly synchronized clocks when 48978064Sume * checking consistency of advertised lifetimes. 49078064Sume */ 49178064Sume MAYHAVE(val, "clockskew", 0); 492222732Shrs rai->rai_clockskew = val; 49378064Sume 494222732Shrs rai->rai_pfxs = 0; 495118968Sume for (i = -1; i < MAXPREFIX; i++) { 496118968Sume struct prefix *pfx; 497118968Sume 498118968Sume makeentry(entbuf, sizeof(entbuf), i, "addr"); 499118968Sume addr = (char *)agetstr(entbuf, &bp); 500118968Sume if (addr == NULL) 501118968Sume continue; 502118968Sume 503118968Sume /* allocate memory to store prefix information */ 504222732Shrs ELM_MALLOC(pfx, exit(1)); 505222820Shrs pfx->pfx_rainfo = rai; 506222732Shrs pfx->pfx_origin = PREFIX_FROM_CONFIG; 50771437Sume 508222732Shrs if (inet_pton(AF_INET6, addr, &pfx->pfx_prefix) != 1) { 509118968Sume syslog(LOG_ERR, 510222732Shrs "<%s> inet_pton failed for %s", 511222732Shrs __func__, addr); 512222972Shrs goto getconfig_free_pfx; 513118968Sume } 514222732Shrs if (IN6_IS_ADDR_MULTICAST(&pfx->pfx_prefix)) { 515118968Sume syslog(LOG_ERR, 516222732Shrs "<%s> multicast prefix (%s) must " 517222732Shrs "not be advertised on %s", 518224144Shrs __func__, addr, ifi->ifi_ifname); 519222972Shrs goto getconfig_free_pfx; 520118968Sume } 521222732Shrs if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix)) 522118968Sume syslog(LOG_NOTICE, 523222732Shrs "<%s> link-local prefix (%s) will be" 524222732Shrs " advertised on %s", 525224144Shrs __func__, addr, ifi->ifi_ifname); 52662656Skris 527118968Sume makeentry(entbuf, sizeof(entbuf), i, "prefixlen"); 528118968Sume MAYHAVE(val, entbuf, 64); 529118968Sume if (val < 0 || val > 128) { 530224144Shrs syslog(LOG_ERR, "<%s> prefixlen (%" PRIu32 ") for %s " 531222732Shrs "on %s out of range", 532224144Shrs __func__, val, addr, ifi->ifi_ifname); 533222972Shrs goto getconfig_free_pfx; 534118968Sume } 535222732Shrs pfx->pfx_prefixlen = (int)val; 53655505Sshin 537118968Sume makeentry(entbuf, sizeof(entbuf), i, "pinfoflags"); 538118968Sume if ((flagstr = (char *)agetstr(entbuf, &bp))) { 539118968Sume val = 0; 540118968Sume if (strchr(flagstr, 'l')) 541118968Sume val |= ND_OPT_PI_FLAG_ONLINK; 542118968Sume if (strchr(flagstr, 'a')) 543118968Sume val |= ND_OPT_PI_FLAG_AUTO; 544118968Sume } else { 545118968Sume MAYHAVE(val, entbuf, 546118968Sume (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 547118968Sume } 548222732Shrs pfx->pfx_onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 549222732Shrs pfx->pfx_autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 55055505Sshin 551118968Sume makeentry(entbuf, sizeof(entbuf), i, "vltime"); 552118968Sume MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 553118968Sume if (val64 < 0 || val64 > 0xffffffff) { 554224144Shrs syslog(LOG_ERR, "<%s> vltime (%" PRIu64 ") for " 555118968Sume "%s/%d on %s is out of range", 556224144Shrs __func__, val64, 557224144Shrs addr, pfx->pfx_prefixlen, ifi->ifi_ifname); 558222972Shrs goto getconfig_free_pfx; 559118968Sume } 560224144Shrs pfx->pfx_validlifetime = (uint32_t)val64; 56155505Sshin 562118968Sume makeentry(entbuf, sizeof(entbuf), i, "vltimedecr"); 563118968Sume if (agetflag(entbuf)) { 564253970Shrs struct timespec now; 565253970Shrs 566253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 567222732Shrs pfx->pfx_vltimeexpire = 568222732Shrs now.tv_sec + pfx->pfx_validlifetime; 569118968Sume } 57078064Sume 571118968Sume makeentry(entbuf, sizeof(entbuf), i, "pltime"); 572118968Sume MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 573118968Sume if (val64 < 0 || val64 > 0xffffffff) { 574118968Sume syslog(LOG_ERR, 575224144Shrs "<%s> pltime (%" PRIu64 ") for %s/%d on %s " 576118968Sume "is out of range", 577224144Shrs __func__, val64, 578224144Shrs addr, pfx->pfx_prefixlen, ifi->ifi_ifname); 579222972Shrs goto getconfig_free_pfx; 580118968Sume } 581224144Shrs pfx->pfx_preflifetime = (uint32_t)val64; 58255505Sshin 583118968Sume makeentry(entbuf, sizeof(entbuf), i, "pltimedecr"); 584118968Sume if (agetflag(entbuf)) { 585253970Shrs struct timespec now; 586253970Shrs 587253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 588222732Shrs pfx->pfx_pltimeexpire = 589222732Shrs now.tv_sec + pfx->pfx_preflifetime; 59055505Sshin } 591222820Shrs /* link into chain */ 592222820Shrs TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 593222820Shrs rai->rai_pfxs++; 594222972Shrs continue; 595222972Shrsgetconfig_free_pfx: 596222972Shrs free(pfx); 59755505Sshin } 598222732Shrs if (rai->rai_advifprefix && rai->rai_pfxs == 0) 599222732Shrs get_prefix(rai); 60055505Sshin 601224144Shrs MAYHAVE(val64, "mtu", 0); 602224144Shrs if (val < 0 || val64 > 0xffffffff) { 60355505Sshin syslog(LOG_ERR, 604224144Shrs "<%s> mtu (%" PRIu64 ") on %s out of range", 605224144Shrs __func__, val64, ifi->ifi_ifname); 606222972Shrs goto getconfig_free_rai; 60755505Sshin } 608224144Shrs rai->rai_linkmtu = (uint32_t)val64; 609222732Shrs if (rai->rai_linkmtu == 0) { 61055505Sshin char *mtustr; 61155505Sshin 61255505Sshin if ((mtustr = (char *)agetstr("mtu", &bp)) && 61355505Sshin strcmp(mtustr, "auto") == 0) 614224144Shrs rai->rai_linkmtu = ifi->ifi_phymtu; 61555505Sshin } 616222732Shrs else if (rai->rai_linkmtu < IPV6_MMTU || 617224144Shrs rai->rai_linkmtu > ifi->ifi_phymtu) { 61855505Sshin syslog(LOG_ERR, 619224144Shrs "<%s> advertised link mtu (%" PRIu32 ") on %s is invalid (must " 620222732Shrs "be between least MTU (%d) and physical link MTU (%d)", 621224144Shrs __func__, rai->rai_linkmtu, ifi->ifi_ifname, 622224144Shrs IPV6_MMTU, ifi->ifi_phymtu); 623222972Shrs goto getconfig_free_rai; 62455505Sshin } 62555505Sshin 626151468Ssuz#ifdef SIOCSIFINFO_IN6 627151468Ssuz { 628151468Ssuz struct in6_ndireq ndi; 629151468Ssuz int s; 630151468Ssuz 631151468Ssuz if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 632151468Ssuz syslog(LOG_ERR, "<%s> socket: %s", __func__, 633222732Shrs strerror(errno)); 634151468Ssuz exit(1); 635151468Ssuz } 636151468Ssuz memset(&ndi, 0, sizeof(ndi)); 637224144Shrs strncpy(ndi.ifname, ifi->ifi_ifname, sizeof(ndi.ifname)); 638222732Shrs if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) 639151468Ssuz syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s", 640224144Shrs __func__, ifi->ifi_ifname, strerror(errno)); 641151468Ssuz 642151468Ssuz /* reflect the RA info to the host variables in kernel */ 643222732Shrs ndi.ndi.chlim = rai->rai_hoplimit; 644222732Shrs ndi.ndi.retrans = rai->rai_retranstimer; 645222732Shrs ndi.ndi.basereachable = rai->rai_reachabletime; 646222732Shrs if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) 647151468Ssuz syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s", 648224144Shrs __func__, ifi->ifi_ifname, strerror(errno)); 649222732Shrs 650151468Ssuz close(s); 651151468Ssuz } 652151468Ssuz#endif 653151468Ssuz 65478064Sume /* route information */ 655222732Shrs rai->rai_routes = 0; 656118968Sume for (i = -1; i < MAXROUTE; i++) { 65778064Sume struct rtinfo *rti; 65878064Sume 659118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtprefix"); 660118968Sume addr = (char *)agetstr(entbuf, &bp); 661118968Sume if (addr == NULL) { 662118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix"); 663118968Sume addr = (char *)agetstr(oentbuf, &bp); 664222732Shrs if (addr) 665118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 666222732Shrs oentbuf, entbuf); 667118968Sume } 668118968Sume if (addr == NULL) 669118968Sume continue; 670118968Sume 67178064Sume /* allocate memory to store prefix information */ 672222732Shrs ELM_MALLOC(rti, exit(1)); 67378064Sume 674222732Shrs if (inet_pton(AF_INET6, addr, &rti->rti_prefix) != 1) { 675118968Sume syslog(LOG_ERR, "<%s> inet_pton failed for %s", 676222732Shrs __func__, addr); 677222972Shrs goto getconfig_free_rti; 67878064Sume } 67978064Sume#if 0 68078064Sume /* 68178064Sume * XXX: currently there's no restriction in route information 682118968Sume * prefix according to 683118968Sume * draft-ietf-ipngwg-router-selection-00.txt. 684118968Sume * However, I think the similar restriction be necessary. 68578064Sume */ 68678064Sume MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 68778064Sume if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 68878064Sume syslog(LOG_ERR, 689222732Shrs "<%s> multicast route (%s) must " 690222732Shrs "not be advertised on %s", 691224144Shrs __func__, addr, ifi->ifi_ifname); 692222972Shrs goto getconfig_free_rti; 69378064Sume } 69478064Sume if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 69578064Sume syslog(LOG_NOTICE, 696222732Shrs "<%s> link-local route (%s) will " 697222732Shrs "be advertised on %s", 698224144Shrs __func__, addr, ifi->ifi_ifname); 699222972Shrs goto getconfig_free_rti; 70078064Sume } 70178064Sume#endif 702118968Sume 703118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtplen"); 704118968Sume /* XXX: 256 is a magic number for compatibility check. */ 705118968Sume MAYHAVE(val, entbuf, 256); 706118968Sume if (val == 256) { 707118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen"); 708118968Sume MAYHAVE(val, oentbuf, 256); 709222732Shrs if (val != 256) 710118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 711222732Shrs oentbuf, entbuf); 712222732Shrs else 713118968Sume val = 64; 714118968Sume } 715118968Sume if (val < 0 || val > 128) { 716224144Shrs syslog(LOG_ERR, "<%s> prefixlen (%" PRIu32 ") for %s on %s " 717222732Shrs "out of range", 718224144Shrs __func__, val, addr, ifi->ifi_ifname); 719222972Shrs goto getconfig_free_rti; 720118968Sume } 721222732Shrs rti->rti_prefixlen = (int)val; 722118968Sume 723118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtflags"); 724118968Sume if ((flagstr = (char *)agetstr(entbuf, &bp))) { 725118968Sume val = 0; 726118968Sume if (strchr(flagstr, 'h')) 727118968Sume val |= ND_RA_FLAG_RTPREF_HIGH; 728118968Sume if (strchr(flagstr, 'l')) { 729118968Sume if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 730118968Sume syslog(LOG_ERR, 731118968Sume "<%s> the \'h\' and \'l\' route" 732118968Sume " preferences are exclusive", 733118968Sume __func__); 734222972Shrs goto getconfig_free_rti; 735118968Sume } 736118968Sume val |= ND_RA_FLAG_RTPREF_LOW; 737118968Sume } 738118968Sume } else 739118968Sume MAYHAVE(val, entbuf, 256); /* XXX */ 740118968Sume if (val == 256) { 741118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags"); 742118968Sume MAYHAVE(val, oentbuf, 256); 743118968Sume if (val != 256) { 744118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 745222732Shrs oentbuf, entbuf); 746118968Sume } else 747118968Sume val = 0; 748118968Sume } 749222732Shrs rti->rti_rtpref = val & ND_RA_FLAG_RTPREF_MASK; 750222732Shrs if (rti->rti_rtpref == ND_RA_FLAG_RTPREF_RSV) { 751118968Sume syslog(LOG_ERR, "<%s> invalid route preference (%02x) " 752222732Shrs "for %s/%d on %s", 753222732Shrs __func__, rti->rti_rtpref, addr, 754224144Shrs rti->rti_prefixlen, ifi->ifi_ifname); 755222972Shrs goto getconfig_free_rti; 756118968Sume } 757118968Sume 758118968Sume /* 759118968Sume * Since the spec does not a default value, we should make 760118968Sume * this entry mandatory. However, FreeBSD 4.4 has shipped 761118968Sume * with this field being optional, we use the router lifetime 762118968Sume * as an ad-hoc default value with a warning message. 763118968Sume */ 764118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtltime"); 765118968Sume MAYHAVE(val64, entbuf, -1); 766118968Sume if (val64 == -1) { 767118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime"); 768118968Sume MAYHAVE(val64, oentbuf, -1); 769222732Shrs if (val64 != -1) 770118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 771222732Shrs oentbuf, entbuf); 772222732Shrs else { 773118968Sume fprintf(stderr, "%s should be specified " 774224144Shrs "for interface %s.\n", entbuf, 775224144Shrs ifi->ifi_ifname); 776222732Shrs val64 = rai->rai_lifetime; 777118968Sume } 778118968Sume } 779118968Sume if (val64 < 0 || val64 > 0xffffffff) { 780224144Shrs syslog(LOG_ERR, "<%s> route lifetime (%" PRIu64 ") for " 781118968Sume "%s/%d on %s out of range", __func__, 782224144Shrs val64, addr, rti->rti_prefixlen, 783224144Shrs ifi->ifi_ifname); 784222972Shrs goto getconfig_free_rti; 785118968Sume } 786224144Shrs rti->rti_ltime = (uint32_t)val64; 787222972Shrs 788222972Shrs /* link into chain */ 789222972Shrs TAILQ_INSERT_TAIL(&rai->rai_route, rti, rti_next); 790222972Shrs rai->rai_routes++; 791222972Shrs continue; 792222972Shrsgetconfig_free_rti: 793222972Shrs free(rti); 79478064Sume } 795224144Shrs 796222732Shrs /* DNS server and DNS search list information */ 797222732Shrs for (i = -1; i < MAXRDNSSENT ; i++) { 798222732Shrs struct rdnss *rdn; 799222732Shrs struct rdnss_addr *rdna; 800222732Shrs char *ap; 801222732Shrs int c; 80278064Sume 803222732Shrs makeentry(entbuf, sizeof(entbuf), i, "rdnss"); 804222732Shrs addr = (char *)agetstr(entbuf, &bp); 805222732Shrs if (addr == NULL) 806222732Shrs break; 807222732Shrs ELM_MALLOC(rdn, exit(1)); 80855505Sshin 809222732Shrs TAILQ_INIT(&rdn->rd_list); 810222732Shrs 811222732Shrs for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 812222732Shrs c = strcspn(ap, ","); 813222732Shrs strncpy(abuf, ap, c); 814222732Shrs abuf[c] = '\0'; 815222972Shrs ELM_MALLOC(rdna, goto getconfig_free_rdn); 816222732Shrs if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) { 817222732Shrs syslog(LOG_ERR, "<%s> inet_pton failed for %s", 818222732Shrs __func__, abuf); 819222732Shrs free(rdna); 820222972Shrs goto getconfig_free_rdn; 821222732Shrs } 822222732Shrs TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next); 823222732Shrs } 824222732Shrs 825222732Shrs makeentry(entbuf, sizeof(entbuf), i, "rdnssltime"); 826222732Shrs MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2)); 827224144Shrs if ((uint16_t)val < rai->rai_maxinterval || 828224144Shrs (uint16_t)val > rai->rai_maxinterval * 2) { 829224144Shrs syslog(LOG_ERR, "%s (%" PRIu16 ") on %s is invalid " 830222732Shrs "(must be between %d and %d)", 831224144Shrs entbuf, val, ifi->ifi_ifname, rai->rai_maxinterval, 832222732Shrs rai->rai_maxinterval * 2); 833222972Shrs goto getconfig_free_rdn; 834222732Shrs } 835222732Shrs rdn->rd_ltime = val; 836222732Shrs 837222732Shrs /* link into chain */ 838222732Shrs TAILQ_INSERT_TAIL(&rai->rai_rdnss, rdn, rd_next); 839222972Shrs continue; 840222972Shrsgetconfig_free_rdn: 841222972Shrs while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) { 842222972Shrs TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next); 843222972Shrs free(rdna); 844222972Shrs } 845222972Shrs free(rdn); 846222732Shrs } 847222732Shrs 848222732Shrs for (i = -1; i < MAXDNSSLENT ; i++) { 849222732Shrs struct dnssl *dns; 850222732Shrs struct dnssl_addr *dnsa; 851222732Shrs char *ap; 852222732Shrs int c; 853222732Shrs 854222732Shrs makeentry(entbuf, sizeof(entbuf), i, "dnssl"); 855222732Shrs addr = (char *)agetstr(entbuf, &bp); 856222732Shrs if (addr == NULL) 857222732Shrs break; 858222732Shrs 859222732Shrs ELM_MALLOC(dns, exit(1)); 860222732Shrs 861222732Shrs TAILQ_INIT(&dns->dn_list); 862222732Shrs 863222732Shrs for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 864222732Shrs c = strcspn(ap, ","); 865222732Shrs strncpy(abuf, ap, c); 866222732Shrs abuf[c] = '\0'; 867222972Shrs ELM_MALLOC(dnsa, goto getconfig_free_dns); 868222732Shrs dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf); 869222732Shrs syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__, 870222732Shrs dnsa->da_len); 871222732Shrs TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next); 872222732Shrs } 873222732Shrs 874222732Shrs makeentry(entbuf, sizeof(entbuf), i, "dnsslltime"); 875222732Shrs MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2)); 876224144Shrs if ((uint16_t)val < rai->rai_maxinterval || 877224144Shrs (uint16_t)val > rai->rai_maxinterval * 2) { 878224144Shrs syslog(LOG_ERR, "%s (%" PRIu16 ") on %s is invalid " 879222732Shrs "(must be between %d and %d)", 880224144Shrs entbuf, val, ifi->ifi_ifname, rai->rai_maxinterval, 881222732Shrs rai->rai_maxinterval * 2); 882222972Shrs goto getconfig_free_dns; 883222732Shrs } 884222732Shrs dns->dn_ltime = val; 885222732Shrs 886222732Shrs /* link into chain */ 887222732Shrs TAILQ_INSERT_TAIL(&rai->rai_dnssl, dns, dn_next); 888222972Shrs continue; 889222972Shrsgetconfig_free_dns: 890222972Shrs while ((dnsa = TAILQ_FIRST(&dns->dn_list)) != NULL) { 891222972Shrs TAILQ_REMOVE(&dns->dn_list, dnsa, da_next); 892222972Shrs free(dnsa); 893222972Shrs } 894222972Shrs free(dns); 895222732Shrs } 89655505Sshin /* construct the sending packet */ 897222732Shrs make_packet(rai); 898222972Shrs 899222972Shrs /* 900222972Shrs * If an entry with the same ifindex exists, remove it first. 901222972Shrs * Before the removal, RDNSS and DNSSL options with 902222972Shrs * zero-lifetime will be sent. 903222972Shrs */ 904224144Shrs switch (ifi->ifi_state) { 905224144Shrs case IFI_STATE_UNCONFIGURED: 906224144Shrs /* UNCONFIGURED -> TRANSITIVE */ 907222972Shrs 908224144Shrs error = sock_mc_join(&sock, ifi->ifi_ifindex); 909224144Shrs if (error) 910224144Shrs exit(1); 911222972Shrs 912224144Shrs ifi->ifi_state = IFI_STATE_TRANSITIVE; 913224144Shrs ifi->ifi_burstcount = MAX_INITIAL_RTR_ADVERTISEMENTS; 914224144Shrs ifi->ifi_burstinterval = MAX_INITIAL_RTR_ADVERT_INTERVAL; 915224144Shrs 916224144Shrs /* The same two rai mean initial burst */ 917224144Shrs ifi->ifi_rainfo = rai; 918224144Shrs ifi->ifi_rainfo_trans = rai; 919224144Shrs TAILQ_INSERT_TAIL(&railist, rai, rai_next); 920224144Shrs 921224144Shrs if (ifi->ifi_ra_timer == NULL) 922224144Shrs ifi->ifi_ra_timer = rtadvd_add_timer(ra_timeout, 923224144Shrs ra_timer_update, ifi, ifi); 924224144Shrs ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm); 925224144Shrs rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm, 926224144Shrs ifi->ifi_ra_timer); 927224144Shrs 928224144Shrs syslog(LOG_DEBUG, 929224144Shrs "<%s> ifname=%s marked as TRANSITIVE (initial burst).", 930224144Shrs __func__, ifi->ifi_ifname); 931224144Shrs break; 932224144Shrs case IFI_STATE_CONFIGURED: 933224144Shrs /* CONFIGURED -> TRANSITIVE */ 934224144Shrs rai_old = ifi->ifi_rainfo; 935224144Shrs if (rai_old == NULL) { 936224144Shrs syslog(LOG_ERR, 937224144Shrs "<%s> ifi_rainfo is NULL" 938224144Shrs " in IFI_STATE_CONFIGURED.", __func__); 939224144Shrs ifi = NULL; 940224144Shrs break; 941224144Shrs } else { 942224144Shrs struct rdnss *rdn; 943224144Shrs struct dnssl *dns; 944224144Shrs 945224144Shrs rai_old->rai_lifetime = 0; 946224144Shrs TAILQ_FOREACH(rdn, &rai_old->rai_rdnss, rd_next) 947224144Shrs rdn->rd_ltime = 0; 948224144Shrs TAILQ_FOREACH(dns, &rai_old->rai_dnssl, dn_next) 949224144Shrs dns->dn_ltime = 0; 950224144Shrs 951224144Shrs ifi->ifi_rainfo_trans = rai_old; 952224144Shrs ifi->ifi_state = IFI_STATE_TRANSITIVE; 953224144Shrs ifi->ifi_burstcount = MAX_FINAL_RTR_ADVERTISEMENTS; 954224144Shrs ifi->ifi_burstinterval = MIN_DELAY_BETWEEN_RAS; 955224144Shrs 956224144Shrs ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm); 957224144Shrs rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm, 958224144Shrs ifi->ifi_ra_timer); 959224144Shrs 960224144Shrs syslog(LOG_DEBUG, 961224144Shrs "<%s> ifname=%s marked as TRANSITIVE" 962224144Shrs " (transitional burst)", 963224144Shrs __func__, ifi->ifi_ifname); 964222972Shrs } 965224144Shrs ifi->ifi_rainfo = rai; 966224144Shrs TAILQ_INSERT_TAIL(&railist, rai, rai_next); 967224144Shrs break; 968224144Shrs case IFI_STATE_TRANSITIVE: 969224144Shrs if (ifi->ifi_rainfo != NULL) { 970224144Shrs if (ifi->ifi_rainfo == ifi->ifi_rainfo_trans) { 971224144Shrs /* Reinitialize initial burst */ 972224144Shrs rm_rainfo(ifi->ifi_rainfo); 973224144Shrs ifi->ifi_rainfo = rai; 974224144Shrs ifi->ifi_rainfo_trans = rai; 975224144Shrs ifi->ifi_burstcount = 976224144Shrs MAX_INITIAL_RTR_ADVERTISEMENTS; 977224144Shrs ifi->ifi_burstinterval = 978224144Shrs MAX_INITIAL_RTR_ADVERT_INTERVAL; 979224144Shrs } else { 980224144Shrs /* Replace ifi_rainfo with the new one */ 981224144Shrs rm_rainfo(ifi->ifi_rainfo); 982224144Shrs ifi->ifi_rainfo = rai; 983224144Shrs } 984224144Shrs TAILQ_INSERT_TAIL(&railist, rai, rai_next); 985224144Shrs 986224144Shrs ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm); 987224144Shrs rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm, 988224144Shrs ifi->ifi_ra_timer); 989224144Shrs } else { 990224144Shrs /* XXX: NOTREACHED. Being shut down. */ 991224144Shrs syslog(LOG_ERR, 992224144Shrs "<%s> %s is shutting down. Skipped.", 993224144Shrs __func__, ifi->ifi_ifname); 994224144Shrs rm_rainfo(rai); 995224144Shrs 996224144Shrs return (NULL); 997224144Shrs } 998224144Shrs break; 999222972Shrs } 100055505Sshin 1001224144Shrs return (ifi); 1002222732Shrs 1003222972Shrsgetconfig_free_rai: 1004222972Shrs free(rai); 1005224144Shrs return (NULL); 100655505Sshin} 100755505Sshin 1008118968Sumevoid 100955505Sshinget_prefix(struct rainfo *rai) 101055505Sshin{ 101178064Sume struct ifaddrs *ifap, *ifa; 1012222732Shrs struct prefix *pfx; 101378064Sume struct in6_addr *a; 1014224144Shrs struct ifinfo *ifi; 1015224144Shrs char *p, *ep, *m, *lim; 1016224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 101755505Sshin 101878064Sume if (getifaddrs(&ifap) < 0) { 101955505Sshin syslog(LOG_ERR, 1020222732Shrs "<%s> can't get interface addresses", 1021222732Shrs __func__); 102255505Sshin exit(1); 102355505Sshin } 1024224144Shrs ifi = rai->rai_ifinfo; 1025118664Sume 102678064Sume for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 102797719Sume int plen; 102897719Sume 1029224144Shrs if (strcmp(ifa->ifa_name, ifi->ifi_ifname) != 0) 103078064Sume continue; 103178064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 103278064Sume continue; 103378064Sume a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 103478064Sume if (IN6_IS_ADDR_LINKLOCAL(a)) 103578064Sume continue; 1036224144Shrs 103797719Sume /* get prefix length */ 1038224144Shrs m = (char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 1039224144Shrs lim = (char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 104097719Sume plen = prefixlen(m, lim); 1041118968Sume if (plen <= 0 || plen > 128) { 104297719Sume syslog(LOG_ERR, "<%s> failed to get prefixlen " 1043222732Shrs "or prefix is invalid", 1044222732Shrs __func__); 104597719Sume exit(1); 104697719Sume } 1047118968Sume if (plen == 128) /* XXX */ 1048118968Sume continue; 104997719Sume if (find_prefix(rai, a, plen)) { 105097719Sume /* ignore a duplicated prefix. */ 105197719Sume continue; 105297719Sume } 105397719Sume 105455505Sshin /* allocate memory to store prefix info. */ 1055222732Shrs ELM_MALLOC(pfx, exit(1)); 105655505Sshin 105778064Sume /* set prefix, sweep bits outside of prefixlen */ 1058222732Shrs pfx->pfx_prefixlen = plen; 1059222732Shrs memcpy(&pfx->pfx_prefix, a, sizeof(*a)); 1060224144Shrs p = (char *)&pfx->pfx_prefix; 1061224144Shrs ep = (char *)(&pfx->pfx_prefix + 1); 1062157047Ssuz while (m < lim && p < ep) 106378064Sume *p++ &= *m++; 106478064Sume while (p < ep) 106578064Sume *p++ = 0x00; 1066222732Shrs if (!inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 106778064Sume sizeof(ntopbuf))) { 1068118660Sume syslog(LOG_ERR, "<%s> inet_ntop failed", __func__); 106978064Sume exit(1); 107078064Sume } 107155505Sshin syslog(LOG_DEBUG, 1072222732Shrs "<%s> add %s/%d to prefix list on %s", 1073224144Shrs __func__, ntopbuf, pfx->pfx_prefixlen, ifi->ifi_ifname); 107455505Sshin 107555505Sshin /* set other fields with protocol defaults */ 1076222732Shrs pfx->pfx_validlifetime = DEF_ADVVALIDLIFETIME; 1077222732Shrs pfx->pfx_preflifetime = DEF_ADVPREFERREDLIFETIME; 1078222732Shrs pfx->pfx_onlinkflg = 1; 1079222732Shrs pfx->pfx_autoconfflg = 1; 1080222732Shrs pfx->pfx_origin = PREFIX_FROM_KERNEL; 1081222732Shrs pfx->pfx_rainfo = rai; 108255505Sshin 108355505Sshin /* link into chain */ 1084222732Shrs TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 108555505Sshin 108655505Sshin /* counter increment */ 1087222732Shrs rai->rai_pfxs++; 108855505Sshin } 108955505Sshin 109078064Sume freeifaddrs(ifap); 109155505Sshin} 109255505Sshin 109355505Sshinstatic void 1094222732Shrsmakeentry(char *buf, size_t len, int id, const char *string) 109555505Sshin{ 109697709Sume 1097118968Sume if (id < 0) 1098118968Sume strlcpy(buf, string, len); 1099118968Sume else 1100118968Sume snprintf(buf, len, "%s%d", string, id); 110155505Sshin} 110255505Sshin 110355505Sshin/* 110455505Sshin * Add a prefix to the list of specified interface and reconstruct 110555505Sshin * the outgoing packet. 110655505Sshin * The prefix must not be in the list. 1107152538Ssuz * XXX: other parameters of the prefix (e.g. lifetime) should be 110855505Sshin * able to be specified. 110955505Sshin */ 111055505Sshinstatic void 111155505Sshinadd_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 111255505Sshin{ 1113222732Shrs struct prefix *pfx; 1114224144Shrs struct ifinfo *ifi; 1115224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 111655505Sshin 1117224144Shrs ifi = rai->rai_ifinfo; 1118222732Shrs ELM_MALLOC(pfx, return); 1119222732Shrs pfx->pfx_prefix = ipr->ipr_prefix.sin6_addr; 1120222732Shrs pfx->pfx_prefixlen = ipr->ipr_plen; 1121222732Shrs pfx->pfx_validlifetime = ipr->ipr_vltime; 1122222732Shrs pfx->pfx_preflifetime = ipr->ipr_pltime; 1123222732Shrs pfx->pfx_onlinkflg = ipr->ipr_raf_onlink; 1124222732Shrs pfx->pfx_autoconfflg = ipr->ipr_raf_auto; 1125222732Shrs pfx->pfx_origin = PREFIX_FROM_DYNAMIC; 1126254684Sdes pfx->pfx_rainfo = rai; 112755505Sshin 1128222732Shrs TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 112955505Sshin 113055505Sshin syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 1131222732Shrs __func__, 1132222732Shrs inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 1133224144Shrs sizeof(ntopbuf)), ipr->ipr_plen, ifi->ifi_ifname); 113455505Sshin 1135222732Shrs rai->rai_pfxs++; 113655505Sshin} 113755505Sshin 113855505Sshin/* 113955505Sshin * Delete a prefix to the list of specified interface and reconstruct 114055505Sshin * the outgoing packet. 114162656Skris * The prefix must be in the list. 114255505Sshin */ 114355505Sshinvoid 1144222732Shrsdelete_prefix(struct prefix *pfx) 114555505Sshin{ 1146222732Shrs struct rainfo *rai; 1147224144Shrs struct ifinfo *ifi; 1148224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 114955505Sshin 1150222732Shrs rai = pfx->pfx_rainfo; 1151224144Shrs ifi = rai->rai_ifinfo; 1152222732Shrs TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next); 115355505Sshin syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 1154222732Shrs __func__, 1155222732Shrs inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 1156224144Shrs sizeof(ntopbuf)), pfx->pfx_prefixlen, ifi->ifi_ifname); 1157222732Shrs if (pfx->pfx_timer) 1158222732Shrs rtadvd_remove_timer(pfx->pfx_timer); 1159222732Shrs free(pfx); 1160224144Shrs 1161222732Shrs rai->rai_pfxs--; 116255505Sshin} 116355505Sshin 116498172Sumevoid 1165222732Shrsinvalidate_prefix(struct prefix *pfx) 116698172Sume{ 1167253970Shrs struct timespec timo; 1168222732Shrs struct rainfo *rai; 1169224144Shrs struct ifinfo *ifi; 1170224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 117198172Sume 1172222732Shrs rai = pfx->pfx_rainfo; 1173224144Shrs ifi = rai->rai_ifinfo; 1174222732Shrs if (pfx->pfx_timer) { /* sanity check */ 117598172Sume syslog(LOG_ERR, 117698172Sume "<%s> assumption failure: timer already exists", 1177118660Sume __func__); 117898172Sume exit(1); 117998172Sume } 118098172Sume 118198172Sume syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " 1182118660Sume "will expire in %ld seconds", __func__, 1183222732Shrs inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, sizeof(ntopbuf)), 1184224144Shrs pfx->pfx_prefixlen, ifi->ifi_ifname, (long)prefix_timo); 118598172Sume 118698172Sume /* set the expiration timer */ 1187222732Shrs pfx->pfx_timer = rtadvd_add_timer(prefix_timeout, NULL, pfx, NULL); 1188222732Shrs if (pfx->pfx_timer == NULL) { 118998172Sume syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. " 1190118660Sume "remove the prefix", __func__); 1191222732Shrs delete_prefix(pfx); 119298172Sume } 119398172Sume timo.tv_sec = prefix_timo; 1194253970Shrs timo.tv_nsec = 0; 1195222732Shrs rtadvd_set_timer(&timo, pfx->pfx_timer); 119698172Sume} 119798172Sume 119898172Sumestatic struct rtadvd_timer * 119998172Sumeprefix_timeout(void *arg) 120098172Sume{ 120198172Sume 1202222732Shrs delete_prefix((struct prefix *)arg); 1203222732Shrs 1204222732Shrs return (NULL); 120598172Sume} 120698172Sume 120798172Sumevoid 1208222732Shrsupdate_prefix(struct prefix *pfx) 120998172Sume{ 1210222732Shrs struct rainfo *rai; 1211224144Shrs struct ifinfo *ifi; 1212224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 121398172Sume 1214222732Shrs rai = pfx->pfx_rainfo; 1215224144Shrs ifi = rai->rai_ifinfo; 1216222732Shrs if (pfx->pfx_timer == NULL) { /* sanity check */ 121798172Sume syslog(LOG_ERR, 121898172Sume "<%s> assumption failure: timer does not exist", 1219118660Sume __func__); 122098172Sume exit(1); 122198172Sume } 122298172Sume 122398172Sume syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", 1224222732Shrs __func__, inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 1225224144Shrs sizeof(ntopbuf)), pfx->pfx_prefixlen, ifi->ifi_ifname); 122698172Sume 122798172Sume /* stop the expiration timer */ 1228222732Shrs rtadvd_remove_timer(pfx->pfx_timer); 1229222732Shrs pfx->pfx_timer = NULL; 123098172Sume} 123198172Sume 123255505Sshin/* 123355505Sshin * Try to get an in6_prefixreq contents for a prefix which matches 123455505Sshin * ipr->ipr_prefix and ipr->ipr_plen and belongs to 123555505Sshin * the interface whose name is ipr->ipr_name[]. 123655505Sshin */ 123755505Sshinstatic int 123855505Sshininit_prefix(struct in6_prefixreq *ipr) 123955505Sshin{ 124098262Sume#if 0 124155505Sshin int s; 124255505Sshin 124355505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1244118660Sume syslog(LOG_ERR, "<%s> socket: %s", __func__, 1245222732Shrs strerror(errno)); 124655505Sshin exit(1); 124755505Sshin } 124855505Sshin 124955505Sshin if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 1250118660Sume syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__, 1251222732Shrs strerror(errno)); 125255505Sshin 125355505Sshin ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 125455505Sshin ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 125555505Sshin ipr->ipr_raf_onlink = 1; 125655505Sshin ipr->ipr_raf_auto = 1; 125755505Sshin /* omit other field initialization */ 125855505Sshin } 125955505Sshin else if (ipr->ipr_origin < PR_ORIG_RR) { 1260224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 126155505Sshin 126255505Sshin syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 1263222732Shrs "lower than PR_ORIG_RR(router renumbering)." 1264222732Shrs "This should not happen if I am router", __func__, 1265222732Shrs inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 1266222732Shrs sizeof(ntopbuf)), ipr->ipr_origin); 126757852Sshin close(s); 1268222732Shrs return (1); 126955505Sshin } 127055505Sshin 127155505Sshin close(s); 1272222732Shrs return (0); 127398262Sume#else 127498262Sume ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 127598262Sume ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 127698262Sume ipr->ipr_raf_onlink = 1; 127798262Sume ipr->ipr_raf_auto = 1; 1278222732Shrs return (0); 127998262Sume#endif 128055505Sshin} 128155505Sshin 128255505Sshinvoid 128355505Sshinmake_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 128455505Sshin{ 128555505Sshin struct in6_prefixreq ipr; 128655505Sshin 128755505Sshin memset(&ipr, 0, sizeof(ipr)); 128855505Sshin if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 1289253057Shrs syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't " 1290222732Shrs "exist. This should not happen! %s", __func__, 1291222732Shrs ifindex, strerror(errno)); 129255505Sshin exit(1); 129355505Sshin } 129455505Sshin ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 129555505Sshin ipr.ipr_prefix.sin6_family = AF_INET6; 129655505Sshin ipr.ipr_prefix.sin6_addr = *addr; 129755505Sshin ipr.ipr_plen = plen; 129855505Sshin 129955505Sshin if (init_prefix(&ipr)) 130055505Sshin return; /* init failed by some error */ 130155505Sshin add_prefix(rai, &ipr); 130255505Sshin} 130355505Sshin 130462656Skrisvoid 1305222732Shrsmake_packet(struct rainfo *rai) 130655505Sshin{ 130755505Sshin size_t packlen, lladdroptlen = 0; 130855505Sshin char *buf; 130955505Sshin struct nd_router_advert *ra; 131055505Sshin struct nd_opt_prefix_info *ndopt_pi; 131155505Sshin struct nd_opt_mtu *ndopt_mtu; 131278064Sume struct nd_opt_route_info *ndopt_rti; 1313118968Sume struct rtinfo *rti; 1314222732Shrs struct nd_opt_rdnss *ndopt_rdnss; 1315222732Shrs struct rdnss *rdn; 1316222732Shrs struct nd_opt_dnssl *ndopt_dnssl; 1317222732Shrs struct dnssl *dns; 1318222732Shrs size_t len; 131955505Sshin struct prefix *pfx; 1320224144Shrs struct ifinfo *ifi; 132155505Sshin 1322224144Shrs ifi = rai->rai_ifinfo; 132355505Sshin /* calculate total length */ 132455505Sshin packlen = sizeof(struct nd_router_advert); 1325222732Shrs if (rai->rai_advlinkopt) { 1326224144Shrs if ((lladdroptlen = lladdropt_length(&ifi->ifi_sdl)) == 0) { 132755505Sshin syslog(LOG_INFO, 1328222732Shrs "<%s> link-layer address option has" 1329222732Shrs " null length on %s. Treat as not included.", 1330224144Shrs __func__, ifi->ifi_ifname); 1331222732Shrs rai->rai_advlinkopt = 0; 133255505Sshin } 133355505Sshin packlen += lladdroptlen; 133455505Sshin } 1335222732Shrs if (rai->rai_pfxs) 1336222732Shrs packlen += sizeof(struct nd_opt_prefix_info) * rai->rai_pfxs; 1337222732Shrs if (rai->rai_linkmtu) 133855505Sshin packlen += sizeof(struct nd_opt_mtu); 1339224144Shrs 1340222732Shrs TAILQ_FOREACH(rti, &rai->rai_route, rti_next) 1341222732Shrs packlen += sizeof(struct nd_opt_route_info) + 1342222732Shrs ((rti->rti_prefixlen + 0x3f) >> 6) * 8; 1343224144Shrs 1344222732Shrs TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { 1345222732Shrs struct rdnss_addr *rdna; 134655505Sshin 1347222732Shrs packlen += sizeof(struct nd_opt_rdnss); 1348222732Shrs TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) 1349222732Shrs packlen += sizeof(rdna->ra_dns); 1350222732Shrs } 1351222732Shrs TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { 1352222732Shrs struct dnssl_addr *dnsa; 1353222732Shrs 1354222732Shrs packlen += sizeof(struct nd_opt_dnssl); 1355222732Shrs len = 0; 1356222732Shrs TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) 1357222732Shrs len += dnsa->da_len; 1358222732Shrs 1359222732Shrs /* A zero octet and 8 octet boundary */ 1360222732Shrs len++; 1361222732Shrs len += (len % 8) ? 8 - len % 8 : 0; 1362222732Shrs 1363222732Shrs packlen += len; 1364222732Shrs } 136555505Sshin /* allocate memory for the packet */ 136655505Sshin if ((buf = malloc(packlen)) == NULL) { 136755505Sshin syslog(LOG_ERR, 1368222732Shrs "<%s> can't get enough memory for an RA packet", 1369222732Shrs __func__); 137055505Sshin exit(1); 137155505Sshin } 1372222732Shrs memset(buf, 0, packlen); 1373222732Shrs if (rai->rai_ra_data) /* Free old data if any. */ 1374222732Shrs free(rai->rai_ra_data); 1375222732Shrs rai->rai_ra_data = buf; 137655505Sshin /* XXX: what if packlen > 576? */ 1377222732Shrs rai->rai_ra_datalen = packlen; 137855505Sshin 137955505Sshin /* 138055505Sshin * construct the packet 138155505Sshin */ 138255505Sshin ra = (struct nd_router_advert *)buf; 138355505Sshin ra->nd_ra_type = ND_ROUTER_ADVERT; 138455505Sshin ra->nd_ra_code = 0; 138555505Sshin ra->nd_ra_cksum = 0; 1386224144Shrs ra->nd_ra_curhoplimit = (uint8_t)(0xff & rai->rai_hoplimit); 138778064Sume ra->nd_ra_flags_reserved = 0; /* just in case */ 138878064Sume /* 138978064Sume * XXX: the router preference field, which is a 2-bit field, should be 139078064Sume * initialized before other fields. 139178064Sume */ 1392222732Shrs ra->nd_ra_flags_reserved = 0xff & rai->rai_rtpref; 139355505Sshin ra->nd_ra_flags_reserved |= 1394222732Shrs rai->rai_managedflg ? ND_RA_FLAG_MANAGED : 0; 139555505Sshin ra->nd_ra_flags_reserved |= 1396222732Shrs rai->rai_otherflg ? ND_RA_FLAG_OTHER : 0; 1397222732Shrs ra->nd_ra_router_lifetime = htons(rai->rai_lifetime); 1398222732Shrs ra->nd_ra_reachable = htonl(rai->rai_reachabletime); 1399222732Shrs ra->nd_ra_retransmit = htonl(rai->rai_retranstimer); 140055505Sshin buf += sizeof(*ra); 140155505Sshin 1402222732Shrs if (rai->rai_advlinkopt) { 1403224144Shrs lladdropt_fill(&ifi->ifi_sdl, (struct nd_opt_hdr *)buf); 140455505Sshin buf += lladdroptlen; 140555505Sshin } 140655505Sshin 1407222732Shrs if (rai->rai_linkmtu) { 140855505Sshin ndopt_mtu = (struct nd_opt_mtu *)buf; 140955505Sshin ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 141055505Sshin ndopt_mtu->nd_opt_mtu_len = 1; 141155505Sshin ndopt_mtu->nd_opt_mtu_reserved = 0; 1412222732Shrs ndopt_mtu->nd_opt_mtu_mtu = htonl(rai->rai_linkmtu); 141355505Sshin buf += sizeof(struct nd_opt_mtu); 141455505Sshin } 141555505Sshin 1416222732Shrs TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { 1417224144Shrs uint32_t vltime, pltime; 1418253970Shrs struct timespec now; 141978064Sume 142055505Sshin ndopt_pi = (struct nd_opt_prefix_info *)buf; 142155505Sshin ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 142255505Sshin ndopt_pi->nd_opt_pi_len = 4; 1423222732Shrs ndopt_pi->nd_opt_pi_prefix_len = pfx->pfx_prefixlen; 142455505Sshin ndopt_pi->nd_opt_pi_flags_reserved = 0; 1425222732Shrs if (pfx->pfx_onlinkflg) 142655505Sshin ndopt_pi->nd_opt_pi_flags_reserved |= 142755505Sshin ND_OPT_PI_FLAG_ONLINK; 1428222732Shrs if (pfx->pfx_autoconfflg) 142955505Sshin ndopt_pi->nd_opt_pi_flags_reserved |= 143055505Sshin ND_OPT_PI_FLAG_AUTO; 1431222732Shrs if (pfx->pfx_timer) 143298172Sume vltime = 0; 143398172Sume else { 1434222732Shrs if (pfx->pfx_vltimeexpire || pfx->pfx_pltimeexpire) 1435253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 1436222732Shrs if (pfx->pfx_vltimeexpire == 0) 1437222732Shrs vltime = pfx->pfx_validlifetime; 143898172Sume else 1439224144Shrs vltime = ((time_t)pfx->pfx_vltimeexpire > now.tv_sec) ? 1440222732Shrs pfx->pfx_vltimeexpire - now.tv_sec : 0; 144198172Sume } 1442222732Shrs if (pfx->pfx_timer) 144398172Sume pltime = 0; 144498172Sume else { 1445222732Shrs if (pfx->pfx_pltimeexpire == 0) 1446222732Shrs pltime = pfx->pfx_preflifetime; 144798172Sume else 1448224144Shrs pltime = ((time_t)pfx->pfx_pltimeexpire > now.tv_sec) ? 1449222732Shrs pfx->pfx_pltimeexpire - now.tv_sec : 0; 145098172Sume } 145178064Sume if (vltime < pltime) { 145278064Sume /* 145378064Sume * this can happen if vltime is decrement but pltime 145478064Sume * is not. 145578064Sume */ 145678064Sume pltime = vltime; 145778064Sume } 145878064Sume ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 145978064Sume ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 146055505Sshin ndopt_pi->nd_opt_pi_reserved2 = 0; 1461222732Shrs ndopt_pi->nd_opt_pi_prefix = pfx->pfx_prefix; 146255505Sshin 146355505Sshin buf += sizeof(struct nd_opt_prefix_info); 146455505Sshin } 146555505Sshin 1466222732Shrs TAILQ_FOREACH(rti, &rai->rai_route, rti_next) { 1467224144Shrs uint8_t psize = (rti->rti_prefixlen + 0x3f) >> 6; 146878064Sume 146978064Sume ndopt_rti = (struct nd_opt_route_info *)buf; 147078064Sume ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 147178064Sume ndopt_rti->nd_opt_rti_len = 1 + psize; 1472222732Shrs ndopt_rti->nd_opt_rti_prefixlen = rti->rti_prefixlen; 1473222732Shrs ndopt_rti->nd_opt_rti_flags = 0xff & rti->rti_rtpref; 1474222732Shrs ndopt_rti->nd_opt_rti_lifetime = htonl(rti->rti_ltime); 1475222732Shrs memcpy(ndopt_rti + 1, &rti->rti_prefix, psize * 8); 147678064Sume buf += sizeof(struct nd_opt_route_info) + psize * 8; 147778064Sume } 1478224144Shrs 1479222732Shrs TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { 1480222732Shrs struct rdnss_addr *rdna; 148178064Sume 1482222732Shrs ndopt_rdnss = (struct nd_opt_rdnss *)buf; 1483222732Shrs ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; 1484222732Shrs ndopt_rdnss->nd_opt_rdnss_len = 0; 1485222732Shrs ndopt_rdnss->nd_opt_rdnss_reserved = 0; 1486222732Shrs ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdn->rd_ltime); 1487222732Shrs buf += sizeof(struct nd_opt_rdnss); 148878064Sume 1489222732Shrs TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) { 1490222732Shrs memcpy(buf, &rdna->ra_dns, sizeof(rdna->ra_dns)); 1491222732Shrs buf += sizeof(rdna->ra_dns); 1492222732Shrs } 1493222732Shrs /* Length field should be in 8 octets */ 1494222732Shrs ndopt_rdnss->nd_opt_rdnss_len = (buf - (char *)ndopt_rdnss) / 8; 149578064Sume 1496222732Shrs syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__, 1497222732Shrs ndopt_rdnss->nd_opt_rdnss_len); 149878064Sume } 1499224144Shrs 1500222732Shrs TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { 1501222732Shrs struct dnssl_addr *dnsa; 1502222732Shrs 1503222732Shrs ndopt_dnssl = (struct nd_opt_dnssl *)buf; 1504222732Shrs ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL; 1505222732Shrs ndopt_dnssl->nd_opt_dnssl_len = 0; 1506222732Shrs ndopt_dnssl->nd_opt_dnssl_reserved = 0; 1507222732Shrs ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dns->dn_ltime); 1508222732Shrs buf += sizeof(*ndopt_dnssl); 1509222732Shrs 1510222732Shrs TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) { 1511222732Shrs memcpy(buf, dnsa->da_dom, dnsa->da_len); 1512222732Shrs buf += dnsa->da_len; 1513222732Shrs } 1514222732Shrs 1515222732Shrs /* A zero octet after encoded DNS server list. */ 1516222732Shrs *buf++ = '\0'; 1517222732Shrs 1518222732Shrs /* Padding to next 8 octets boundary */ 1519222732Shrs len = buf - (char *)ndopt_dnssl; 1520222732Shrs len += (len % 8) ? 8 - len % 8 : 0; 1521222732Shrs 1522222732Shrs /* Length field must be in 8 octets */ 1523222732Shrs ndopt_dnssl->nd_opt_dnssl_len = len / 8; 1524222732Shrs 1525222732Shrs syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__, 1526222732Shrs ndopt_dnssl->nd_opt_dnssl_len); 1527222732Shrs } 1528222732Shrs return; 152978064Sume} 1530