config.c revision 222732
1/* $FreeBSD: head/usr.sbin/rtadvd/config.c 222732 2011-06-06 03:06:43Z hrs $ */ 2/* $KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $ */ 3 4/* 5 * Copyright (C) 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/param.h> 34#include <sys/ioctl.h> 35#include <sys/socket.h> 36#include <sys/time.h> 37 38#include <net/if.h> 39#include <net/if_var.h> 40#include <net/route.h> 41#include <net/if_dl.h> 42 43#include <netinet/in.h> 44#include <netinet/in_var.h> 45#include <netinet/ip6.h> 46#include <netinet6/ip6_var.h> 47#include <netinet/icmp6.h> 48#include <netinet6/nd6.h> 49 50#include <arpa/inet.h> 51 52#include <stdio.h> 53#include <syslog.h> 54#include <errno.h> 55#include <netdb.h> 56#include <string.h> 57#include <search.h> 58#include <stdlib.h> 59#include <unistd.h> 60#include <ifaddrs.h> 61 62#include "rtadvd.h" 63#include "advcap.h" 64#include "timer.h" 65#include "if.h" 66#include "config.h" 67 68/* label of tcapcode + number + domain name + zero octet */ 69static char entbuf[10 + 3 + NI_MAXHOST + 1]; 70static char oentbuf[10 + 3 + NI_MAXHOST + 1]; 71static char abuf[DNAME_LABELENC_MAXLEN]; 72 73static time_t prefix_timo = (60 * 120); /* 2 hours. 74 * XXX: should be configurable. */ 75 76static struct rtadvd_timer *prefix_timeout(void *); 77static void makeentry(char *, size_t, int, const char *); 78static size_t dname_labelenc(char *, const char *); 79 80/* Encode domain name label encoding in RFC 1035 Section 3.1 */ 81static size_t 82dname_labelenc(char *dst, const char *src) 83{ 84 char *dst_origin; 85 char *p; 86 size_t len; 87 88 dst_origin = dst; 89 len = strlen(src); 90 91 /* Length fields per 63 octets + '\0' (<= DNAME_LABELENC_MAXLEN) */ 92 memset(dst, 0, len + len / 64 + 1 + 1); 93 94 syslog(LOG_DEBUG, "<%s> labelenc = %s", __func__, src); 95 while (src && (len = strlen(src)) != 0) { 96 /* Put a length field with 63 octet limitation first. */ 97 p = strchr(src, '.'); 98 if (p == NULL) 99 *dst++ = len = MIN(63, len); 100 else 101 *dst++ = len = MIN(63, p - src); 102 /* Copy 63 octets at most. */ 103 memcpy(dst, src, len); 104 dst += len; 105 if (p == NULL) /* the last label */ 106 break; 107 src = p + 1; 108 } 109 /* Always need a 0-length label at the tail. */ 110 *dst++ = '\0'; 111 112 syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, dst - dst_origin); 113 return (dst - dst_origin); 114} 115 116#define MUSTHAVE(var, cap) \ 117 do { \ 118 int64_t t; \ 119 if ((t = agetnum(cap)) < 0) { \ 120 fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 121 cap, intface); \ 122 exit(1); \ 123 } \ 124 var = t; \ 125 } while (0) 126 127#define MAYHAVE(var, cap, def) \ 128 do { \ 129 if ((var = agetnum(cap)) < 0) \ 130 var = def; \ 131 } while (0) 132 133#define ELM_MALLOC(p,error_action) \ 134 do { \ 135 p = malloc(sizeof(*p)); \ 136 if (p == NULL) { \ 137 syslog(LOG_ERR, "<%s> malloc failed: %s", \ 138 __func__, strerror(errno)); \ 139 error_action; \ 140 } \ 141 memset(p, 0, sizeof(*p)); \ 142 } while(0) 143 144int 145rmconfig(int idx) 146{ 147 struct rainfo *rai; 148 struct prefix *pfx; 149 struct soliciter *sol; 150 struct rdnss *rdn; 151 struct rdnss_addr *rdna; 152 struct dnssl *dns; 153 struct rtinfo *rti; 154 155 rai = if_indextorainfo(idx); 156 if (rai == NULL) { 157 syslog(LOG_ERR, "<%s>: rainfo not found (idx=%d)", 158 __func__, idx); 159 return (-1); 160 } 161 162 TAILQ_REMOVE(&railist, rai, rai_next); 163 syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.", 164 __func__, idx); 165 166 /* Free all of allocated memories for this entry. */ 167 rtadvd_remove_timer(rai->rai_timer); 168 169 if (rai->rai_ra_data != NULL) 170 free(rai->rai_ra_data); 171 172 if (rai->rai_sdl != NULL) 173 free(rai->rai_sdl); 174 175 while ((pfx = TAILQ_FIRST(&rai->rai_prefix)) != NULL) { 176 TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next); 177 free(pfx); 178 } 179 while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) { 180 TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next); 181 free(sol); 182 } 183 while ((rdn = TAILQ_FIRST(&rai->rai_rdnss)) != NULL) { 184 TAILQ_REMOVE(&rai->rai_rdnss, rdn, rd_next); 185 while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) { 186 TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next); 187 free(rdna); 188 } 189 free(rdn); 190 } 191 while ((dns = TAILQ_FIRST(&rai->rai_dnssl)) != NULL) { 192 TAILQ_REMOVE(&rai->rai_dnssl, dns, dn_next); 193 free(dns); 194 } 195 while ((rti = TAILQ_FIRST(&rai->rai_route)) != NULL) { 196 TAILQ_REMOVE(&rai->rai_route, rti, rti_next); 197 free(rti); 198 } 199 free(rai); 200 201 return (0); 202} 203 204int 205getconfig(int idx) 206{ 207 int stat, i; 208 char tbuf[BUFSIZ]; 209 struct rainfo *rai; 210 long val; 211 int64_t val64; 212 char buf[BUFSIZ]; 213 char *bp = buf; 214 char *addr, *flagstr; 215 char intface[IFNAMSIZ]; 216 217 if (if_indextoname(idx, intface) == NULL) { 218 syslog(LOG_ERR, "<%s> invalid index number (%d)", 219 __func__, idx); 220 return (-1); 221 } 222 223 if ((stat = agetent(tbuf, intface)) <= 0) { 224 memset(tbuf, 0, sizeof(tbuf)); 225 syslog(LOG_INFO, 226 "<%s> %s isn't defined in the configuration file" 227 " or the configuration file doesn't exist." 228 " Treat it as default", 229 __func__, intface); 230 } 231 232 rai = malloc(sizeof(*rai)); 233 if (rai == NULL) { 234 syslog(LOG_INFO, "<%s> %s: can't allocate enough memory", 235 __func__, intface); 236 exit(1); 237 } 238 memset(rai, 0, sizeof(*rai)); 239 TAILQ_INIT(&rai->rai_prefix); 240#ifdef ROUTEINFO 241 TAILQ_INIT(&rai->rai_route); 242#endif 243 TAILQ_INIT(&rai->rai_rdnss); 244 TAILQ_INIT(&rai->rai_dnssl); 245 TAILQ_INIT(&rai->rai_soliciter); 246 247 /* gather on-link prefixes from the network interfaces. */ 248 if (agetflag("noifprefix")) 249 rai->rai_advifprefix = 0; 250 else 251 rai->rai_advifprefix = 1; 252 253 /* get interface information */ 254 if (agetflag("nolladdr")) 255 rai->rai_advlinkopt = 0; 256 else 257 rai->rai_advlinkopt = 1; 258 if (rai->rai_advlinkopt) { 259 if ((rai->rai_sdl = if_nametosdl(intface)) == NULL) { 260 syslog(LOG_ERR, 261 "<%s> can't get information of %s", 262 __func__, intface); 263 return (-1); 264 } 265 rai->rai_ifindex = rai->rai_sdl->sdl_index; 266 } else 267 rai->rai_ifindex = if_nametoindex(intface); 268 strncpy(rai->rai_ifname, intface, sizeof(rai->rai_ifname)); 269 syslog(LOG_DEBUG, 270 "<%s> ifindex = %d on %s", __func__, rai->rai_ifindex, 271 rai->rai_ifname); 272 273 if ((rai->rai_phymtu = if_getmtu(intface)) == 0) { 274 rai->rai_phymtu = IPV6_MMTU; 275 syslog(LOG_WARNING, 276 "<%s> can't get interface mtu of %s. Treat as %d", 277 __func__, intface, IPV6_MMTU); 278 } 279 280 /* 281 * set router configuration variables. 282 */ 283 MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 284 if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 285 syslog(LOG_ERR, 286 "<%s> maxinterval (%ld) on %s is invalid " 287 "(must be between %u and %u)", __func__, val, 288 intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 289 return (-1); 290 } 291 rai->rai_maxinterval = (u_int)val; 292 293 MAYHAVE(val, "mininterval", rai->rai_maxinterval/3); 294 if ((u_int)val < MIN_MININTERVAL || 295 (u_int)val > (rai->rai_maxinterval * 3) / 4) { 296 syslog(LOG_ERR, 297 "<%s> mininterval (%ld) on %s is invalid " 298 "(must be between %d and %d)", 299 __func__, val, intface, MIN_MININTERVAL, 300 (rai->rai_maxinterval * 3) / 4); 301 return (-1); 302 } 303 rai->rai_mininterval = (u_int)val; 304 305 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 306 rai->rai_hoplimit = val & 0xff; 307 308 if ((flagstr = (char *)agetstr("raflags", &bp))) { 309 val = 0; 310 if (strchr(flagstr, 'm')) 311 val |= ND_RA_FLAG_MANAGED; 312 if (strchr(flagstr, 'o')) 313 val |= ND_RA_FLAG_OTHER; 314 if (strchr(flagstr, 'h')) 315 val |= ND_RA_FLAG_RTPREF_HIGH; 316 if (strchr(flagstr, 'l')) { 317 if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 318 syslog(LOG_ERR, "<%s> the \'h\' and \'l\'" 319 " router flags are exclusive", __func__); 320 return (-1); 321 } 322 val |= ND_RA_FLAG_RTPREF_LOW; 323 } 324 } else 325 MAYHAVE(val, "raflags", 0); 326 327 rai->rai_managedflg = val & ND_RA_FLAG_MANAGED; 328 rai->rai_otherflg = val & ND_RA_FLAG_OTHER; 329#ifndef ND_RA_FLAG_RTPREF_MASK 330#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 331#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 332#endif 333 rai->rai_rtpref = val & ND_RA_FLAG_RTPREF_MASK; 334 if (rai->rai_rtpref == ND_RA_FLAG_RTPREF_RSV) { 335 syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s", 336 __func__, rai->rai_rtpref, intface); 337 return (-1); 338 } 339 340 MAYHAVE(val, "rltime", rai->rai_maxinterval * 3); 341 if ((u_int)val && ((u_int)val < rai->rai_maxinterval || 342 (u_int)val > MAXROUTERLIFETIME)) { 343 syslog(LOG_ERR, 344 "<%s> router lifetime (%ld) on %s is invalid " 345 "(must be 0 or between %d and %d)", 346 __func__, val, intface, rai->rai_maxinterval, 347 MAXROUTERLIFETIME); 348 return (-1); 349 } 350 rai->rai_lifetime = val & 0xffff; 351 352 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 353 if (val < 0 || val > MAXREACHABLETIME) { 354 syslog(LOG_ERR, 355 "<%s> reachable time (%ld) on %s is invalid " 356 "(must be no greater than %d)", 357 __func__, val, intface, MAXREACHABLETIME); 358 return (-1); 359 } 360 rai->rai_reachabletime = (u_int32_t)val; 361 362 MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); 363 if (val64 < 0 || val64 > 0xffffffff) { 364 syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range", 365 __func__, (long long)val64, intface); 366 return (-1); 367 } 368 rai->rai_retranstimer = (u_int32_t)val64; 369 370 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) { 371 syslog(LOG_ERR, 372 "<%s> mobile-ip6 configuration not supported", 373 __func__); 374 return (-1); 375 } 376 /* prefix information */ 377 378 /* 379 * This is an implementation specific parameter to consider 380 * link propagation delays and poorly synchronized clocks when 381 * checking consistency of advertised lifetimes. 382 */ 383 MAYHAVE(val, "clockskew", 0); 384 rai->rai_clockskew = val; 385 386 rai->rai_pfxs = 0; 387 for (i = -1; i < MAXPREFIX; i++) { 388 struct prefix *pfx; 389 390 makeentry(entbuf, sizeof(entbuf), i, "addr"); 391 addr = (char *)agetstr(entbuf, &bp); 392 if (addr == NULL) 393 continue; 394 395 /* allocate memory to store prefix information */ 396 ELM_MALLOC(pfx, exit(1)); 397 398 /* link into chain */ 399 TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 400 rai->rai_pfxs++; 401 pfx->pfx_origin = PREFIX_FROM_CONFIG; 402 403 if (inet_pton(AF_INET6, addr, &pfx->pfx_prefix) != 1) { 404 syslog(LOG_ERR, 405 "<%s> inet_pton failed for %s", 406 __func__, addr); 407 return (-1); 408 } 409 if (IN6_IS_ADDR_MULTICAST(&pfx->pfx_prefix)) { 410 syslog(LOG_ERR, 411 "<%s> multicast prefix (%s) must " 412 "not be advertised on %s", 413 __func__, addr, intface); 414 return (-1); 415 } 416 if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix)) 417 syslog(LOG_NOTICE, 418 "<%s> link-local prefix (%s) will be" 419 " advertised on %s", 420 __func__, addr, intface); 421 422 makeentry(entbuf, sizeof(entbuf), i, "prefixlen"); 423 MAYHAVE(val, entbuf, 64); 424 if (val < 0 || val > 128) { 425 syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s " 426 "on %s out of range", 427 __func__, val, addr, intface); 428 return (-1); 429 } 430 pfx->pfx_prefixlen = (int)val; 431 432 makeentry(entbuf, sizeof(entbuf), i, "pinfoflags"); 433 if ((flagstr = (char *)agetstr(entbuf, &bp))) { 434 val = 0; 435 if (strchr(flagstr, 'l')) 436 val |= ND_OPT_PI_FLAG_ONLINK; 437 if (strchr(flagstr, 'a')) 438 val |= ND_OPT_PI_FLAG_AUTO; 439 } else { 440 MAYHAVE(val, entbuf, 441 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 442 } 443 pfx->pfx_onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 444 pfx->pfx_autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 445 446 makeentry(entbuf, sizeof(entbuf), i, "vltime"); 447 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 448 if (val64 < 0 || val64 > 0xffffffff) { 449 syslog(LOG_ERR, "<%s> vltime (%lld) for " 450 "%s/%d on %s is out of range", 451 __func__, (long long)val64, 452 addr, pfx->pfx_prefixlen, intface); 453 return (-1); 454 } 455 pfx->pfx_validlifetime = (u_int32_t)val64; 456 457 makeentry(entbuf, sizeof(entbuf), i, "vltimedecr"); 458 if (agetflag(entbuf)) { 459 struct timeval now; 460 gettimeofday(&now, 0); 461 pfx->pfx_vltimeexpire = 462 now.tv_sec + pfx->pfx_validlifetime; 463 } 464 465 makeentry(entbuf, sizeof(entbuf), i, "pltime"); 466 MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); 467 if (val64 < 0 || val64 > 0xffffffff) { 468 syslog(LOG_ERR, 469 "<%s> pltime (%lld) for %s/%d on %s " 470 "is out of range", 471 __func__, (long long)val64, 472 addr, pfx->pfx_prefixlen, intface); 473 return (-1); 474 } 475 pfx->pfx_preflifetime = (u_int32_t)val64; 476 477 makeentry(entbuf, sizeof(entbuf), i, "pltimedecr"); 478 if (agetflag(entbuf)) { 479 struct timeval now; 480 gettimeofday(&now, 0); 481 pfx->pfx_pltimeexpire = 482 now.tv_sec + pfx->pfx_preflifetime; 483 } 484 } 485 if (rai->rai_advifprefix && rai->rai_pfxs == 0) 486 get_prefix(rai); 487 488 MAYHAVE(val, "mtu", 0); 489 if (val < 0 || (u_int)val > 0xffffffff) { 490 syslog(LOG_ERR, 491 "<%s> mtu (%ld) on %s out of range", 492 __func__, val, intface); 493 return (-1); 494 } 495 rai->rai_linkmtu = (u_int32_t)val; 496 if (rai->rai_linkmtu == 0) { 497 char *mtustr; 498 499 if ((mtustr = (char *)agetstr("mtu", &bp)) && 500 strcmp(mtustr, "auto") == 0) 501 rai->rai_linkmtu = rai->rai_phymtu; 502 } 503 else if (rai->rai_linkmtu < IPV6_MMTU || 504 rai->rai_linkmtu > rai->rai_phymtu) { 505 syslog(LOG_ERR, 506 "<%s> advertised link mtu (%lu) on %s is invalid (must " 507 "be between least MTU (%d) and physical link MTU (%d)", 508 __func__, (unsigned long)rai->rai_linkmtu, intface, 509 IPV6_MMTU, rai->rai_phymtu); 510 return (-1); 511 } 512 513#ifdef SIOCSIFINFO_IN6 514 { 515 struct in6_ndireq ndi; 516 int s; 517 518 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 519 syslog(LOG_ERR, "<%s> socket: %s", __func__, 520 strerror(errno)); 521 exit(1); 522 } 523 memset(&ndi, 0, sizeof(ndi)); 524 strncpy(ndi.ifname, intface, IFNAMSIZ); 525 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) 526 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s", 527 __func__, intface, strerror(errno)); 528 529 /* reflect the RA info to the host variables in kernel */ 530 ndi.ndi.chlim = rai->rai_hoplimit; 531 ndi.ndi.retrans = rai->rai_retranstimer; 532 ndi.ndi.basereachable = rai->rai_reachabletime; 533 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) 534 syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s", 535 __func__, intface, strerror(errno)); 536 537 close(s); 538 } 539#endif 540 541 /* route information */ 542#ifdef ROUTEINFO 543 rai->rai_routes = 0; 544 for (i = -1; i < MAXROUTE; i++) { 545 struct rtinfo *rti; 546 547 makeentry(entbuf, sizeof(entbuf), i, "rtprefix"); 548 addr = (char *)agetstr(entbuf, &bp); 549 if (addr == NULL) { 550 makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix"); 551 addr = (char *)agetstr(oentbuf, &bp); 552 if (addr) 553 fprintf(stderr, "%s was obsoleted. Use %s.\n", 554 oentbuf, entbuf); 555 } 556 if (addr == NULL) 557 continue; 558 559 /* allocate memory to store prefix information */ 560 ELM_MALLOC(rti, exit(1)); 561 562 /* link into chain */ 563 TAILQ_INSERT_TAIL(&rai->rai_route, rti, rti_next); 564 rai->rai_routes++; 565 566 if (inet_pton(AF_INET6, addr, &rti->rti_prefix) != 1) { 567 syslog(LOG_ERR, "<%s> inet_pton failed for %s", 568 __func__, addr); 569 return (-1); 570 } 571#if 0 572 /* 573 * XXX: currently there's no restriction in route information 574 * prefix according to 575 * draft-ietf-ipngwg-router-selection-00.txt. 576 * However, I think the similar restriction be necessary. 577 */ 578 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); 579 if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { 580 syslog(LOG_ERR, 581 "<%s> multicast route (%s) must " 582 "not be advertised on %s", 583 __func__, addr, intface); 584 return (-1); 585 } 586 if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { 587 syslog(LOG_NOTICE, 588 "<%s> link-local route (%s) will " 589 "be advertised on %s", 590 __func__, addr, intface); 591 return (-1); 592 } 593#endif 594 595 makeentry(entbuf, sizeof(entbuf), i, "rtplen"); 596 /* XXX: 256 is a magic number for compatibility check. */ 597 MAYHAVE(val, entbuf, 256); 598 if (val == 256) { 599 makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen"); 600 MAYHAVE(val, oentbuf, 256); 601 if (val != 256) 602 fprintf(stderr, "%s was obsoleted. Use %s.\n", 603 oentbuf, entbuf); 604 else 605 val = 64; 606 } 607 if (val < 0 || val > 128) { 608 syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s " 609 "out of range", 610 __func__, val, addr, intface); 611 return (-1); 612 } 613 rti->rti_prefixlen = (int)val; 614 615 makeentry(entbuf, sizeof(entbuf), i, "rtflags"); 616 if ((flagstr = (char *)agetstr(entbuf, &bp))) { 617 val = 0; 618 if (strchr(flagstr, 'h')) 619 val |= ND_RA_FLAG_RTPREF_HIGH; 620 if (strchr(flagstr, 'l')) { 621 if ((val & ND_RA_FLAG_RTPREF_HIGH)) { 622 syslog(LOG_ERR, 623 "<%s> the \'h\' and \'l\' route" 624 " preferences are exclusive", 625 __func__); 626 exit(1); 627 } 628 val |= ND_RA_FLAG_RTPREF_LOW; 629 } 630 } else 631 MAYHAVE(val, entbuf, 256); /* XXX */ 632 if (val == 256) { 633 makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags"); 634 MAYHAVE(val, oentbuf, 256); 635 if (val != 256) { 636 fprintf(stderr, "%s was obsoleted. Use %s.\n", 637 oentbuf, entbuf); 638 } else 639 val = 0; 640 } 641 rti->rti_rtpref = val & ND_RA_FLAG_RTPREF_MASK; 642 if (rti->rti_rtpref == ND_RA_FLAG_RTPREF_RSV) { 643 syslog(LOG_ERR, "<%s> invalid route preference (%02x) " 644 "for %s/%d on %s", 645 __func__, rti->rti_rtpref, addr, 646 rti->rti_prefixlen, intface); 647 return (-1); 648 } 649 650 /* 651 * Since the spec does not a default value, we should make 652 * this entry mandatory. However, FreeBSD 4.4 has shipped 653 * with this field being optional, we use the router lifetime 654 * as an ad-hoc default value with a warning message. 655 */ 656 makeentry(entbuf, sizeof(entbuf), i, "rtltime"); 657 MAYHAVE(val64, entbuf, -1); 658 if (val64 == -1) { 659 makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime"); 660 MAYHAVE(val64, oentbuf, -1); 661 if (val64 != -1) 662 fprintf(stderr, "%s was obsoleted. Use %s.\n", 663 oentbuf, entbuf); 664 else { 665 fprintf(stderr, "%s should be specified " 666 "for interface %s.\n", entbuf, intface); 667 val64 = rai->rai_lifetime; 668 } 669 } 670 if (val64 < 0 || val64 > 0xffffffff) { 671 syslog(LOG_ERR, "<%s> route lifetime (%lld) for " 672 "%s/%d on %s out of range", __func__, 673 (long long)val64, addr, rti->rti_prefixlen, intface); 674 return (-1); 675 } 676 rti->rti_ltime = (u_int32_t)val64; 677 } 678#endif 679 /* DNS server and DNS search list information */ 680 for (i = -1; i < MAXRDNSSENT ; i++) { 681 struct rdnss *rdn; 682 struct rdnss_addr *rdna; 683 char *ap; 684 int c; 685 686 makeentry(entbuf, sizeof(entbuf), i, "rdnss"); 687 addr = (char *)agetstr(entbuf, &bp); 688 if (addr == NULL) 689 break; 690 ELM_MALLOC(rdn, exit(1)); 691 692 TAILQ_INIT(&rdn->rd_list); 693 694 for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 695 c = strcspn(ap, ","); 696 strncpy(abuf, ap, c); 697 abuf[c] = '\0'; 698 ELM_MALLOC(rdna, exit(1)); 699 if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) { 700 syslog(LOG_ERR, "<%s> inet_pton failed for %s", 701 __func__, abuf); 702 free(rdna); 703 return (-1); 704 } 705 TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next); 706 } 707 708 makeentry(entbuf, sizeof(entbuf), i, "rdnssltime"); 709 MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2)); 710 if ((u_int)val < rai->rai_maxinterval || 711 (u_int)val > rai->rai_maxinterval * 2) { 712 syslog(LOG_ERR, "%s (%ld) on %s is invalid " 713 "(must be between %d and %d)", 714 entbuf, val, intface, rai->rai_maxinterval, 715 rai->rai_maxinterval * 2); 716 return (-1); 717 } 718 rdn->rd_ltime = val; 719 720 /* link into chain */ 721 TAILQ_INSERT_TAIL(&rai->rai_rdnss, rdn, rd_next); 722 } 723 724 for (i = -1; i < MAXDNSSLENT ; i++) { 725 struct dnssl *dns; 726 struct dnssl_addr *dnsa; 727 char *ap; 728 int c; 729 730 makeentry(entbuf, sizeof(entbuf), i, "dnssl"); 731 addr = (char *)agetstr(entbuf, &bp); 732 if (addr == NULL) 733 break; 734 735 ELM_MALLOC(dns, exit(1)); 736 737 TAILQ_INIT(&dns->dn_list); 738 739 for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) { 740 c = strcspn(ap, ","); 741 strncpy(abuf, ap, c); 742 abuf[c] = '\0'; 743 ELM_MALLOC(dnsa, exit(1)); 744 dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf); 745 syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__, 746 dnsa->da_len); 747 TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next); 748 } 749 750 makeentry(entbuf, sizeof(entbuf), i, "dnsslltime"); 751 MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2)); 752 if ((u_int)val < rai->rai_maxinterval || 753 (u_int)val > rai->rai_maxinterval * 2) { 754 syslog(LOG_ERR, "%s (%ld) on %s is invalid " 755 "(must be between %d and %d)", 756 entbuf, val, intface, rai->rai_maxinterval, 757 rai->rai_maxinterval * 2); 758 return (-1); 759 } 760 dns->dn_ltime = val; 761 762 /* link into chain */ 763 TAILQ_INSERT_TAIL(&rai->rai_dnssl, dns, dn_next); 764 } 765 /* construct the sending packet */ 766 make_packet(rai); 767 TAILQ_INSERT_TAIL(&railist, rai, rai_next); 768 769 /* set timer */ 770 rai->rai_timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 771 rai, rai); 772 ra_timer_update((void *)rai, &rai->rai_timer->rat_tm); 773 rtadvd_set_timer(&rai->rai_timer->rat_tm, rai->rai_timer); 774 775 return (0); 776} 777 778void 779get_prefix(struct rainfo *rai) 780{ 781 struct ifaddrs *ifap, *ifa; 782 struct prefix *pfx; 783 struct in6_addr *a; 784 u_char *p, *ep, *m, *lim; 785 u_char ntopbuf[INET6_ADDRSTRLEN]; 786 787 if (getifaddrs(&ifap) < 0) { 788 syslog(LOG_ERR, 789 "<%s> can't get interface addresses", 790 __func__); 791 exit(1); 792 } 793 794 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 795 int plen; 796 797 if (strcmp(ifa->ifa_name, rai->rai_ifname) != 0) 798 continue; 799 if (ifa->ifa_addr->sa_family != AF_INET6) 800 continue; 801 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 802 if (IN6_IS_ADDR_LINKLOCAL(a)) 803 continue; 804 /* get prefix length */ 805 m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 806 lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; 807 plen = prefixlen(m, lim); 808 if (plen <= 0 || plen > 128) { 809 syslog(LOG_ERR, "<%s> failed to get prefixlen " 810 "or prefix is invalid", 811 __func__); 812 exit(1); 813 } 814 if (plen == 128) /* XXX */ 815 continue; 816 if (find_prefix(rai, a, plen)) { 817 /* ignore a duplicated prefix. */ 818 continue; 819 } 820 821 /* allocate memory to store prefix info. */ 822 ELM_MALLOC(pfx, exit(1)); 823 824 /* set prefix, sweep bits outside of prefixlen */ 825 pfx->pfx_prefixlen = plen; 826 memcpy(&pfx->pfx_prefix, a, sizeof(*a)); 827 p = (u_char *)&pfx->pfx_prefix; 828 ep = (u_char *)(&pfx->pfx_prefix + 1); 829 while (m < lim && p < ep) 830 *p++ &= *m++; 831 while (p < ep) 832 *p++ = 0x00; 833 if (!inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 834 sizeof(ntopbuf))) { 835 syslog(LOG_ERR, "<%s> inet_ntop failed", __func__); 836 exit(1); 837 } 838 syslog(LOG_DEBUG, 839 "<%s> add %s/%d to prefix list on %s", 840 __func__, ntopbuf, pfx->pfx_prefixlen, rai->rai_ifname); 841 842 /* set other fields with protocol defaults */ 843 pfx->pfx_validlifetime = DEF_ADVVALIDLIFETIME; 844 pfx->pfx_preflifetime = DEF_ADVPREFERREDLIFETIME; 845 pfx->pfx_onlinkflg = 1; 846 pfx->pfx_autoconfflg = 1; 847 pfx->pfx_origin = PREFIX_FROM_KERNEL; 848 pfx->pfx_rainfo = rai; 849 850 /* link into chain */ 851 TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 852 853 /* counter increment */ 854 rai->rai_pfxs++; 855 } 856 857 freeifaddrs(ifap); 858} 859 860static void 861makeentry(char *buf, size_t len, int id, const char *string) 862{ 863 864 if (id < 0) 865 strlcpy(buf, string, len); 866 else 867 snprintf(buf, len, "%s%d", string, id); 868} 869 870/* 871 * Add a prefix to the list of specified interface and reconstruct 872 * the outgoing packet. 873 * The prefix must not be in the list. 874 * XXX: other parameters of the prefix (e.g. lifetime) should be 875 * able to be specified. 876 */ 877static void 878add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 879{ 880 struct prefix *pfx; 881 u_char ntopbuf[INET6_ADDRSTRLEN]; 882 883 ELM_MALLOC(pfx, return); 884 pfx->pfx_prefix = ipr->ipr_prefix.sin6_addr; 885 pfx->pfx_prefixlen = ipr->ipr_plen; 886 pfx->pfx_validlifetime = ipr->ipr_vltime; 887 pfx->pfx_preflifetime = ipr->ipr_pltime; 888 pfx->pfx_onlinkflg = ipr->ipr_raf_onlink; 889 pfx->pfx_autoconfflg = ipr->ipr_raf_auto; 890 pfx->pfx_origin = PREFIX_FROM_DYNAMIC; 891 892 TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next); 893 pfx->pfx_rainfo = rai; 894 895 syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 896 __func__, 897 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 898 sizeof(ntopbuf)), ipr->ipr_plen, rai->rai_ifname); 899 900 /* reconstruct the packet */ 901 rai->rai_pfxs++; 902 make_packet(rai); 903} 904 905/* 906 * Delete a prefix to the list of specified interface and reconstruct 907 * the outgoing packet. 908 * The prefix must be in the list. 909 */ 910void 911delete_prefix(struct prefix *pfx) 912{ 913 u_char ntopbuf[INET6_ADDRSTRLEN]; 914 struct rainfo *rai; 915 916 rai = pfx->pfx_rainfo; 917 TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next); 918 syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 919 __func__, 920 inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 921 sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname); 922 if (pfx->pfx_timer) 923 rtadvd_remove_timer(pfx->pfx_timer); 924 free(pfx); 925 rai->rai_pfxs--; 926 make_packet(rai); 927} 928 929void 930invalidate_prefix(struct prefix *pfx) 931{ 932 u_char ntopbuf[INET6_ADDRSTRLEN]; 933 struct timeval timo; 934 struct rainfo *rai; 935 936 rai = pfx->pfx_rainfo; 937 if (pfx->pfx_timer) { /* sanity check */ 938 syslog(LOG_ERR, 939 "<%s> assumption failure: timer already exists", 940 __func__); 941 exit(1); 942 } 943 944 syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, " 945 "will expire in %ld seconds", __func__, 946 inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, sizeof(ntopbuf)), 947 pfx->pfx_prefixlen, rai->rai_ifname, (long)prefix_timo); 948 949 /* set the expiration timer */ 950 pfx->pfx_timer = rtadvd_add_timer(prefix_timeout, NULL, pfx, NULL); 951 if (pfx->pfx_timer == NULL) { 952 syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. " 953 "remove the prefix", __func__); 954 delete_prefix(pfx); 955 } 956 timo.tv_sec = prefix_timo; 957 timo.tv_usec = 0; 958 rtadvd_set_timer(&timo, pfx->pfx_timer); 959} 960 961static struct rtadvd_timer * 962prefix_timeout(void *arg) 963{ 964 965 delete_prefix((struct prefix *)arg); 966 967 return (NULL); 968} 969 970void 971update_prefix(struct prefix *pfx) 972{ 973 u_char ntopbuf[INET6_ADDRSTRLEN]; 974 struct rainfo *rai; 975 976 rai = pfx->pfx_rainfo; 977 if (pfx->pfx_timer == NULL) { /* sanity check */ 978 syslog(LOG_ERR, 979 "<%s> assumption failure: timer does not exist", 980 __func__); 981 exit(1); 982 } 983 984 syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s", 985 __func__, inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, 986 sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname); 987 988 /* stop the expiration timer */ 989 rtadvd_remove_timer(pfx->pfx_timer); 990 pfx->pfx_timer = NULL; 991} 992 993/* 994 * Try to get an in6_prefixreq contents for a prefix which matches 995 * ipr->ipr_prefix and ipr->ipr_plen and belongs to 996 * the interface whose name is ipr->ipr_name[]. 997 */ 998static int 999init_prefix(struct in6_prefixreq *ipr) 1000{ 1001#if 0 1002 int s; 1003 1004 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1005 syslog(LOG_ERR, "<%s> socket: %s", __func__, 1006 strerror(errno)); 1007 exit(1); 1008 } 1009 1010 if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 1011 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__, 1012 strerror(errno)); 1013 1014 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 1015 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 1016 ipr->ipr_raf_onlink = 1; 1017 ipr->ipr_raf_auto = 1; 1018 /* omit other field initialization */ 1019 } 1020 else if (ipr->ipr_origin < PR_ORIG_RR) { 1021 u_char ntopbuf[INET6_ADDRSTRLEN]; 1022 1023 syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 1024 "lower than PR_ORIG_RR(router renumbering)." 1025 "This should not happen if I am router", __func__, 1026 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 1027 sizeof(ntopbuf)), ipr->ipr_origin); 1028 close(s); 1029 return (1); 1030 } 1031 1032 close(s); 1033 return (0); 1034#else 1035 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 1036 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 1037 ipr->ipr_raf_onlink = 1; 1038 ipr->ipr_raf_auto = 1; 1039 return (0); 1040#endif 1041} 1042 1043void 1044make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 1045{ 1046 struct in6_prefixreq ipr; 1047 1048 memset(&ipr, 0, sizeof(ipr)); 1049 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 1050 syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 1051 "exist. This should not happen! %s", __func__, 1052 ifindex, strerror(errno)); 1053 exit(1); 1054 } 1055 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 1056 ipr.ipr_prefix.sin6_family = AF_INET6; 1057 ipr.ipr_prefix.sin6_addr = *addr; 1058 ipr.ipr_plen = plen; 1059 1060 if (init_prefix(&ipr)) 1061 return; /* init failed by some error */ 1062 add_prefix(rai, &ipr); 1063} 1064 1065void 1066make_packet(struct rainfo *rai) 1067{ 1068 size_t packlen, lladdroptlen = 0; 1069 char *buf; 1070 struct nd_router_advert *ra; 1071 struct nd_opt_prefix_info *ndopt_pi; 1072 struct nd_opt_mtu *ndopt_mtu; 1073#ifdef ROUTEINFO 1074 struct nd_opt_route_info *ndopt_rti; 1075 struct rtinfo *rti; 1076#endif 1077 struct nd_opt_rdnss *ndopt_rdnss; 1078 struct rdnss *rdn; 1079 struct nd_opt_dnssl *ndopt_dnssl; 1080 struct dnssl *dns; 1081 size_t len; 1082 struct prefix *pfx; 1083 1084 /* calculate total length */ 1085 packlen = sizeof(struct nd_router_advert); 1086 if (rai->rai_advlinkopt) { 1087 if ((lladdroptlen = lladdropt_length(rai->rai_sdl)) == 0) { 1088 syslog(LOG_INFO, 1089 "<%s> link-layer address option has" 1090 " null length on %s. Treat as not included.", 1091 __func__, rai->rai_ifname); 1092 rai->rai_advlinkopt = 0; 1093 } 1094 packlen += lladdroptlen; 1095 } 1096 if (rai->rai_pfxs) 1097 packlen += sizeof(struct nd_opt_prefix_info) * rai->rai_pfxs; 1098 if (rai->rai_linkmtu) 1099 packlen += sizeof(struct nd_opt_mtu); 1100#ifdef ROUTEINFO 1101 TAILQ_FOREACH(rti, &rai->rai_route, rti_next) 1102 packlen += sizeof(struct nd_opt_route_info) + 1103 ((rti->rti_prefixlen + 0x3f) >> 6) * 8; 1104#endif 1105 TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { 1106 struct rdnss_addr *rdna; 1107 1108 packlen += sizeof(struct nd_opt_rdnss); 1109 TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) 1110 packlen += sizeof(rdna->ra_dns); 1111 } 1112 TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { 1113 struct dnssl_addr *dnsa; 1114 1115 packlen += sizeof(struct nd_opt_dnssl); 1116 len = 0; 1117 TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) 1118 len += dnsa->da_len; 1119 1120 /* A zero octet and 8 octet boundary */ 1121 len++; 1122 len += (len % 8) ? 8 - len % 8 : 0; 1123 1124 packlen += len; 1125 } 1126 /* allocate memory for the packet */ 1127 if ((buf = malloc(packlen)) == NULL) { 1128 syslog(LOG_ERR, 1129 "<%s> can't get enough memory for an RA packet", 1130 __func__); 1131 exit(1); 1132 } 1133 memset(buf, 0, packlen); 1134 if (rai->rai_ra_data) /* Free old data if any. */ 1135 free(rai->rai_ra_data); 1136 rai->rai_ra_data = buf; 1137 /* XXX: what if packlen > 576? */ 1138 rai->rai_ra_datalen = packlen; 1139 1140 /* 1141 * construct the packet 1142 */ 1143 ra = (struct nd_router_advert *)buf; 1144 ra->nd_ra_type = ND_ROUTER_ADVERT; 1145 ra->nd_ra_code = 0; 1146 ra->nd_ra_cksum = 0; 1147 ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rai->rai_hoplimit); 1148 ra->nd_ra_flags_reserved = 0; /* just in case */ 1149 /* 1150 * XXX: the router preference field, which is a 2-bit field, should be 1151 * initialized before other fields. 1152 */ 1153 ra->nd_ra_flags_reserved = 0xff & rai->rai_rtpref; 1154 ra->nd_ra_flags_reserved |= 1155 rai->rai_managedflg ? ND_RA_FLAG_MANAGED : 0; 1156 ra->nd_ra_flags_reserved |= 1157 rai->rai_otherflg ? ND_RA_FLAG_OTHER : 0; 1158 ra->nd_ra_router_lifetime = htons(rai->rai_lifetime); 1159 ra->nd_ra_reachable = htonl(rai->rai_reachabletime); 1160 ra->nd_ra_retransmit = htonl(rai->rai_retranstimer); 1161 buf += sizeof(*ra); 1162 1163 if (rai->rai_advlinkopt) { 1164 lladdropt_fill(rai->rai_sdl, (struct nd_opt_hdr *)buf); 1165 buf += lladdroptlen; 1166 } 1167 1168 if (rai->rai_linkmtu) { 1169 ndopt_mtu = (struct nd_opt_mtu *)buf; 1170 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 1171 ndopt_mtu->nd_opt_mtu_len = 1; 1172 ndopt_mtu->nd_opt_mtu_reserved = 0; 1173 ndopt_mtu->nd_opt_mtu_mtu = htonl(rai->rai_linkmtu); 1174 buf += sizeof(struct nd_opt_mtu); 1175 } 1176 1177 TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { 1178 u_int32_t vltime, pltime; 1179 struct timeval now; 1180 1181 ndopt_pi = (struct nd_opt_prefix_info *)buf; 1182 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 1183 ndopt_pi->nd_opt_pi_len = 4; 1184 ndopt_pi->nd_opt_pi_prefix_len = pfx->pfx_prefixlen; 1185 ndopt_pi->nd_opt_pi_flags_reserved = 0; 1186 if (pfx->pfx_onlinkflg) 1187 ndopt_pi->nd_opt_pi_flags_reserved |= 1188 ND_OPT_PI_FLAG_ONLINK; 1189 if (pfx->pfx_autoconfflg) 1190 ndopt_pi->nd_opt_pi_flags_reserved |= 1191 ND_OPT_PI_FLAG_AUTO; 1192 if (pfx->pfx_timer) 1193 vltime = 0; 1194 else { 1195 if (pfx->pfx_vltimeexpire || pfx->pfx_pltimeexpire) 1196 gettimeofday(&now, NULL); 1197 if (pfx->pfx_vltimeexpire == 0) 1198 vltime = pfx->pfx_validlifetime; 1199 else 1200 vltime = (pfx->pfx_vltimeexpire > now.tv_sec) ? 1201 pfx->pfx_vltimeexpire - now.tv_sec : 0; 1202 } 1203 if (pfx->pfx_timer) 1204 pltime = 0; 1205 else { 1206 if (pfx->pfx_pltimeexpire == 0) 1207 pltime = pfx->pfx_preflifetime; 1208 else 1209 pltime = (pfx->pfx_pltimeexpire > now.tv_sec) ? 1210 pfx->pfx_pltimeexpire - now.tv_sec : 0; 1211 } 1212 if (vltime < pltime) { 1213 /* 1214 * this can happen if vltime is decrement but pltime 1215 * is not. 1216 */ 1217 pltime = vltime; 1218 } 1219 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 1220 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 1221 ndopt_pi->nd_opt_pi_reserved2 = 0; 1222 ndopt_pi->nd_opt_pi_prefix = pfx->pfx_prefix; 1223 1224 buf += sizeof(struct nd_opt_prefix_info); 1225 } 1226 1227#ifdef ROUTEINFO 1228 TAILQ_FOREACH(rti, &rai->rai_route, rti_next) { 1229 u_int8_t psize = (rti->rti_prefixlen + 0x3f) >> 6; 1230 1231 ndopt_rti = (struct nd_opt_route_info *)buf; 1232 ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; 1233 ndopt_rti->nd_opt_rti_len = 1 + psize; 1234 ndopt_rti->nd_opt_rti_prefixlen = rti->rti_prefixlen; 1235 ndopt_rti->nd_opt_rti_flags = 0xff & rti->rti_rtpref; 1236 ndopt_rti->nd_opt_rti_lifetime = htonl(rti->rti_ltime); 1237 memcpy(ndopt_rti + 1, &rti->rti_prefix, psize * 8); 1238 buf += sizeof(struct nd_opt_route_info) + psize * 8; 1239 } 1240#endif 1241 TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) { 1242 struct rdnss_addr *rdna; 1243 1244 ndopt_rdnss = (struct nd_opt_rdnss *)buf; 1245 ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; 1246 ndopt_rdnss->nd_opt_rdnss_len = 0; 1247 ndopt_rdnss->nd_opt_rdnss_reserved = 0; 1248 ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdn->rd_ltime); 1249 buf += sizeof(struct nd_opt_rdnss); 1250 1251 TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) { 1252 memcpy(buf, &rdna->ra_dns, sizeof(rdna->ra_dns)); 1253 buf += sizeof(rdna->ra_dns); 1254 } 1255 /* Length field should be in 8 octets */ 1256 ndopt_rdnss->nd_opt_rdnss_len = (buf - (char *)ndopt_rdnss) / 8; 1257 1258 syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__, 1259 ndopt_rdnss->nd_opt_rdnss_len); 1260 } 1261 TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) { 1262 struct dnssl_addr *dnsa; 1263 1264 ndopt_dnssl = (struct nd_opt_dnssl *)buf; 1265 ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL; 1266 ndopt_dnssl->nd_opt_dnssl_len = 0; 1267 ndopt_dnssl->nd_opt_dnssl_reserved = 0; 1268 ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dns->dn_ltime); 1269 buf += sizeof(*ndopt_dnssl); 1270 1271 TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) { 1272 memcpy(buf, dnsa->da_dom, dnsa->da_len); 1273 buf += dnsa->da_len; 1274 } 1275 1276 /* A zero octet after encoded DNS server list. */ 1277 *buf++ = '\0'; 1278 1279 /* Padding to next 8 octets boundary */ 1280 len = buf - (char *)ndopt_dnssl; 1281 len += (len % 8) ? 8 - len % 8 : 0; 1282 1283 /* Length field must be in 8 octets */ 1284 ndopt_dnssl->nd_opt_dnssl_len = len / 8; 1285 1286 syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__, 1287 ndopt_dnssl->nd_opt_dnssl_len); 1288 } 1289 return; 1290} 1291