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