config.c revision 254684
171333Sitojun/* $FreeBSD: head/usr.sbin/rtadvd/config.c 254684 2013-08-23 10:57:05Z des $ */ 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 299222732Shrs while ((pfx = TAILQ_FIRST(&rai->rai_prefix)) != NULL) { 300222732Shrs TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next); 301222732Shrs free(pfx); 302222732Shrs } 303222732Shrs while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) { 304222732Shrs TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next); 305222732Shrs free(sol); 306222732Shrs } 307222732Shrs while ((rdn = TAILQ_FIRST(&rai->rai_rdnss)) != NULL) { 308222732Shrs TAILQ_REMOVE(&rai->rai_rdnss, rdn, rd_next); 309222732Shrs while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) { 310222732Shrs TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next); 311222732Shrs free(rdna); 312222732Shrs } 313222732Shrs free(rdn); 314222732Shrs } 315222732Shrs while ((dns = TAILQ_FIRST(&rai->rai_dnssl)) != NULL) { 316222732Shrs TAILQ_REMOVE(&rai->rai_dnssl, dns, dn_next); 317222732Shrs free(dns); 318222732Shrs } 319222732Shrs while ((rti = TAILQ_FIRST(&rai->rai_route)) != NULL) { 320222732Shrs TAILQ_REMOVE(&rai->rai_route, rti, rti_next); 321222732Shrs free(rti); 322222732Shrs } 323222732Shrs free(rai); 324224144Shrs syslog(LOG_DEBUG, "<%s>: leave", __func__); 325224144Shrs 326222732Shrs return (0); 327222732Shrs} 328222732Shrs 329224144Shrsstruct ifinfo * 330224144Shrsgetconfig(struct ifinfo *ifi) 331222732Shrs{ 332222732Shrs int stat, i; 333224144Shrs int error; 334222732Shrs char tbuf[BUFSIZ]; 335222732Shrs struct rainfo *rai; 336222972Shrs struct rainfo *rai_old; 337224144Shrs int32_t val; 338222732Shrs int64_t val64; 339222732Shrs char buf[BUFSIZ]; 340222732Shrs char *bp = buf; 341222732Shrs char *addr, *flagstr; 342222732Shrs 343224144Shrs if (ifi == NULL) /* if does not exist */ 344224144Shrs return (NULL); 345224144Shrs 346224144Shrs if (ifi->ifi_state == IFI_STATE_TRANSITIVE && 347224144Shrs ifi->ifi_rainfo == NULL) { 348224144Shrs syslog(LOG_INFO, "<%s> %s is shutting down. Skipped.", 349224144Shrs __func__, ifi->ifi_ifname); 350224144Shrs return (NULL); 351222732Shrs } 352222732Shrs 353224144Shrs if ((stat = agetent(tbuf, ifi->ifi_ifname)) <= 0) { 35455505Sshin memset(tbuf, 0, sizeof(tbuf)); 35555505Sshin syslog(LOG_INFO, 356222732Shrs "<%s> %s isn't defined in the configuration file" 357222732Shrs " or the configuration file doesn't exist." 358222732Shrs " Treat it as default", 359224144Shrs __func__, ifi->ifi_ifname); 36055505Sshin } 36155505Sshin 362222820Shrs ELM_MALLOC(rai, exit(1)); 363222732Shrs TAILQ_INIT(&rai->rai_prefix); 364222732Shrs TAILQ_INIT(&rai->rai_route); 365222732Shrs TAILQ_INIT(&rai->rai_rdnss); 366222732Shrs TAILQ_INIT(&rai->rai_dnssl); 367222732Shrs TAILQ_INIT(&rai->rai_soliciter); 368224144Shrs rai->rai_ifinfo = ifi; 36955505Sshin 370222732Shrs /* gather on-link prefixes from the network interfaces. */ 371222732Shrs if (agetflag("noifprefix")) 372222732Shrs rai->rai_advifprefix = 0; 373222732Shrs else 374222732Shrs rai->rai_advifprefix = 1; 37578064Sume 37655505Sshin /* get interface information */ 37755505Sshin if (agetflag("nolladdr")) 378222732Shrs rai->rai_advlinkopt = 0; 37955505Sshin else 380222732Shrs rai->rai_advlinkopt = 1; 381222732Shrs if (rai->rai_advlinkopt) { 382224144Shrs if (ifi->ifi_sdl.sdl_type == 0) { 38355505Sshin syslog(LOG_ERR, 384222732Shrs "<%s> can't get information of %s", 385224144Shrs __func__, ifi->ifi_ifname); 386222972Shrs goto getconfig_free_rai; 38755505Sshin } 38855505Sshin } 38955505Sshin 39055505Sshin /* 39155505Sshin * set router configuration variables. 39255505Sshin */ 39355505Sshin MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 39455505Sshin if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 39555505Sshin syslog(LOG_ERR, 396224144Shrs "<%s> maxinterval (%" PRIu32 ") on %s is invalid " 397222732Shrs "(must be between %u and %u)", __func__, val, 398224144Shrs ifi->ifi_ifname, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 399222972Shrs goto getconfig_free_rai; 40055505Sshin } 401224144Shrs rai->rai_maxinterval = (uint16_t)val; 402222732Shrs 403222732Shrs MAYHAVE(val, "mininterval", rai->rai_maxinterval/3); 404224144Shrs if ((uint16_t)val < MIN_MININTERVAL || 405224144Shrs (uint16_t)val > (rai->rai_maxinterval * 3) / 4) { 40655505Sshin syslog(LOG_ERR, 407224144Shrs "<%s> mininterval (%" PRIu32 ") on %s is invalid " 408222732Shrs "(must be between %d and %d)", 409224144Shrs __func__, val, ifi->ifi_ifname, MIN_MININTERVAL, 410222732Shrs (rai->rai_maxinterval * 3) / 4); 411222972Shrs goto getconfig_free_rai; 41255505Sshin } 413224144Shrs rai->rai_mininterval = (uint16_t)val; 41455505Sshin 41555505Sshin MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 416222732Shrs rai->rai_hoplimit = val & 0xff; 41755505Sshin 418118968Sume if ((flagstr = (char *)agetstr("raflags", &bp))) { 419118968Sume val = 0; 420118968Sume if (strchr(flagstr, 'm')) 421118968Sume val |= ND_RA_FLAG_MANAGED; 422118968Sume if (strchr(flagstr, 'o')) 423118968Sume val |= ND_RA_FLAG_OTHER; 424118968Sume if (strchr(flagstr, 'h')) 425118968Sume val |= ND_RA_FLAG_RTPREF_HIGH; 426118968Sume if (strchr(flagstr, 'l')) { 427118968Sume if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 428118968Sume syslog(LOG_ERR, "<%s> the \'h\' and \'l\'" 429118968Sume " router flags are exclusive", __func__); 430222972Shrs goto getconfig_free_rai; 431118968Sume } 432118968Sume val |= ND_RA_FLAG_RTPREF_LOW; 433118968Sume } 434222732Shrs } else 435118968Sume MAYHAVE(val, "raflags", 0); 436222732Shrs 437222732Shrs rai->rai_managedflg = val & ND_RA_FLAG_MANAGED; 438222732Shrs rai->rai_otherflg = val & ND_RA_FLAG_OTHER; 43978064Sume#ifndef ND_RA_FLAG_RTPREF_MASK 44078064Sume#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 44178064Sume#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 44278064Sume#endif 443222732Shrs rai->rai_rtpref = val & ND_RA_FLAG_RTPREF_MASK; 444222732Shrs if (rai->rai_rtpref == ND_RA_FLAG_RTPREF_RSV) { 445118968Sume syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s", 446224144Shrs __func__, rai->rai_rtpref, ifi->ifi_ifname); 447222972Shrs goto getconfig_free_rai; 44878064Sume } 44955505Sshin 450222732Shrs MAYHAVE(val, "rltime", rai->rai_maxinterval * 3); 451224144Shrs if ((uint16_t)val && ((uint16_t)val < rai->rai_maxinterval || 452224144Shrs (uint16_t)val > MAXROUTERLIFETIME)) { 45355505Sshin syslog(LOG_ERR, 454224144Shrs "<%s> router lifetime (%" PRIu32 ") on %s is invalid " 455222732Shrs "(must be 0 or between %d and %d)", 456224144Shrs __func__, val, ifi->ifi_ifname, rai->rai_maxinterval, 457222732Shrs MAXROUTERLIFETIME); 458222972Shrs goto getconfig_free_rai; 45955505Sshin } 460222732Shrs rai->rai_lifetime = val & 0xffff; 46155505Sshin 46255505Sshin MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 463118968Sume if (val < 0 || val > MAXREACHABLETIME) { 46455505Sshin syslog(LOG_ERR, 465224144Shrs "<%s> reachable time (%" PRIu32 ") on %s is invalid " 466222732Shrs "(must be no greater than %d)", 467224144Shrs __func__, val, ifi->ifi_ifname, MAXREACHABLETIME); 468222972Shrs goto getconfig_free_rai; 46955505Sshin } 470224144Shrs rai->rai_reachabletime = (uint32_t)val; 47155505Sshin 47278064Sume MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 47378064Sume if (val64 < 0 || val64 > 0xffffffff) { 474224144Shrs syslog(LOG_ERR, "<%s> retrans time (%" PRIu64 ") on %s out of range", 475224144Shrs __func__, val64, ifi->ifi_ifname); 476222972Shrs goto getconfig_free_rai; 47755505Sshin } 478224144Shrs rai->rai_retranstimer = (uint32_t)val64; 47955505Sshin 480118968Sume if (agetnum("hapref") != -1 || agetnum("hatime") != -1) { 48178064Sume syslog(LOG_ERR, 482222732Shrs "<%s> mobile-ip6 configuration not supported", 483222732Shrs __func__); 484222972Shrs goto getconfig_free_rai; 48578064Sume } 48655505Sshin /* prefix information */ 48778064Sume 48878064Sume /* 489118664Sume * This is an implementation specific parameter to consider 49078064Sume * link propagation delays and poorly synchronized clocks when 49178064Sume * checking consistency of advertised lifetimes. 49278064Sume */ 49378064Sume MAYHAVE(val, "clockskew", 0); 494222732Shrs rai->rai_clockskew = val; 49578064Sume 496222732Shrs rai->rai_pfxs = 0; 497118968Sume for (i = -1; i < MAXPREFIX; i++) { 498118968Sume struct prefix *pfx; 499118968Sume 500118968Sume makeentry(entbuf, sizeof(entbuf), i, "addr"); 501118968Sume addr = (char *)agetstr(entbuf, &bp); 502118968Sume if (addr == NULL) 503118968Sume continue; 504118968Sume 505118968Sume /* allocate memory to store prefix information */ 506222732Shrs ELM_MALLOC(pfx, exit(1)); 507222820Shrs pfx->pfx_rainfo = rai; 508222732Shrs pfx->pfx_origin = PREFIX_FROM_CONFIG; 50971437Sume 510222732Shrs if (inet_pton(AF_INET6, addr, &pfx->pfx_prefix) != 1) { 511118968Sume syslog(LOG_ERR, 512222732Shrs "<%s> inet_pton failed for %s", 513222732Shrs __func__, addr); 514222972Shrs goto getconfig_free_pfx; 515118968Sume } 516222732Shrs if (IN6_IS_ADDR_MULTICAST(&pfx->pfx_prefix)) { 517118968Sume syslog(LOG_ERR, 518222732Shrs "<%s> multicast prefix (%s) must " 519222732Shrs "not be advertised on %s", 520224144Shrs __func__, addr, ifi->ifi_ifname); 521222972Shrs goto getconfig_free_pfx; 522118968Sume } 523222732Shrs if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix)) 524118968Sume syslog(LOG_NOTICE, 525222732Shrs "<%s> link-local prefix (%s) will be" 526222732Shrs " advertised on %s", 527224144Shrs __func__, addr, ifi->ifi_ifname); 52862656Skris 529118968Sume makeentry(entbuf, sizeof(entbuf), i, "prefixlen"); 530118968Sume MAYHAVE(val, entbuf, 64); 531118968Sume if (val < 0 || val > 128) { 532224144Shrs syslog(LOG_ERR, "<%s> prefixlen (%" PRIu32 ") for %s " 533222732Shrs "on %s out of range", 534224144Shrs __func__, val, addr, ifi->ifi_ifname); 535222972Shrs goto getconfig_free_pfx; 536118968Sume } 537222732Shrs pfx->pfx_prefixlen = (int)val; 53855505Sshin 539118968Sume makeentry(entbuf, sizeof(entbuf), i, "pinfoflags"); 540118968Sume if ((flagstr = (char *)agetstr(entbuf, &bp))) { 541118968Sume val = 0; 542118968Sume if (strchr(flagstr, 'l')) 543118968Sume val |= ND_OPT_PI_FLAG_ONLINK; 544118968Sume if (strchr(flagstr, 'a')) 545118968Sume val |= ND_OPT_PI_FLAG_AUTO; 546118968Sume } else { 547118968Sume MAYHAVE(val, entbuf, 548118968Sume (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 549118968Sume } 550222732Shrs pfx->pfx_onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 551222732Shrs pfx->pfx_autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 55255505Sshin 553118968Sume makeentry(entbuf, sizeof(entbuf), i, "vltime"); 554118968Sume MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 555118968Sume if (val64 < 0 || val64 > 0xffffffff) { 556224144Shrs syslog(LOG_ERR, "<%s> vltime (%" PRIu64 ") for " 557118968Sume "%s/%d on %s is out of range", 558224144Shrs __func__, val64, 559224144Shrs addr, pfx->pfx_prefixlen, ifi->ifi_ifname); 560222972Shrs goto getconfig_free_pfx; 561118968Sume } 562224144Shrs pfx->pfx_validlifetime = (uint32_t)val64; 56355505Sshin 564118968Sume makeentry(entbuf, sizeof(entbuf), i, "vltimedecr"); 565118968Sume if (agetflag(entbuf)) { 566253970Shrs struct timespec now; 567253970Shrs 568253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 569222732Shrs pfx->pfx_vltimeexpire = 570222732Shrs now.tv_sec + pfx->pfx_validlifetime; 571118968Sume } 57278064Sume 573118968Sume makeentry(entbuf, sizeof(entbuf), i, "pltime"); 574118968Sume MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 575118968Sume if (val64 < 0 || val64 > 0xffffffff) { 576118968Sume syslog(LOG_ERR, 577224144Shrs "<%s> pltime (%" PRIu64 ") for %s/%d on %s " 578118968Sume "is out of range", 579224144Shrs __func__, val64, 580224144Shrs addr, pfx->pfx_prefixlen, ifi->ifi_ifname); 581222972Shrs goto getconfig_free_pfx; 582118968Sume } 583224144Shrs pfx->pfx_preflifetime = (uint32_t)val64; 58455505Sshin 585118968Sume makeentry(entbuf, sizeof(entbuf), i, "pltimedecr"); 586118968Sume if (agetflag(entbuf)) { 587253970Shrs struct timespec now; 588253970Shrs 589253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 590222732Shrs pfx->pfx_pltimeexpire = 591222732Shrs now.tv_sec + pfx->pfx_preflifetime; 59255505Sshin } 593222820Shrs /* link into chain */ 594222820Shrs TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 595222820Shrs rai->rai_pfxs++; 596222972Shrs continue; 597222972Shrsgetconfig_free_pfx: 598222972Shrs free(pfx); 59955505Sshin } 600222732Shrs if (rai->rai_advifprefix && rai->rai_pfxs == 0) 601222732Shrs get_prefix(rai); 60255505Sshin 603224144Shrs MAYHAVE(val64, "mtu", 0); 604224144Shrs if (val < 0 || val64 > 0xffffffff) { 60555505Sshin syslog(LOG_ERR, 606224144Shrs "<%s> mtu (%" PRIu64 ") on %s out of range", 607224144Shrs __func__, val64, ifi->ifi_ifname); 608222972Shrs goto getconfig_free_rai; 60955505Sshin } 610224144Shrs rai->rai_linkmtu = (uint32_t)val64; 611222732Shrs if (rai->rai_linkmtu == 0) { 61255505Sshin char *mtustr; 61355505Sshin 61455505Sshin if ((mtustr = (char *)agetstr("mtu", &bp)) && 61555505Sshin strcmp(mtustr, "auto") == 0) 616224144Shrs rai->rai_linkmtu = ifi->ifi_phymtu; 61755505Sshin } 618222732Shrs else if (rai->rai_linkmtu < IPV6_MMTU || 619224144Shrs rai->rai_linkmtu > ifi->ifi_phymtu) { 62055505Sshin syslog(LOG_ERR, 621224144Shrs "<%s> advertised link mtu (%" PRIu32 ") on %s is invalid (must " 622222732Shrs "be between least MTU (%d) and physical link MTU (%d)", 623224144Shrs __func__, rai->rai_linkmtu, ifi->ifi_ifname, 624224144Shrs IPV6_MMTU, ifi->ifi_phymtu); 625222972Shrs goto getconfig_free_rai; 62655505Sshin } 62755505Sshin 628151468Ssuz#ifdef SIOCSIFINFO_IN6 629151468Ssuz { 630151468Ssuz struct in6_ndireq ndi; 631151468Ssuz int s; 632151468Ssuz 633151468Ssuz if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 634151468Ssuz syslog(LOG_ERR, "<%s> socket: %s", __func__, 635222732Shrs strerror(errno)); 636151468Ssuz exit(1); 637151468Ssuz } 638151468Ssuz memset(&ndi, 0, sizeof(ndi)); 639224144Shrs strncpy(ndi.ifname, ifi->ifi_ifname, sizeof(ndi.ifname)); 640222732Shrs if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) 641151468Ssuz syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s", 642224144Shrs __func__, ifi->ifi_ifname, strerror(errno)); 643151468Ssuz 644151468Ssuz /* reflect the RA info to the host variables in kernel */ 645222732Shrs ndi.ndi.chlim = rai->rai_hoplimit; 646222732Shrs ndi.ndi.retrans = rai->rai_retranstimer; 647222732Shrs ndi.ndi.basereachable = rai->rai_reachabletime; 648222732Shrs if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) 649151468Ssuz syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s", 650224144Shrs __func__, ifi->ifi_ifname, strerror(errno)); 651222732Shrs 652151468Ssuz close(s); 653151468Ssuz } 654151468Ssuz#endif 655151468Ssuz 65678064Sume /* route information */ 657222732Shrs rai->rai_routes = 0; 658118968Sume for (i = -1; i < MAXROUTE; i++) { 65978064Sume struct rtinfo *rti; 66078064Sume 661118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtprefix"); 662118968Sume addr = (char *)agetstr(entbuf, &bp); 663118968Sume if (addr == NULL) { 664118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix"); 665118968Sume addr = (char *)agetstr(oentbuf, &bp); 666222732Shrs if (addr) 667118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 668222732Shrs oentbuf, entbuf); 669118968Sume } 670118968Sume if (addr == NULL) 671118968Sume continue; 672118968Sume 67378064Sume /* allocate memory to store prefix information */ 674222732Shrs ELM_MALLOC(rti, exit(1)); 67578064Sume 676222732Shrs if (inet_pton(AF_INET6, addr, &rti->rti_prefix) != 1) { 677118968Sume syslog(LOG_ERR, "<%s> inet_pton failed for %s", 678222732Shrs __func__, addr); 679222972Shrs goto getconfig_free_rti; 68078064Sume } 68178064Sume#if 0 68278064Sume /* 68378064Sume * XXX: currently there's no restriction in route information 684118968Sume * prefix according to 685118968Sume * draft-ietf-ipngwg-router-selection-00.txt. 686118968Sume * However, I think the similar restriction be necessary. 68778064Sume */ 68878064Sume MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 68978064Sume if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 69078064Sume syslog(LOG_ERR, 691222732Shrs "<%s> multicast route (%s) must " 692222732Shrs "not be advertised on %s", 693224144Shrs __func__, addr, ifi->ifi_ifname); 694222972Shrs goto getconfig_free_rti; 69578064Sume } 69678064Sume if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 69778064Sume syslog(LOG_NOTICE, 698222732Shrs "<%s> link-local route (%s) will " 699222732Shrs "be advertised on %s", 700224144Shrs __func__, addr, ifi->ifi_ifname); 701222972Shrs goto getconfig_free_rti; 70278064Sume } 70378064Sume#endif 704118968Sume 705118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtplen"); 706118968Sume /* XXX: 256 is a magic number for compatibility check. */ 707118968Sume MAYHAVE(val, entbuf, 256); 708118968Sume if (val == 256) { 709118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen"); 710118968Sume MAYHAVE(val, oentbuf, 256); 711222732Shrs if (val != 256) 712118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 713222732Shrs oentbuf, entbuf); 714222732Shrs else 715118968Sume val = 64; 716118968Sume } 717118968Sume if (val < 0 || val > 128) { 718224144Shrs syslog(LOG_ERR, "<%s> prefixlen (%" PRIu32 ") for %s on %s " 719222732Shrs "out of range", 720224144Shrs __func__, val, addr, ifi->ifi_ifname); 721222972Shrs goto getconfig_free_rti; 722118968Sume } 723222732Shrs rti->rti_prefixlen = (int)val; 724118968Sume 725118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtflags"); 726118968Sume if ((flagstr = (char *)agetstr(entbuf, &bp))) { 727118968Sume val = 0; 728118968Sume if (strchr(flagstr, 'h')) 729118968Sume val |= ND_RA_FLAG_RTPREF_HIGH; 730118968Sume if (strchr(flagstr, 'l')) { 731118968Sume if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 732118968Sume syslog(LOG_ERR, 733118968Sume "<%s> the \'h\' and \'l\' route" 734118968Sume " preferences are exclusive", 735118968Sume __func__); 736222972Shrs goto getconfig_free_rti; 737118968Sume } 738118968Sume val |= ND_RA_FLAG_RTPREF_LOW; 739118968Sume } 740118968Sume } else 741118968Sume MAYHAVE(val, entbuf, 256); /* XXX */ 742118968Sume if (val == 256) { 743118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags"); 744118968Sume MAYHAVE(val, oentbuf, 256); 745118968Sume if (val != 256) { 746118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 747222732Shrs oentbuf, entbuf); 748118968Sume } else 749118968Sume val = 0; 750118968Sume } 751222732Shrs rti->rti_rtpref = val & ND_RA_FLAG_RTPREF_MASK; 752222732Shrs if (rti->rti_rtpref == ND_RA_FLAG_RTPREF_RSV) { 753118968Sume syslog(LOG_ERR, "<%s> invalid route preference (%02x) " 754222732Shrs "for %s/%d on %s", 755222732Shrs __func__, rti->rti_rtpref, addr, 756224144Shrs rti->rti_prefixlen, ifi->ifi_ifname); 757222972Shrs goto getconfig_free_rti; 758118968Sume } 759118968Sume 760118968Sume /* 761118968Sume * Since the spec does not a default value, we should make 762118968Sume * this entry mandatory. However, FreeBSD 4.4 has shipped 763118968Sume * with this field being optional, we use the router lifetime 764118968Sume * as an ad-hoc default value with a warning message. 765118968Sume */ 766118968Sume makeentry(entbuf, sizeof(entbuf), i, "rtltime"); 767118968Sume MAYHAVE(val64, entbuf, -1); 768118968Sume if (val64 == -1) { 769118968Sume makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime"); 770118968Sume MAYHAVE(val64, oentbuf, -1); 771222732Shrs if (val64 != -1) 772118968Sume fprintf(stderr, "%s was obsoleted. Use %s.\n", 773222732Shrs oentbuf, entbuf); 774222732Shrs else { 775118968Sume fprintf(stderr, "%s should be specified " 776224144Shrs "for interface %s.\n", entbuf, 777224144Shrs ifi->ifi_ifname); 778222732Shrs val64 = rai->rai_lifetime; 779118968Sume } 780118968Sume } 781118968Sume if (val64 < 0 || val64 > 0xffffffff) { 782224144Shrs syslog(LOG_ERR, "<%s> route lifetime (%" PRIu64 ") for " 783118968Sume "%s/%d on %s out of range", __func__, 784224144Shrs val64, addr, rti->rti_prefixlen, 785224144Shrs ifi->ifi_ifname); 786222972Shrs goto getconfig_free_rti; 787118968Sume } 788224144Shrs rti->rti_ltime = (uint32_t)val64; 789222972Shrs 790222972Shrs /* link into chain */ 791222972Shrs TAILQ_INSERT_TAIL(&rai->rai_route, rti, rti_next); 792222972Shrs rai->rai_routes++; 793222972Shrs continue; 794222972Shrsgetconfig_free_rti: 795222972Shrs free(rti); 79678064Sume } 797224144Shrs 798222732Shrs /* DNS server and DNS search list information */ 799222732Shrs for (i = -1; i < MAXRDNSSENT ; i++) { 800222732Shrs struct rdnss *rdn; 801222732Shrs struct rdnss_addr *rdna; 802222732Shrs char *ap; 803222732Shrs int c; 80478064Sume 805222732Shrs makeentry(entbuf, sizeof(entbuf), i, "rdnss"); 806222732Shrs addr = (char *)agetstr(entbuf, &bp); 807222732Shrs if (addr == NULL) 808222732Shrs break; 809222732Shrs ELM_MALLOC(rdn, exit(1)); 81055505Sshin 811222732Shrs TAILQ_INIT(&rdn->rd_list); 812222732Shrs 813222732Shrs for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 814222732Shrs c = strcspn(ap, ","); 815222732Shrs strncpy(abuf, ap, c); 816222732Shrs abuf[c] = '\0'; 817222972Shrs ELM_MALLOC(rdna, goto getconfig_free_rdn); 818222732Shrs if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) { 819222732Shrs syslog(LOG_ERR, "<%s> inet_pton failed for %s", 820222732Shrs __func__, abuf); 821222732Shrs free(rdna); 822222972Shrs goto getconfig_free_rdn; 823222732Shrs } 824222732Shrs TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next); 825222732Shrs } 826222732Shrs 827222732Shrs makeentry(entbuf, sizeof(entbuf), i, "rdnssltime"); 828222732Shrs MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2)); 829224144Shrs if ((uint16_t)val < rai->rai_maxinterval || 830224144Shrs (uint16_t)val > rai->rai_maxinterval * 2) { 831224144Shrs syslog(LOG_ERR, "%s (%" PRIu16 ") on %s is invalid " 832222732Shrs "(must be between %d and %d)", 833224144Shrs entbuf, val, ifi->ifi_ifname, rai->rai_maxinterval, 834222732Shrs rai->rai_maxinterval * 2); 835222972Shrs goto getconfig_free_rdn; 836222732Shrs } 837222732Shrs rdn->rd_ltime = val; 838222732Shrs 839222732Shrs /* link into chain */ 840222732Shrs TAILQ_INSERT_TAIL(&rai->rai_rdnss, rdn, rd_next); 841222972Shrs continue; 842222972Shrsgetconfig_free_rdn: 843222972Shrs while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) { 844222972Shrs TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next); 845222972Shrs free(rdna); 846222972Shrs } 847222972Shrs free(rdn); 848222732Shrs } 849222732Shrs 850222732Shrs for (i = -1; i < MAXDNSSLENT ; i++) { 851222732Shrs struct dnssl *dns; 852222732Shrs struct dnssl_addr *dnsa; 853222732Shrs char *ap; 854222732Shrs int c; 855222732Shrs 856222732Shrs makeentry(entbuf, sizeof(entbuf), i, "dnssl"); 857222732Shrs addr = (char *)agetstr(entbuf, &bp); 858222732Shrs if (addr == NULL) 859222732Shrs break; 860222732Shrs 861222732Shrs ELM_MALLOC(dns, exit(1)); 862222732Shrs 863222732Shrs TAILQ_INIT(&dns->dn_list); 864222732Shrs 865222732Shrs for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 866222732Shrs c = strcspn(ap, ","); 867222732Shrs strncpy(abuf, ap, c); 868222732Shrs abuf[c] = '\0'; 869222972Shrs ELM_MALLOC(dnsa, goto getconfig_free_dns); 870222732Shrs dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf); 871222732Shrs syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__, 872222732Shrs dnsa->da_len); 873222732Shrs TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next); 874222732Shrs } 875222732Shrs 876222732Shrs makeentry(entbuf, sizeof(entbuf), i, "dnsslltime"); 877222732Shrs MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2)); 878224144Shrs if ((uint16_t)val < rai->rai_maxinterval || 879224144Shrs (uint16_t)val > rai->rai_maxinterval * 2) { 880224144Shrs syslog(LOG_ERR, "%s (%" PRIu16 ") on %s is invalid " 881222732Shrs "(must be between %d and %d)", 882224144Shrs entbuf, val, ifi->ifi_ifname, rai->rai_maxinterval, 883222732Shrs rai->rai_maxinterval * 2); 884222972Shrs goto getconfig_free_dns; 885222732Shrs } 886222732Shrs dns->dn_ltime = val; 887222732Shrs 888222732Shrs /* link into chain */ 889222732Shrs TAILQ_INSERT_TAIL(&rai->rai_dnssl, dns, dn_next); 890222972Shrs continue; 891222972Shrsgetconfig_free_dns: 892222972Shrs while ((dnsa = TAILQ_FIRST(&dns->dn_list)) != NULL) { 893222972Shrs TAILQ_REMOVE(&dns->dn_list, dnsa, da_next); 894222972Shrs free(dnsa); 895222972Shrs } 896222972Shrs free(dns); 897222732Shrs } 89855505Sshin /* construct the sending packet */ 899222732Shrs make_packet(rai); 900222972Shrs 901222972Shrs /* 902222972Shrs * If an entry with the same ifindex exists, remove it first. 903222972Shrs * Before the removal, RDNSS and DNSSL options with 904222972Shrs * zero-lifetime will be sent. 905222972Shrs */ 906224144Shrs switch (ifi->ifi_state) { 907224144Shrs case IFI_STATE_UNCONFIGURED: 908224144Shrs /* UNCONFIGURED -> TRANSITIVE */ 909222972Shrs 910224144Shrs error = sock_mc_join(&sock, ifi->ifi_ifindex); 911224144Shrs if (error) 912224144Shrs exit(1); 913222972Shrs 914224144Shrs ifi->ifi_state = IFI_STATE_TRANSITIVE; 915224144Shrs ifi->ifi_burstcount = MAX_INITIAL_RTR_ADVERTISEMENTS; 916224144Shrs ifi->ifi_burstinterval = MAX_INITIAL_RTR_ADVERT_INTERVAL; 917224144Shrs 918224144Shrs /* The same two rai mean initial burst */ 919224144Shrs ifi->ifi_rainfo = rai; 920224144Shrs ifi->ifi_rainfo_trans = rai; 921224144Shrs TAILQ_INSERT_TAIL(&railist, rai, rai_next); 922224144Shrs 923224144Shrs if (ifi->ifi_ra_timer == NULL) 924224144Shrs ifi->ifi_ra_timer = rtadvd_add_timer(ra_timeout, 925224144Shrs ra_timer_update, ifi, ifi); 926224144Shrs ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm); 927224144Shrs rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm, 928224144Shrs ifi->ifi_ra_timer); 929224144Shrs 930224144Shrs syslog(LOG_DEBUG, 931224144Shrs "<%s> ifname=%s marked as TRANSITIVE (initial burst).", 932224144Shrs __func__, ifi->ifi_ifname); 933224144Shrs break; 934224144Shrs case IFI_STATE_CONFIGURED: 935224144Shrs /* CONFIGURED -> TRANSITIVE */ 936224144Shrs rai_old = ifi->ifi_rainfo; 937224144Shrs if (rai_old == NULL) { 938224144Shrs syslog(LOG_ERR, 939224144Shrs "<%s> ifi_rainfo is NULL" 940224144Shrs " in IFI_STATE_CONFIGURED.", __func__); 941224144Shrs ifi = NULL; 942224144Shrs break; 943224144Shrs } else { 944224144Shrs struct rdnss *rdn; 945224144Shrs struct dnssl *dns; 946224144Shrs 947224144Shrs rai_old->rai_lifetime = 0; 948224144Shrs TAILQ_FOREACH(rdn, &rai_old->rai_rdnss, rd_next) 949224144Shrs rdn->rd_ltime = 0; 950224144Shrs TAILQ_FOREACH(dns, &rai_old->rai_dnssl, dn_next) 951224144Shrs dns->dn_ltime = 0; 952224144Shrs 953224144Shrs ifi->ifi_rainfo_trans = rai_old; 954224144Shrs ifi->ifi_state = IFI_STATE_TRANSITIVE; 955224144Shrs ifi->ifi_burstcount = MAX_FINAL_RTR_ADVERTISEMENTS; 956224144Shrs ifi->ifi_burstinterval = MIN_DELAY_BETWEEN_RAS; 957224144Shrs 958224144Shrs ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm); 959224144Shrs rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm, 960224144Shrs ifi->ifi_ra_timer); 961224144Shrs 962224144Shrs syslog(LOG_DEBUG, 963224144Shrs "<%s> ifname=%s marked as TRANSITIVE" 964224144Shrs " (transitional burst)", 965224144Shrs __func__, ifi->ifi_ifname); 966222972Shrs } 967224144Shrs ifi->ifi_rainfo = rai; 968224144Shrs TAILQ_INSERT_TAIL(&railist, rai, rai_next); 969224144Shrs break; 970224144Shrs case IFI_STATE_TRANSITIVE: 971224144Shrs if (ifi->ifi_rainfo != NULL) { 972224144Shrs if (ifi->ifi_rainfo == ifi->ifi_rainfo_trans) { 973224144Shrs /* Reinitialize initial burst */ 974224144Shrs rm_rainfo(ifi->ifi_rainfo); 975224144Shrs ifi->ifi_rainfo = rai; 976224144Shrs ifi->ifi_rainfo_trans = rai; 977224144Shrs ifi->ifi_burstcount = 978224144Shrs MAX_INITIAL_RTR_ADVERTISEMENTS; 979224144Shrs ifi->ifi_burstinterval = 980224144Shrs MAX_INITIAL_RTR_ADVERT_INTERVAL; 981224144Shrs } else { 982224144Shrs /* Replace ifi_rainfo with the new one */ 983224144Shrs rm_rainfo(ifi->ifi_rainfo); 984224144Shrs ifi->ifi_rainfo = rai; 985224144Shrs } 986224144Shrs TAILQ_INSERT_TAIL(&railist, rai, rai_next); 987224144Shrs 988224144Shrs ra_timer_update(ifi, &ifi->ifi_ra_timer->rat_tm); 989224144Shrs rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm, 990224144Shrs ifi->ifi_ra_timer); 991224144Shrs } else { 992224144Shrs /* XXX: NOTREACHED. Being shut down. */ 993224144Shrs syslog(LOG_ERR, 994224144Shrs "<%s> %s is shutting down. Skipped.", 995224144Shrs __func__, ifi->ifi_ifname); 996224144Shrs rm_rainfo(rai); 997224144Shrs 998224144Shrs return (NULL); 999224144Shrs } 1000224144Shrs break; 1001222972Shrs } 100255505Sshin 1003224144Shrs return (ifi); 1004222732Shrs 1005222972Shrsgetconfig_free_rai: 1006222972Shrs free(rai); 1007224144Shrs return (NULL); 100855505Sshin} 100955505Sshin 1010118968Sumevoid 101155505Sshinget_prefix(struct rainfo *rai) 101255505Sshin{ 101378064Sume struct ifaddrs *ifap, *ifa; 1014222732Shrs struct prefix *pfx; 101578064Sume struct in6_addr *a; 1016224144Shrs struct ifinfo *ifi; 1017224144Shrs char *p, *ep, *m, *lim; 1018224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 101955505Sshin 102078064Sume if (getifaddrs(&ifap) < 0) { 102155505Sshin syslog(LOG_ERR, 1022222732Shrs "<%s> can't get interface addresses", 1023222732Shrs __func__); 102455505Sshin exit(1); 102555505Sshin } 1026224144Shrs ifi = rai->rai_ifinfo; 1027118664Sume 102878064Sume for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 102997719Sume int plen; 103097719Sume 1031224144Shrs if (strcmp(ifa->ifa_name, ifi->ifi_ifname) != 0) 103278064Sume continue; 103378064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 103478064Sume continue; 103578064Sume a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 103678064Sume if (IN6_IS_ADDR_LINKLOCAL(a)) 103778064Sume continue; 1038224144Shrs 103997719Sume /* get prefix length */ 1040224144Shrs m = (char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 1041224144Shrs lim = (char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 104297719Sume plen = prefixlen(m, lim); 1043118968Sume if (plen <= 0 || plen > 128) { 104497719Sume syslog(LOG_ERR, "<%s> failed to get prefixlen " 1045222732Shrs "or prefix is invalid", 1046222732Shrs __func__); 104797719Sume exit(1); 104897719Sume } 1049118968Sume if (plen == 128) /* XXX */ 1050118968Sume continue; 105197719Sume if (find_prefix(rai, a, plen)) { 105297719Sume /* ignore a duplicated prefix. */ 105397719Sume continue; 105497719Sume } 105597719Sume 105655505Sshin /* allocate memory to store prefix info. */ 1057222732Shrs ELM_MALLOC(pfx, exit(1)); 105855505Sshin 105978064Sume /* set prefix, sweep bits outside of prefixlen */ 1060222732Shrs pfx->pfx_prefixlen = plen; 1061222732Shrs memcpy(&pfx->pfx_prefix, a, sizeof(*a)); 1062224144Shrs p = (char *)&pfx->pfx_prefix; 1063224144Shrs ep = (char *)(&pfx->pfx_prefix + 1); 1064157047Ssuz while (m < lim && p < ep) 106578064Sume *p++ &= *m++; 106678064Sume while (p < ep) 106778064Sume *p++ = 0x00; 1068222732Shrs if (!inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 106978064Sume sizeof(ntopbuf))) { 1070118660Sume syslog(LOG_ERR, "<%s> inet_ntop failed", __func__); 107178064Sume exit(1); 107278064Sume } 107355505Sshin syslog(LOG_DEBUG, 1074222732Shrs "<%s> add %s/%d to prefix list on %s", 1075224144Shrs __func__, ntopbuf, pfx->pfx_prefixlen, ifi->ifi_ifname); 107655505Sshin 107755505Sshin /* set other fields with protocol defaults */ 1078222732Shrs pfx->pfx_validlifetime = DEF_ADVVALIDLIFETIME; 1079222732Shrs pfx->pfx_preflifetime = DEF_ADVPREFERREDLIFETIME; 1080222732Shrs pfx->pfx_onlinkflg = 1; 1081222732Shrs pfx->pfx_autoconfflg = 1; 1082222732Shrs pfx->pfx_origin = PREFIX_FROM_KERNEL; 1083222732Shrs pfx->pfx_rainfo = rai; 108455505Sshin 108555505Sshin /* link into chain */ 1086222732Shrs TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 108755505Sshin 108855505Sshin /* counter increment */ 1089222732Shrs rai->rai_pfxs++; 109055505Sshin } 109155505Sshin 109278064Sume freeifaddrs(ifap); 109355505Sshin} 109455505Sshin 109555505Sshinstatic void 1096222732Shrsmakeentry(char *buf, size_t len, int id, const char *string) 109755505Sshin{ 109897709Sume 1099118968Sume if (id < 0) 1100118968Sume strlcpy(buf, string, len); 1101118968Sume else 1102118968Sume snprintf(buf, len, "%s%d", string, id); 110355505Sshin} 110455505Sshin 110555505Sshin/* 110655505Sshin * Add a prefix to the list of specified interface and reconstruct 110755505Sshin * the outgoing packet. 110855505Sshin * The prefix must not be in the list. 1109152538Ssuz * XXX: other parameters of the prefix (e.g. lifetime) should be 111055505Sshin * able to be specified. 111155505Sshin */ 111255505Sshinstatic void 111355505Sshinadd_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 111455505Sshin{ 1115222732Shrs struct prefix *pfx; 1116224144Shrs struct ifinfo *ifi; 1117224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 111855505Sshin 1119224144Shrs ifi = rai->rai_ifinfo; 1120222732Shrs ELM_MALLOC(pfx, return); 1121222732Shrs pfx->pfx_prefix = ipr->ipr_prefix.sin6_addr; 1122222732Shrs pfx->pfx_prefixlen = ipr->ipr_plen; 1123222732Shrs pfx->pfx_validlifetime = ipr->ipr_vltime; 1124222732Shrs pfx->pfx_preflifetime = ipr->ipr_pltime; 1125222732Shrs pfx->pfx_onlinkflg = ipr->ipr_raf_onlink; 1126222732Shrs pfx->pfx_autoconfflg = ipr->ipr_raf_auto; 1127222732Shrs pfx->pfx_origin = PREFIX_FROM_DYNAMIC; 1128254684Sdes pfx->pfx_rainfo = rai; 112955505Sshin 1130222732Shrs TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 113155505Sshin 113255505Sshin syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 1133222732Shrs __func__, 1134222732Shrs inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 1135224144Shrs sizeof(ntopbuf)), ipr->ipr_plen, ifi->ifi_ifname); 113655505Sshin 1137222732Shrs rai->rai_pfxs++; 113855505Sshin} 113955505Sshin 114055505Sshin/* 114155505Sshin * Delete a prefix to the list of specified interface and reconstruct 114255505Sshin * the outgoing packet. 114362656Skris * The prefix must be in the list. 114455505Sshin */ 114555505Sshinvoid 1146222732Shrsdelete_prefix(struct prefix *pfx) 114755505Sshin{ 1148222732Shrs struct rainfo *rai; 1149224144Shrs struct ifinfo *ifi; 1150224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 115155505Sshin 1152222732Shrs rai = pfx->pfx_rainfo; 1153224144Shrs ifi = rai->rai_ifinfo; 1154222732Shrs TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next); 115555505Sshin syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 1156222732Shrs __func__, 1157222732Shrs inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 1158224144Shrs sizeof(ntopbuf)), pfx->pfx_prefixlen, ifi->ifi_ifname); 1159222732Shrs if (pfx->pfx_timer) 1160222732Shrs rtadvd_remove_timer(pfx->pfx_timer); 1161222732Shrs free(pfx); 1162224144Shrs 1163222732Shrs rai->rai_pfxs--; 116455505Sshin} 116555505Sshin 116698172Sumevoid 1167222732Shrsinvalidate_prefix(struct prefix *pfx) 116898172Sume{ 1169253970Shrs struct timespec timo; 1170222732Shrs struct rainfo *rai; 1171224144Shrs struct ifinfo *ifi; 1172224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 117398172Sume 1174222732Shrs rai = pfx->pfx_rainfo; 1175224144Shrs ifi = rai->rai_ifinfo; 1176222732Shrs if (pfx->pfx_timer) { /* sanity check */ 117798172Sume syslog(LOG_ERR, 117898172Sume "<%s> assumption failure: timer already exists", 1179118660Sume __func__); 118098172Sume exit(1); 118198172Sume } 118298172Sume 118398172Sume syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " 1184118660Sume "will expire in %ld seconds", __func__, 1185222732Shrs inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, sizeof(ntopbuf)), 1186224144Shrs pfx->pfx_prefixlen, ifi->ifi_ifname, (long)prefix_timo); 118798172Sume 118898172Sume /* set the expiration timer */ 1189222732Shrs pfx->pfx_timer = rtadvd_add_timer(prefix_timeout, NULL, pfx, NULL); 1190222732Shrs if (pfx->pfx_timer == NULL) { 119198172Sume syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. " 1192118660Sume "remove the prefix", __func__); 1193222732Shrs delete_prefix(pfx); 119498172Sume } 119598172Sume timo.tv_sec = prefix_timo; 1196253970Shrs timo.tv_nsec = 0; 1197222732Shrs rtadvd_set_timer(&timo, pfx->pfx_timer); 119898172Sume} 119998172Sume 120098172Sumestatic struct rtadvd_timer * 120198172Sumeprefix_timeout(void *arg) 120298172Sume{ 120398172Sume 1204222732Shrs delete_prefix((struct prefix *)arg); 1205222732Shrs 1206222732Shrs return (NULL); 120798172Sume} 120898172Sume 120998172Sumevoid 1210222732Shrsupdate_prefix(struct prefix *pfx) 121198172Sume{ 1212222732Shrs struct rainfo *rai; 1213224144Shrs struct ifinfo *ifi; 1214224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 121598172Sume 1216222732Shrs rai = pfx->pfx_rainfo; 1217224144Shrs ifi = rai->rai_ifinfo; 1218222732Shrs if (pfx->pfx_timer == NULL) { /* sanity check */ 121998172Sume syslog(LOG_ERR, 122098172Sume "<%s> assumption failure: timer does not exist", 1221118660Sume __func__); 122298172Sume exit(1); 122398172Sume } 122498172Sume 122598172Sume syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", 1226222732Shrs __func__, inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 1227224144Shrs sizeof(ntopbuf)), pfx->pfx_prefixlen, ifi->ifi_ifname); 122898172Sume 122998172Sume /* stop the expiration timer */ 1230222732Shrs rtadvd_remove_timer(pfx->pfx_timer); 1231222732Shrs pfx->pfx_timer = NULL; 123298172Sume} 123398172Sume 123455505Sshin/* 123555505Sshin * Try to get an in6_prefixreq contents for a prefix which matches 123655505Sshin * ipr->ipr_prefix and ipr->ipr_plen and belongs to 123755505Sshin * the interface whose name is ipr->ipr_name[]. 123855505Sshin */ 123955505Sshinstatic int 124055505Sshininit_prefix(struct in6_prefixreq *ipr) 124155505Sshin{ 124298262Sume#if 0 124355505Sshin int s; 124455505Sshin 124555505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1246118660Sume syslog(LOG_ERR, "<%s> socket: %s", __func__, 1247222732Shrs strerror(errno)); 124855505Sshin exit(1); 124955505Sshin } 125055505Sshin 125155505Sshin if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 1252118660Sume syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__, 1253222732Shrs strerror(errno)); 125455505Sshin 125555505Sshin ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 125655505Sshin ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 125755505Sshin ipr->ipr_raf_onlink = 1; 125855505Sshin ipr->ipr_raf_auto = 1; 125955505Sshin /* omit other field initialization */ 126055505Sshin } 126155505Sshin else if (ipr->ipr_origin < PR_ORIG_RR) { 1262224144Shrs char ntopbuf[INET6_ADDRSTRLEN]; 126355505Sshin 126455505Sshin syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 1265222732Shrs "lower than PR_ORIG_RR(router renumbering)." 1266222732Shrs "This should not happen if I am router", __func__, 1267222732Shrs inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 1268222732Shrs sizeof(ntopbuf)), ipr->ipr_origin); 126957852Sshin close(s); 1270222732Shrs return (1); 127155505Sshin } 127255505Sshin 127355505Sshin close(s); 1274222732Shrs return (0); 127598262Sume#else 127698262Sume ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 127798262Sume ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 127898262Sume ipr->ipr_raf_onlink = 1; 127998262Sume ipr->ipr_raf_auto = 1; 1280222732Shrs return (0); 128198262Sume#endif 128255505Sshin} 128355505Sshin 128455505Sshinvoid 128555505Sshinmake_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 128655505Sshin{ 128755505Sshin struct in6_prefixreq ipr; 128855505Sshin 128955505Sshin memset(&ipr, 0, sizeof(ipr)); 129055505Sshin if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 1291253057Shrs syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't " 1292222732Shrs "exist. This should not happen! %s", __func__, 1293222732Shrs ifindex, strerror(errno)); 129455505Sshin exit(1); 129555505Sshin } 129655505Sshin ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 129755505Sshin ipr.ipr_prefix.sin6_family = AF_INET6; 129855505Sshin ipr.ipr_prefix.sin6_addr = *addr; 129955505Sshin ipr.ipr_plen = plen; 130055505Sshin 130155505Sshin if (init_prefix(&ipr)) 130255505Sshin return; /* init failed by some error */ 130355505Sshin add_prefix(rai, &ipr); 130455505Sshin} 130555505Sshin 130662656Skrisvoid 1307222732Shrsmake_packet(struct rainfo *rai) 130855505Sshin{ 130955505Sshin size_t packlen, lladdroptlen = 0; 131055505Sshin char *buf; 131155505Sshin struct nd_router_advert *ra; 131255505Sshin struct nd_opt_prefix_info *ndopt_pi; 131355505Sshin struct nd_opt_mtu *ndopt_mtu; 131478064Sume struct nd_opt_route_info *ndopt_rti; 1315118968Sume struct rtinfo *rti; 1316222732Shrs struct nd_opt_rdnss *ndopt_rdnss; 1317222732Shrs struct rdnss *rdn; 1318222732Shrs struct nd_opt_dnssl *ndopt_dnssl; 1319222732Shrs struct dnssl *dns; 1320222732Shrs size_t len; 132155505Sshin struct prefix *pfx; 1322224144Shrs struct ifinfo *ifi; 132355505Sshin 1324224144Shrs ifi = rai->rai_ifinfo; 132555505Sshin /* calculate total length */ 132655505Sshin packlen = sizeof(struct nd_router_advert); 1327222732Shrs if (rai->rai_advlinkopt) { 1328224144Shrs if ((lladdroptlen = lladdropt_length(&ifi->ifi_sdl)) == 0) { 132955505Sshin syslog(LOG_INFO, 1330222732Shrs "<%s> link-layer address option has" 1331222732Shrs " null length on %s. Treat as not included.", 1332224144Shrs __func__, ifi->ifi_ifname); 1333222732Shrs rai->rai_advlinkopt = 0; 133455505Sshin } 133555505Sshin packlen += lladdroptlen; 133655505Sshin } 1337222732Shrs if (rai->rai_pfxs) 1338222732Shrs packlen += sizeof(struct nd_opt_prefix_info) * rai->rai_pfxs; 1339222732Shrs if (rai->rai_linkmtu) 134055505Sshin packlen += sizeof(struct nd_opt_mtu); 1341224144Shrs 1342222732Shrs TAILQ_FOREACH(rti, &rai->rai_route, rti_next) 1343222732Shrs packlen += sizeof(struct nd_opt_route_info) + 1344222732Shrs ((rti->rti_prefixlen + 0x3f) >> 6) * 8; 1345224144Shrs 1346222732Shrs TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { 1347222732Shrs struct rdnss_addr *rdna; 134855505Sshin 1349222732Shrs packlen += sizeof(struct nd_opt_rdnss); 1350222732Shrs TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) 1351222732Shrs packlen += sizeof(rdna->ra_dns); 1352222732Shrs } 1353222732Shrs TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { 1354222732Shrs struct dnssl_addr *dnsa; 1355222732Shrs 1356222732Shrs packlen += sizeof(struct nd_opt_dnssl); 1357222732Shrs len = 0; 1358222732Shrs TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) 1359222732Shrs len += dnsa->da_len; 1360222732Shrs 1361222732Shrs /* A zero octet and 8 octet boundary */ 1362222732Shrs len++; 1363222732Shrs len += (len % 8) ? 8 - len % 8 : 0; 1364222732Shrs 1365222732Shrs packlen += len; 1366222732Shrs } 136755505Sshin /* allocate memory for the packet */ 136855505Sshin if ((buf = malloc(packlen)) == NULL) { 136955505Sshin syslog(LOG_ERR, 1370222732Shrs "<%s> can't get enough memory for an RA packet", 1371222732Shrs __func__); 137255505Sshin exit(1); 137355505Sshin } 1374222732Shrs memset(buf, 0, packlen); 1375222732Shrs if (rai->rai_ra_data) /* Free old data if any. */ 1376222732Shrs free(rai->rai_ra_data); 1377222732Shrs rai->rai_ra_data = buf; 137855505Sshin /* XXX: what if packlen > 576? */ 1379222732Shrs rai->rai_ra_datalen = packlen; 138055505Sshin 138155505Sshin /* 138255505Sshin * construct the packet 138355505Sshin */ 138455505Sshin ra = (struct nd_router_advert *)buf; 138555505Sshin ra->nd_ra_type = ND_ROUTER_ADVERT; 138655505Sshin ra->nd_ra_code = 0; 138755505Sshin ra->nd_ra_cksum = 0; 1388224144Shrs ra->nd_ra_curhoplimit = (uint8_t)(0xff & rai->rai_hoplimit); 138978064Sume ra->nd_ra_flags_reserved = 0; /* just in case */ 139078064Sume /* 139178064Sume * XXX: the router preference field, which is a 2-bit field, should be 139278064Sume * initialized before other fields. 139378064Sume */ 1394222732Shrs ra->nd_ra_flags_reserved = 0xff & rai->rai_rtpref; 139555505Sshin ra->nd_ra_flags_reserved |= 1396222732Shrs rai->rai_managedflg ? ND_RA_FLAG_MANAGED : 0; 139755505Sshin ra->nd_ra_flags_reserved |= 1398222732Shrs rai->rai_otherflg ? ND_RA_FLAG_OTHER : 0; 1399222732Shrs ra->nd_ra_router_lifetime = htons(rai->rai_lifetime); 1400222732Shrs ra->nd_ra_reachable = htonl(rai->rai_reachabletime); 1401222732Shrs ra->nd_ra_retransmit = htonl(rai->rai_retranstimer); 140255505Sshin buf += sizeof(*ra); 140355505Sshin 1404222732Shrs if (rai->rai_advlinkopt) { 1405224144Shrs lladdropt_fill(&ifi->ifi_sdl, (struct nd_opt_hdr *)buf); 140655505Sshin buf += lladdroptlen; 140755505Sshin } 140855505Sshin 1409222732Shrs if (rai->rai_linkmtu) { 141055505Sshin ndopt_mtu = (struct nd_opt_mtu *)buf; 141155505Sshin ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 141255505Sshin ndopt_mtu->nd_opt_mtu_len = 1; 141355505Sshin ndopt_mtu->nd_opt_mtu_reserved = 0; 1414222732Shrs ndopt_mtu->nd_opt_mtu_mtu = htonl(rai->rai_linkmtu); 141555505Sshin buf += sizeof(struct nd_opt_mtu); 141655505Sshin } 141755505Sshin 1418222732Shrs TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { 1419224144Shrs uint32_t vltime, pltime; 1420253970Shrs struct timespec now; 142178064Sume 142255505Sshin ndopt_pi = (struct nd_opt_prefix_info *)buf; 142355505Sshin ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 142455505Sshin ndopt_pi->nd_opt_pi_len = 4; 1425222732Shrs ndopt_pi->nd_opt_pi_prefix_len = pfx->pfx_prefixlen; 142655505Sshin ndopt_pi->nd_opt_pi_flags_reserved = 0; 1427222732Shrs if (pfx->pfx_onlinkflg) 142855505Sshin ndopt_pi->nd_opt_pi_flags_reserved |= 142955505Sshin ND_OPT_PI_FLAG_ONLINK; 1430222732Shrs if (pfx->pfx_autoconfflg) 143155505Sshin ndopt_pi->nd_opt_pi_flags_reserved |= 143255505Sshin ND_OPT_PI_FLAG_AUTO; 1433222732Shrs if (pfx->pfx_timer) 143498172Sume vltime = 0; 143598172Sume else { 1436222732Shrs if (pfx->pfx_vltimeexpire || pfx->pfx_pltimeexpire) 1437253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 1438222732Shrs if (pfx->pfx_vltimeexpire == 0) 1439222732Shrs vltime = pfx->pfx_validlifetime; 144098172Sume else 1441224144Shrs vltime = ((time_t)pfx->pfx_vltimeexpire > now.tv_sec) ? 1442222732Shrs pfx->pfx_vltimeexpire - now.tv_sec : 0; 144398172Sume } 1444222732Shrs if (pfx->pfx_timer) 144598172Sume pltime = 0; 144698172Sume else { 1447222732Shrs if (pfx->pfx_pltimeexpire == 0) 1448222732Shrs pltime = pfx->pfx_preflifetime; 144998172Sume else 1450224144Shrs pltime = ((time_t)pfx->pfx_pltimeexpire > now.tv_sec) ? 1451222732Shrs pfx->pfx_pltimeexpire - now.tv_sec : 0; 145298172Sume } 145378064Sume if (vltime < pltime) { 145478064Sume /* 145578064Sume * this can happen if vltime is decrement but pltime 145678064Sume * is not. 145778064Sume */ 145878064Sume pltime = vltime; 145978064Sume } 146078064Sume ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 146178064Sume ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 146255505Sshin ndopt_pi->nd_opt_pi_reserved2 = 0; 1463222732Shrs ndopt_pi->nd_opt_pi_prefix = pfx->pfx_prefix; 146455505Sshin 146555505Sshin buf += sizeof(struct nd_opt_prefix_info); 146655505Sshin } 146755505Sshin 1468222732Shrs TAILQ_FOREACH(rti, &rai->rai_route, rti_next) { 1469224144Shrs uint8_t psize = (rti->rti_prefixlen + 0x3f) >> 6; 147078064Sume 147178064Sume ndopt_rti = (struct nd_opt_route_info *)buf; 147278064Sume ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 147378064Sume ndopt_rti->nd_opt_rti_len = 1 + psize; 1474222732Shrs ndopt_rti->nd_opt_rti_prefixlen = rti->rti_prefixlen; 1475222732Shrs ndopt_rti->nd_opt_rti_flags = 0xff & rti->rti_rtpref; 1476222732Shrs ndopt_rti->nd_opt_rti_lifetime = htonl(rti->rti_ltime); 1477222732Shrs memcpy(ndopt_rti + 1, &rti->rti_prefix, psize * 8); 147878064Sume buf += sizeof(struct nd_opt_route_info) + psize * 8; 147978064Sume } 1480224144Shrs 1481222732Shrs TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { 1482222732Shrs struct rdnss_addr *rdna; 148378064Sume 1484222732Shrs ndopt_rdnss = (struct nd_opt_rdnss *)buf; 1485222732Shrs ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; 1486222732Shrs ndopt_rdnss->nd_opt_rdnss_len = 0; 1487222732Shrs ndopt_rdnss->nd_opt_rdnss_reserved = 0; 1488222732Shrs ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdn->rd_ltime); 1489222732Shrs buf += sizeof(struct nd_opt_rdnss); 149078064Sume 1491222732Shrs TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) { 1492222732Shrs memcpy(buf, &rdna->ra_dns, sizeof(rdna->ra_dns)); 1493222732Shrs buf += sizeof(rdna->ra_dns); 1494222732Shrs } 1495222732Shrs /* Length field should be in 8 octets */ 1496222732Shrs ndopt_rdnss->nd_opt_rdnss_len = (buf - (char *)ndopt_rdnss) / 8; 149778064Sume 1498222732Shrs syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__, 1499222732Shrs ndopt_rdnss->nd_opt_rdnss_len); 150078064Sume } 1501224144Shrs 1502222732Shrs TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { 1503222732Shrs struct dnssl_addr *dnsa; 1504222732Shrs 1505222732Shrs ndopt_dnssl = (struct nd_opt_dnssl *)buf; 1506222732Shrs ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL; 1507222732Shrs ndopt_dnssl->nd_opt_dnssl_len = 0; 1508222732Shrs ndopt_dnssl->nd_opt_dnssl_reserved = 0; 1509222732Shrs ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dns->dn_ltime); 1510222732Shrs buf += sizeof(*ndopt_dnssl); 1511222732Shrs 1512222732Shrs TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) { 1513222732Shrs memcpy(buf, dnsa->da_dom, dnsa->da_len); 1514222732Shrs buf += dnsa->da_len; 1515222732Shrs } 1516222732Shrs 1517222732Shrs /* A zero octet after encoded DNS server list. */ 1518222732Shrs *buf++ = '\0'; 1519222732Shrs 1520222732Shrs /* Padding to next 8 octets boundary */ 1521222732Shrs len = buf - (char *)ndopt_dnssl; 1522222732Shrs len += (len % 8) ? 8 - len % 8 : 0; 1523222732Shrs 1524222732Shrs /* Length field must be in 8 octets */ 1525222732Shrs ndopt_dnssl->nd_opt_dnssl_len = len / 8; 1526222732Shrs 1527222732Shrs syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__, 1528222732Shrs ndopt_dnssl->nd_opt_dnssl_len); 1529222732Shrs } 1530222732Shrs return; 153178064Sume} 1532