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