config.c revision 71437
1/* $FreeBSD: head/usr.sbin/rtadvd/config.c 71437 2001-01-23 17:29:12Z ume $ */ 2/* $KAME: config.c,v 1.11 2000/05/16 13:34:13 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#if defined(__FreeBSD__) && __FreeBSD__ >= 3 40#include <net/if_var.h> 41#endif /* __FreeBSD__ >= 3 */ 42#include <net/route.h> 43#include <net/if_dl.h> 44 45#include <netinet/in.h> 46#include <netinet/in_var.h> 47#include <netinet/ip6.h> 48#include <netinet6/ip6_var.h> 49#include <netinet/icmp6.h> 50#ifdef MIP6 51#include <netinet6/mip6.h> 52#endif 53 54#include <arpa/inet.h> 55 56#include <stdio.h> 57#include <syslog.h> 58#include <errno.h> 59#include <string.h> 60#include <stdlib.h> 61#if defined(__NetBSD__) || defined(__OpenBSD__) 62#include <search.h> 63#endif 64#include <unistd.h> 65 66#include "rtadvd.h" 67#include "advcap.h" 68#include "timer.h" 69#include "if.h" 70#include "config.h" 71 72static void makeentry __P((char *, int, char *, int)); 73static void get_prefix __P((struct rainfo *)); 74 75extern struct rainfo *ralist; 76 77void 78getconfig(intface) 79 char *intface; 80{ 81 int stat, pfxs, i; 82 char tbuf[BUFSIZ]; 83 struct rainfo *tmp; 84 long val; 85 char buf[BUFSIZ]; 86 char *bp = buf; 87 char *addr; 88 89#define MUSTHAVE(var, cap) \ 90 do { \ 91 int t; \ 92 if ((t = agetnum(cap)) < 0) { \ 93 fprintf(stderr, "rtadvd: need %s for interface %s\n", \ 94 cap, intface); \ 95 exit(1); \ 96 } \ 97 var = t; \ 98 } while (0) 99#define MAYHAVE(var, cap, def) \ 100 do { \ 101 if ((var = agetnum(cap)) < 0) \ 102 var = def; \ 103 } while (0) 104 105 if ((stat = agetent(tbuf, intface)) <= 0) { 106 memset(tbuf, 0, sizeof(tbuf)); 107 syslog(LOG_INFO, 108 "<%s> %s isn't defined in the configuration file" 109 " or the configuration file doesn't exist." 110 " Treat it as default", 111 __FUNCTION__, intface); 112 } 113 114 tmp = (struct rainfo *)malloc(sizeof(*ralist)); 115 memset(tmp, 0, sizeof(*tmp)); 116 tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; 117 118 /* get interface information */ 119 if (agetflag("nolladdr")) 120 tmp->advlinkopt = 0; 121 else 122 tmp->advlinkopt = 1; 123 if (tmp->advlinkopt) { 124 if ((tmp->sdl = if_nametosdl(intface)) == NULL) { 125 syslog(LOG_ERR, 126 "<%s> can't get information of %s", 127 __FUNCTION__, intface); 128 exit(1); 129 } 130 tmp->ifindex = tmp->sdl->sdl_index; 131 } else 132 tmp->ifindex = if_nametoindex(intface); 133 strncpy(tmp->ifname, intface, sizeof(tmp->ifname)); 134 if ((tmp->phymtu = if_getmtu(intface)) == 0) { 135 tmp->phymtu = IPV6_MMTU; 136 syslog(LOG_WARNING, 137 "<%s> can't get interface mtu of %s. Treat as %d", 138 __FUNCTION__, intface, IPV6_MMTU); 139 } 140 141 /* 142 * set router configuration variables. 143 */ 144 MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); 145 if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { 146 syslog(LOG_ERR, 147 "<%s> maxinterval must be between %e and %u", 148 __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL); 149 exit(1); 150 } 151 tmp->maxinterval = (u_int)val; 152 MAYHAVE(val, "mininterval", tmp->maxinterval/3); 153 if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { 154 syslog(LOG_ERR, 155 "<%s> mininterval must be between %e and %d", 156 __FUNCTION__, 157 MIN_MININTERVAL, 158 (tmp->maxinterval * 3) / 4); 159 exit(1); 160 } 161 tmp->mininterval = (u_int)val; 162 163 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); 164 tmp->hoplimit = val & 0xff; 165 166 MAYHAVE(val, "raflags", 0); 167 tmp->managedflg= val & ND_RA_FLAG_MANAGED; 168 tmp->otherflg = val & ND_RA_FLAG_OTHER; 169#ifdef MIP6 170 if (mobileip6) 171 tmp->haflg = val & ND_RA_FLAG_HA; 172#endif 173 174 MAYHAVE(val, "rltime", tmp->maxinterval * 3); 175 if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { 176 syslog(LOG_ERR, 177 "<%s> router lifetime on %s must be 0 or" 178 " between %d and %d", 179 __FUNCTION__, intface, 180 tmp->maxinterval, MAXROUTERLIFETIME); 181 exit(1); 182 } 183 tmp->lifetime = val & 0xffff; 184 185 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); 186 if (val > MAXREACHABLETIME) { 187 syslog(LOG_ERR, 188 "<%s> reachable time must be no greater than %d", 189 __FUNCTION__, MAXREACHABLETIME); 190 exit(1); 191 } 192 tmp->reachabletime = (u_int32_t)val; 193 194 MAYHAVE(val, "retrans", DEF_ADVRETRANSTIMER); 195 if (val < 0 || val > 0xffffffff) { 196 syslog(LOG_ERR, 197 "<%s> retrans time out of range", __FUNCTION__); 198 exit(1); 199 } 200 tmp->retranstimer = (u_int32_t)val; 201 202#ifdef MIP6 203 if (!mobileip6) 204#else 205 if (1) 206#endif 207 { 208 if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { 209 syslog(LOG_ERR, 210 "<%s> mobile-ip6 configuration without " 211 "proper command line option", 212 __FUNCTION__); 213 exit(1); 214 } 215 } 216#ifdef MIP6 217 else { 218 tmp->hapref = 0; 219 if ((val = agetnum("hapref")) >= 0) 220 tmp->hapref = (int16_t)val; 221 if (tmp->hapref != 0) { 222 tmp->hatime = 0; 223 MUSTHAVE(val, "hatime"); 224 tmp->hatime = (u_int16_t)val; 225 if (tmp->hatime <= 0) { 226 syslog(LOG_ERR, 227 "<%s> home agent lifetime must be greater than 0", 228 __FUNCTION__); 229 exit(1); 230 } 231 } 232 } 233#endif 234 235 /* prefix information */ 236 if ((pfxs = agetnum("addrs")) < 0) { 237 /* auto configure prefix information */ 238 if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { 239 syslog(LOG_ERR, 240 "<%s> conflicting prefix configuration for %s: " 241 "automatic and manual config at the same time", 242 __FUNCTION__, intface); 243 exit(1); 244 } 245 get_prefix(tmp); 246 } 247 else { 248 tmp->pfxs = pfxs; 249 for (i = 0; i < pfxs; i++) { 250 struct prefix *pfx; 251 char entbuf[256]; 252 int added = (pfxs > 1) ? 1 : 0; 253 254 /* allocate memory to store prefix information */ 255 if ((pfx = malloc(sizeof(struct prefix))) == NULL) { 256 syslog(LOG_ERR, 257 "<%s> can't allocate enough memory", 258 __FUNCTION__); 259 exit(1); 260 } 261 memset(pfx, 0, sizeof(*pfx)); 262 263 /* link into chain */ 264 insque(pfx, &tmp->prefix); 265 266 pfx->origin = PREFIX_FROM_CONFIG; 267 268 makeentry(entbuf, i, "prefixlen", added); 269 MAYHAVE(val, entbuf, 64); 270 if (val < 0 || val > 128) { 271 syslog(LOG_ERR, 272 "<%s> prefixlen out of range", 273 __FUNCTION__); 274 exit(1); 275 } 276 pfx->prefixlen = (int)val; 277 278 makeentry(entbuf, i, "pinfoflags", added); 279#ifdef MIP6 280 if (mobileip6) 281 { 282 MAYHAVE(val, entbuf, 283 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| 284 ND_OPT_PI_FLAG_RTADDR)); 285 } else 286#endif 287 { 288 MAYHAVE(val, entbuf, 289 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); 290 } 291 pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; 292 pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; 293#ifdef MIP6 294 if (mobileip6) 295 pfx->routeraddr = val & ND_OPT_PI_FLAG_RTADDR; 296#endif 297 298 makeentry(entbuf, i, "vltime", added); 299 MAYHAVE(val, entbuf, DEF_ADVVALIDLIFETIME); 300 if (val < 0 || val > 0xffffffff) { 301 syslog(LOG_ERR, 302 "<%s> vltime out of range", 303 __FUNCTION__); 304 exit(1); 305 } 306 pfx->validlifetime = (u_int32_t)val; 307 308 makeentry(entbuf, i, "pltime", added); 309 MAYHAVE(val, entbuf, DEF_ADVPREFERREDLIFETIME); 310 if (val < 0 || val > 0xffffffff) { 311 syslog(LOG_ERR, 312 "<%s> pltime out of range", 313 __FUNCTION__); 314 exit(1); 315 } 316 pfx->preflifetime = (u_int32_t)val; 317 318 makeentry(entbuf, i, "addr", added); 319 addr = (char *)agetstr(entbuf, &bp); 320 if (addr == NULL) { 321 syslog(LOG_ERR, 322 "<%s> need %s as an prefix for " 323 "interface %s", 324 __FUNCTION__, entbuf, intface); 325 exit(1); 326 } 327 if (inet_pton(AF_INET6, addr, 328 &pfx->prefix) != 1) { 329 syslog(LOG_ERR, 330 "<%s> inet_pton failed for %s", 331 __FUNCTION__, addr); 332 exit(1); 333 } 334 if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { 335 syslog(LOG_ERR, 336 "<%s> multicast prefix(%s) must " 337 "not be advertised (IF=%s)", 338 __FUNCTION__, addr, intface); 339 exit(1); 340 } 341 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) 342 syslog(LOG_NOTICE, 343 "<%s> link-local prefix(%s) will be" 344 " advertised on %s", 345 __FUNCTION__, addr, intface); 346 } 347 } 348 349 MAYHAVE(val, "mtu", 0); 350 if (val < 0 || val > 0xffffffff) { 351 syslog(LOG_ERR, 352 "<%s> mtu out of range", __FUNCTION__); 353 exit(1); 354 } 355 tmp->linkmtu = (u_int32_t)val; 356 if (tmp->linkmtu == 0) { 357 char *mtustr; 358 359 if ((mtustr = (char *)agetstr("mtu", &bp)) && 360 strcmp(mtustr, "auto") == 0) 361 tmp->linkmtu = tmp->phymtu; 362 } 363 else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { 364 syslog(LOG_ERR, 365 "<%s> advertised link mtu must be between" 366 " least MTU and physical link MTU", 367 __FUNCTION__); 368 exit(1); 369 } 370 371 /* okey */ 372 tmp->next = ralist; 373 ralist = tmp; 374 375 /* construct the sending packet */ 376 make_packet(tmp); 377 378 /* set timer */ 379 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, 380 tmp, tmp); 381 ra_timer_update((void *)tmp, &tmp->timer->tm); 382 rtadvd_set_timer(&tmp->timer->tm, tmp->timer); 383} 384 385static void 386get_prefix(struct rainfo *rai) 387{ 388 size_t len; 389 u_char *buf, *lim, *next; 390 u_char ntopbuf[INET6_ADDRSTRLEN]; 391 392 if ((len = rtbuf_len()) < 0) { 393 syslog(LOG_ERR, 394 "<%s> can't get buffer length for routing info", 395 __FUNCTION__); 396 exit(1); 397 } 398 if ((buf = malloc(len)) == NULL) { 399 syslog(LOG_ERR, 400 "<%s> can't allocate buffer", __FUNCTION__); 401 exit(1); 402 } 403 if (get_rtinfo(buf, &len) < 0) { 404 syslog(LOG_ERR, 405 "<%s> can't get routing inforamtion", __FUNCTION__); 406 exit(1); 407 } 408 409 lim = buf + len; 410 next = get_next_msg(buf, lim, rai->ifindex, &len, 411 RTADV_TYPE2BITMASK(RTM_GET)); 412 while (next < lim) { 413 struct prefix *pp; 414 struct in6_addr *a; 415 416 /* allocate memory to store prefix info. */ 417 if ((pp = malloc(sizeof(*pp))) == NULL) { 418 syslog(LOG_ERR, 419 "<%s> can't get allocate buffer for prefix", 420 __FUNCTION__); 421 exit(1); 422 } 423 memset(pp, 0, sizeof(*pp)); 424 425 /* set prefix and its length */ 426 a = get_addr(next); 427 memcpy(&pp->prefix, a, sizeof(*a)); 428 if ((pp->prefixlen = get_prefixlen(next)) < 0) { 429 syslog(LOG_ERR, 430 "<%s> failed to get prefixlen " 431 "or prefixl is invalid", 432 __FUNCTION__); 433 exit(1); 434 } 435 syslog(LOG_DEBUG, 436 "<%s> add %s/%d to prefix list on %s", 437 __FUNCTION__, 438 inet_ntop(AF_INET6, a, ntopbuf, INET6_ADDRSTRLEN), 439 pp->prefixlen, rai->ifname); 440 441 /* set other fields with protocol defaults */ 442 pp->validlifetime = DEF_ADVVALIDLIFETIME; 443 pp->preflifetime = DEF_ADVPREFERREDLIFETIME; 444 pp->onlinkflg = 1; 445 pp->autoconfflg = 1; 446 pp->origin = PREFIX_FROM_KERNEL; 447 448 /* link into chain */ 449 insque(pp, &rai->prefix); 450 451 /* counter increment */ 452 rai->pfxs++; 453 454 /* forward pointer and get next prefix(if any) */ 455 next += len; 456 next = get_next_msg(next, lim, rai->ifindex, 457 &len, RTADV_TYPE2BITMASK(RTM_GET)); 458 } 459 460 free(buf); 461} 462 463static void 464makeentry(buf, id, string, add) 465 char *buf, *string; 466 int id, add; 467{ 468 strcpy(buf, string); 469 if (add) { 470 char *cp; 471 472 cp = (char *)index(buf, '\0'); 473 cp += sprintf(cp, "%d", id); 474 *cp = '\0'; 475 } 476} 477 478/* 479 * Add a prefix to the list of specified interface and reconstruct 480 * the outgoing packet. 481 * The prefix must not be in the list. 482 * XXX: other parameter of the prefix(e.g. lifetime) shoule be 483 * able to be specified. 484 */ 485static void 486add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) 487{ 488 struct prefix *prefix; 489 u_char ntopbuf[INET6_ADDRSTRLEN]; 490 491 if ((prefix = malloc(sizeof(*prefix))) == NULL) { 492 syslog(LOG_ERR, "<%s> memory allocation failed", 493 __FUNCTION__); 494 return; /* XXX: error or exit? */ 495 } 496 prefix->prefix = ipr->ipr_prefix.sin6_addr; 497 prefix->prefixlen = ipr->ipr_plen; 498 prefix->validlifetime = ipr->ipr_vltime; 499 prefix->preflifetime = ipr->ipr_pltime; 500 prefix->onlinkflg = ipr->ipr_raf_onlink; 501 prefix->autoconfflg = ipr->ipr_raf_auto; 502 prefix->origin = PREFIX_FROM_DYNAMIC; 503 504 insque(prefix, &rai->prefix); 505 506 syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", 507 __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, 508 ntopbuf, INET6_ADDRSTRLEN), 509 ipr->ipr_plen, rai->ifname); 510 511 /* free the previous packet */ 512 free(rai->ra_data); 513 rai->ra_data = 0; 514 515 /* reconstruct the packet */ 516 rai->pfxs++; 517 make_packet(rai); 518 519 /* 520 * reset the timer so that the new prefix will be advertised quickly. 521 */ 522 rai->initcounter = 0; 523 ra_timer_update((void *)rai, &rai->timer->tm); 524 rtadvd_set_timer(&rai->timer->tm, rai->timer); 525} 526 527/* 528 * Delete a prefix to the list of specified interface and reconstruct 529 * the outgoing packet. 530 * The prefix must be in the list. 531 */ 532void 533delete_prefix(struct rainfo *rai, struct prefix *prefix) 534{ 535 u_char ntopbuf[INET6_ADDRSTRLEN]; 536 537 remque(prefix); 538 syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", 539 __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, 540 ntopbuf, INET6_ADDRSTRLEN), 541 prefix->prefixlen, rai->ifname); 542 free(prefix); 543 rai->pfxs--; 544 make_packet(rai); 545} 546 547/* 548 * Try to get an in6_prefixreq contents for a prefix which matches 549 * ipr->ipr_prefix and ipr->ipr_plen and belongs to 550 * the interface whose name is ipr->ipr_name[]. 551 */ 552static int 553init_prefix(struct in6_prefixreq *ipr) 554{ 555 int s; 556 557 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 558 syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, 559 strerror(errno)); 560 exit(1); 561 } 562 563 if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { 564 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__, 565 strerror(errno)); 566 567 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; 568 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; 569 ipr->ipr_raf_onlink = 1; 570 ipr->ipr_raf_auto = 1; 571 /* omit other field initialization */ 572 } 573 else if (ipr->ipr_origin < PR_ORIG_RR) { 574 u_char ntopbuf[INET6_ADDRSTRLEN]; 575 576 syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" 577 "lower than PR_ORIG_RR(router renumbering)." 578 "This should not happen if I am router", __FUNCTION__, 579 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, 580 sizeof(ntopbuf)), ipr->ipr_origin); 581 close(s); 582 return 1; 583 } 584 585 close(s); 586 return 0; 587} 588 589void 590make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) 591{ 592 struct in6_prefixreq ipr; 593 594 memset(&ipr, 0, sizeof(ipr)); 595 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { 596 syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" 597 "exist. This should not happen! %s", __FUNCTION__, 598 ifindex, strerror(errno)); 599 exit(1); 600 } 601 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); 602 ipr.ipr_prefix.sin6_family = AF_INET6; 603 ipr.ipr_prefix.sin6_addr = *addr; 604 ipr.ipr_plen = plen; 605 606 if (init_prefix(&ipr)) 607 return; /* init failed by some error */ 608 add_prefix(rai, &ipr); 609} 610 611void 612make_packet(struct rainfo *rainfo) 613{ 614 size_t packlen, lladdroptlen = 0; 615 char *buf; 616 struct nd_router_advert *ra; 617 struct nd_opt_prefix_info *ndopt_pi; 618 struct nd_opt_mtu *ndopt_mtu; 619#ifdef MIP6 620 struct nd_opt_advint *ndopt_advint; 621 struct nd_opt_hai *ndopt_hai; 622#endif 623 struct prefix *pfx; 624 625 /* calculate total length */ 626 packlen = sizeof(struct nd_router_advert); 627 if (rainfo->advlinkopt) { 628 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { 629 syslog(LOG_INFO, 630 "<%s> link-layer address option has" 631 " null length on %s." 632 " Treat as not included.", 633 __FUNCTION__, rainfo->ifname); 634 rainfo->advlinkopt = 0; 635 } 636 packlen += lladdroptlen; 637 } 638 if (rainfo->pfxs) 639 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; 640 if (rainfo->linkmtu) 641 packlen += sizeof(struct nd_opt_mtu); 642#ifdef MIP6 643 if (mobileip6 && rainfo->maxinterval) 644 packlen += sizeof(struct nd_opt_advint); 645 if (mobileip6 && rainfo->hatime) 646 packlen += sizeof(struct nd_opt_hai); 647#endif 648 649 /* allocate memory for the packet */ 650 if ((buf = malloc(packlen)) == NULL) { 651 syslog(LOG_ERR, 652 "<%s> can't get enough memory for an RA packet", 653 __FUNCTION__); 654 exit(1); 655 } 656 rainfo->ra_data = buf; 657 /* XXX: what if packlen > 576? */ 658 rainfo->ra_datalen = packlen; 659 660 /* 661 * construct the packet 662 */ 663 ra = (struct nd_router_advert *)buf; 664 ra->nd_ra_type = ND_ROUTER_ADVERT; 665 ra->nd_ra_code = 0; 666 ra->nd_ra_cksum = 0; 667 ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); 668 ra->nd_ra_flags_reserved = 0; 669 ra->nd_ra_flags_reserved |= 670 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; 671 ra->nd_ra_flags_reserved |= 672 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; 673#ifdef MIP6 674 ra->nd_ra_flags_reserved |= 675 rainfo->haflg ? ND_RA_FLAG_HA : 0; 676#endif 677 ra->nd_ra_router_lifetime = htons(rainfo->lifetime); 678 ra->nd_ra_reachable = htonl(rainfo->reachabletime); 679 ra->nd_ra_retransmit = htonl(rainfo->retranstimer); 680 buf += sizeof(*ra); 681 682 if (rainfo->advlinkopt) { 683 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); 684 buf += lladdroptlen; 685 } 686 687 if (rainfo->linkmtu) { 688 ndopt_mtu = (struct nd_opt_mtu *)buf; 689 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 690 ndopt_mtu->nd_opt_mtu_len = 1; 691 ndopt_mtu->nd_opt_mtu_reserved = 0; 692 ndopt_mtu->nd_opt_mtu_mtu = ntohl(rainfo->linkmtu); 693 buf += sizeof(struct nd_opt_mtu); 694 } 695 696#ifdef MIP6 697 if (mobileip6 && rainfo->maxinterval) { 698 ndopt_advint = (struct nd_opt_advint *)buf; 699 ndopt_advint->nd_opt_int_type = ND_OPT_ADV_INTERVAL; 700 ndopt_advint->nd_opt_int_len = 1; 701 ndopt_advint->nd_opt_int_reserved = 0; 702 ndopt_advint->nd_opt_int_interval = ntohl(rainfo->maxinterval * 703 1000); 704 buf += sizeof(struct nd_opt_advint); 705 } 706#endif 707 708#ifdef MIP6 709 if (rainfo->hatime) { 710 ndopt_hai = (struct nd_opt_hai *)buf; 711 ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION; 712 ndopt_hai->nd_opt_hai_len = 1; 713 ndopt_hai->nd_opt_hai_reserved = 0; 714 ndopt_hai->nd_opt_hai_pref = ntohs(rainfo->hapref); 715 ndopt_hai->nd_opt_hai_lifetime = ntohs(rainfo->hatime); 716 buf += sizeof(struct nd_opt_hai); 717 } 718#endif 719 720 for (pfx = rainfo->prefix.next; 721 pfx != &rainfo->prefix; pfx = pfx->next) { 722 ndopt_pi = (struct nd_opt_prefix_info *)buf; 723 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 724 ndopt_pi->nd_opt_pi_len = 4; 725 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; 726 ndopt_pi->nd_opt_pi_flags_reserved = 0; 727 if (pfx->onlinkflg) 728 ndopt_pi->nd_opt_pi_flags_reserved |= 729 ND_OPT_PI_FLAG_ONLINK; 730 if (pfx->autoconfflg) 731 ndopt_pi->nd_opt_pi_flags_reserved |= 732 ND_OPT_PI_FLAG_AUTO; 733#ifdef MIP6 734 if (pfx->routeraddr) 735 ndopt_pi->nd_opt_pi_flags_reserved |= 736 ND_OPT_PI_FLAG_RTADDR; 737#endif 738 ndopt_pi->nd_opt_pi_valid_time = ntohl(pfx->validlifetime); 739 ndopt_pi->nd_opt_pi_preferred_time = 740 ntohl(pfx->preflifetime); 741 ndopt_pi->nd_opt_pi_reserved2 = 0; 742 ndopt_pi->nd_opt_pi_prefix = pfx->prefix; 743 744 buf += sizeof(struct nd_opt_prefix_info); 745 } 746 747 return; 748} 749