1 /* $NetBSD: rtadvd.c,v 1.9 2000/05/23 11:37:59 itojun Exp $ */ 2 /* $KAME: rtadvd.c,v 1.26 2000/05/23 11:31:26 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 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/socket.h> 35 #include <sys/uio.h> 36 #include <sys/time.h> 37 38 #include <net/if.h> 39 #include <net/route.h> 40 #include <net/if_dl.h> 41 #include <netinet/in.h> 42 #include <netinet/ip6.h> 43 #include <netinet6/ip6_var.h> 44 #include <netinet/icmp6.h> 45 46 #include <arpa/inet.h> 47 48 #include <time.h> 49 #include <unistd.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <err.h> 53 #include <errno.h> 54 #include <string.h> 55 #include <stdlib.h> 56 #include <syslog.h> 57 #include "rtadvd.h" 58 #include "rrenum.h" 59 #include "advcap.h" 60 #include "timer.h" 61 #include "if.h" 62 #include "config.h" 63 #include "dump.h" 64 65 struct msghdr rcvmhdr; 66 static u_char *rcvcmsgbuf; 67 static size_t rcvcmsgbuflen; 68 static u_char *sndcmsgbuf = NULL; 69 static size_t sndcmsgbuflen; 70 static int do_dump; 71 struct msghdr sndmhdr; 72 struct iovec rcviov[2]; 73 struct iovec sndiov[2]; 74 struct sockaddr_in6 from; 75 struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6}; 76 static char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX: should be configurable */ 77 static char *pidfilename = "/var/run/rtadvd.pid"; /* should be configurable */ 78 int sock, rtsock; 79 #ifdef MIP6 80 int mobileip6 = 0; 81 #endif 82 int accept_rr = 0; 83 int dflag = 0, sflag = 0; 84 85 u_char *conffile = NULL; 86 87 struct rainfo *ralist = NULL; 88 struct nd_optlist { 89 struct nd_optlist *next; 90 struct nd_opt_hdr *opt; 91 }; 92 union nd_opts { 93 struct nd_opt_hdr *nd_opt_array[7]; 94 struct { 95 struct nd_opt_hdr *zero; 96 struct nd_opt_hdr *src_lladdr; 97 struct nd_opt_hdr *tgt_lladdr; 98 struct nd_opt_prefix_info *pi; 99 struct nd_opt_rd_hdr *rh; 100 struct nd_opt_mtu *mtu; 101 struct nd_optlist *list; 102 } nd_opt_each; 103 }; 104 #define nd_opts_src_lladdr nd_opt_each.src_lladdr 105 #define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr 106 #define nd_opts_pi nd_opt_each.pi 107 #define nd_opts_rh nd_opt_each.rh 108 #define nd_opts_mtu nd_opt_each.mtu 109 #define nd_opts_list nd_opt_each.list 110 111 #define NDOPT_FLAG_SRCLINKADDR 0x1 112 #define NDOPT_FLAG_TGTLINKADDR 0x2 113 #define NDOPT_FLAG_PREFIXINFO 0x4 114 #define NDOPT_FLAG_RDHDR 0x8 115 #define NDOPT_FLAG_MTU 0x10 116 117 u_int32_t ndopt_flags[] = { 118 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR, 119 NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU 120 }; 121 122 int main __P((int, char *[])); 123 static void die __P((int)); 124 static void sock_open __P((void)); 125 static void rtsock_open __P((void)); 126 static void rtadvd_input __P((void)); 127 static void rs_input __P((int, struct nd_router_solicit *, 128 struct in6_pktinfo *, struct sockaddr_in6 *)); 129 static void ra_input __P((int, struct nd_router_advert *, 130 struct in6_pktinfo *, struct sockaddr_in6 *)); 131 static int prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *, 132 struct sockaddr_in6 *)); 133 static int nd6_options __P((struct nd_opt_hdr *, int, 134 union nd_opts *, u_int32_t)); 135 static void free_ndopts __P((union nd_opts *)); 136 static struct rainfo *if_indextorainfo __P((int)); 137 static void ra_output __P((struct rainfo *)); 138 static void rtmsg_input __P((void)); 139 static void rtadvd_set_dump_file __P((void)); 140 141 struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int)); 142 143 int 144 main(argc, argv) 145 int argc; 146 char *argv[]; 147 { 148 fd_set fdset; 149 int maxfd = 0; 150 struct timeval *timeout; 151 int i, ch; 152 int fflag = 0; 153 FILE *pidfp; 154 pid_t pid; 155 156 openlog("rtadvd", LOG_NDELAY|LOG_PID, LOG_DAEMON); 157 158 /* get command line options and arguments */ 159 #ifdef MIP6 160 #define OPTIONS "c:dDfmRs" 161 #else 162 #define OPTIONS "c:dDfRs" 163 #endif 164 while ((ch = getopt(argc, argv, OPTIONS)) != -1) { 165 #undef OPTIONS 166 switch(ch) { 167 case 'c': 168 conffile = optarg; 169 break; 170 case 'd': 171 dflag = 1; 172 break; 173 case 'D': 174 dflag = 2; 175 break; 176 case 'f': 177 fflag = 1; 178 break; 179 #ifdef MIP6 180 case 'm': 181 mobileip6 = 1; 182 break; 183 #endif 184 case 'R': 185 accept_rr = 1; 186 break; 187 case 's': 188 sflag = 1; 189 break; 190 } 191 } 192 argc -= optind; 193 argv += optind; 194 if (argc == 0) { 195 fprintf(stderr, 196 #ifdef MIP6 197 "usage: rtadvd [-dDfmRs] [-c conffile] " 198 #else 199 "usage: rtadvd [-dDfRs] [-c conffile] " 200 #endif 201 "interfaces...\n"); 202 exit(1); 203 } 204 205 /* set log level */ 206 if (dflag == 0) 207 (void)setlogmask(LOG_UPTO(LOG_ERR)); 208 if (dflag == 1) 209 (void)setlogmask(LOG_UPTO(LOG_INFO)); 210 211 /* timer initialization */ 212 rtadvd_timer_init(); 213 214 /* random value initialization */ 215 srandom((u_long)time(NULL)); 216 217 /* get iflist block from kernel */ 218 init_iflist(); 219 220 while (argc--) 221 getconfig(*argv++); 222 223 if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) { 224 fprintf(stderr, "fatal: inet_pton failed\n"); 225 exit(1); 226 } 227 sock_open(); 228 229 if (!fflag) 230 daemon(1, 0); 231 232 /* record the current PID */ 233 pid = getpid(); 234 if ((pidfp = fopen(pidfilename, "w")) == NULL) 235 syslog(LOG_ERR, 236 "<%s> failed to open a log file(%s), run anyway.", 237 __FUNCTION__, pidfilename); 238 else { 239 fprintf(pidfp, "%d\n", pid); 240 fclose(pidfp); 241 } 242 243 FD_ZERO(&fdset); 244 FD_SET(sock, &fdset); 245 maxfd = sock; 246 if (sflag == 0) { 247 rtsock_open(); 248 FD_SET(rtsock, &fdset); 249 if (rtsock > sock) 250 maxfd = rtsock; 251 } 252 253 signal(SIGTERM, (void *)die); 254 signal(SIGUSR1, (void *)rtadvd_set_dump_file); 255 256 while (1) { 257 struct fd_set select_fd = fdset; /* reinitialize */ 258 259 if (do_dump) { /* SIGUSR1 */ 260 do_dump = 0; 261 rtadvd_dump_file(dumpfilename); 262 } 263 264 /* timer expiration check and reset the timer */ 265 timeout = rtadvd_check_timer(); 266 267 syslog(LOG_DEBUG, 268 "<%s> set timer to %ld:%ld. waiting for inputs " 269 "or timeout", 270 __FUNCTION__, 271 (long int)timeout->tv_sec, (long int)timeout->tv_usec); 272 273 if ((i = select(maxfd + 1, &select_fd, 274 NULL, NULL, timeout)) < 0) { 275 /* EINTR would occur upon SIGUSR1 for status dump */ 276 if (errno != EINTR) 277 syslog(LOG_ERR, "<%s> select: %s", 278 __FUNCTION__, strerror(errno)); 279 continue; 280 } 281 if (i == 0) /* timeout */ 282 continue; 283 if (sflag == 0 && FD_ISSET(rtsock, &select_fd)) 284 rtmsg_input(); 285 if (FD_ISSET(sock, &select_fd)) 286 rtadvd_input(); 287 } 288 exit(0); /* NOTREACHED */ 289 } 290 291 static void 292 rtadvd_set_dump_file() 293 { 294 do_dump = 1; 295 } 296 297 static void 298 die(sig) 299 int sig; 300 { 301 struct rainfo *ra; 302 int i; 303 const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS; 304 305 if (dflag > 1) { 306 syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n", 307 __FUNCTION__); 308 } 309 310 for (ra = ralist; ra; ra = ra->next) { 311 ra->lifetime = 0; 312 make_packet(ra); 313 } 314 for (i = 0; i < retrans; i++) { 315 for (ra = ralist; ra; ra = ra->next) 316 ra_output(ra); 317 sleep(MIN_DELAY_BETWEEN_RAS); 318 } 319 exit(0); 320 /*NOTREACHED*/ 321 } 322 323 static void 324 rtmsg_input() 325 { 326 int n, type, ifindex = 0, plen; 327 size_t len; 328 char msg[2048], *next, *lim; 329 u_char ifname[16]; 330 struct prefix *prefix; 331 struct rainfo *rai; 332 struct in6_addr *addr; 333 char addrbuf[INET6_ADDRSTRLEN]; 334 335 n = read(rtsock, msg, 2048); 336 if (dflag > 1) { 337 syslog(LOG_DEBUG, 338 "<%s> received a routing message " 339 "(type = %d, len = %d)", 340 __FUNCTION__, 341 rtmsg_type(msg), n); 342 } 343 if (n > rtmsg_len(msg)) { 344 /* 345 * This usually won't happen for messages received on 346 * an routing socket. 347 */ 348 if (dflag > 1) 349 syslog(LOG_DEBUG, 350 "<%s> received data length is larger than" 351 "1st routing message len. multiple messages?" 352 " read %d bytes, but 1st msg len = %d", 353 __FUNCTION__, n, rtmsg_len(msg)); 354 #if 0 355 /* adjust length */ 356 n = rtmsg_len(msg); 357 #endif 358 } 359 360 lim = msg + n; 361 for (next = msg; next < lim; next += len) { 362 next = get_next_msg(next, lim, 0, &len, 363 RTADV_TYPE2BITMASK(RTM_ADD) | 364 RTADV_TYPE2BITMASK(RTM_DELETE) | 365 RTADV_TYPE2BITMASK(RTM_NEWADDR) | 366 RTADV_TYPE2BITMASK(RTM_DELADDR) | 367 RTADV_TYPE2BITMASK(RTM_IFINFO)); 368 if (len == 0) 369 break; 370 type = rtmsg_type(next); 371 switch (type) { 372 case RTM_ADD: 373 case RTM_DELETE: 374 ifindex = get_rtm_ifindex(next); 375 break; 376 case RTM_NEWADDR: 377 case RTM_DELADDR: 378 ifindex = get_ifam_ifindex(next); 379 break; 380 case RTM_IFINFO: 381 ifindex = get_ifm_ifindex(next); 382 break; 383 default: 384 /* should not reach here */ 385 if (dflag > 1) { 386 syslog(LOG_DEBUG, 387 "<%s:%d> unknown rtmsg %d on %s", 388 __FUNCTION__, __LINE__, type, 389 if_indextoname(ifindex, ifname)); 390 } 391 return; 392 } 393 394 if ((rai = if_indextorainfo(ifindex)) == NULL) { 395 if (dflag > 1) { 396 syslog(LOG_DEBUG, 397 "<%s> route changed on " 398 "non advertising interface(%s)", 399 __FUNCTION__, 400 if_indextoname(ifindex, ifname)); 401 } 402 return; 403 } 404 405 switch(type) { 406 case RTM_ADD: 407 /* init iffalgs because it may have changed */ 408 iflist[ifindex]->ifm_flags = 409 if_getflags(ifindex, 410 iflist[ifindex]->ifm_flags); 411 412 addr = get_addr(msg); 413 plen = get_prefixlen(msg); 414 /* sanity check for plen */ 415 if (plen < 4 /* as RFC2373, prefixlen is at least 4 */ 416 || plen > 127) { 417 syslog(LOG_INFO, "<%s> new interface route's" 418 "plen %d is invalid for a prefix", 419 __FUNCTION__, plen); 420 return; 421 } 422 prefix = find_prefix(rai, addr, plen); 423 if (prefix) { 424 if (dflag > 1) { 425 syslog(LOG_DEBUG, 426 "<%s> new prefix(%s/%d) " 427 "added on %s, " 428 "but it was already in list", 429 __FUNCTION__, 430 inet_ntop(AF_INET6, 431 addr, (char *)addrbuf, 432 INET6_ADDRSTRLEN), 433 plen, 434 rai->ifname); 435 } 436 return; 437 } 438 make_prefix(rai, ifindex, addr, plen); 439 break; 440 case RTM_DELETE: 441 /* init ifflags because it may have changed */ 442 iflist[ifindex]->ifm_flags = 443 if_getflags(ifindex, 444 iflist[ifindex]->ifm_flags); 445 446 addr = get_addr(msg); 447 plen = get_prefixlen(msg); 448 /* sanity check for plen */ 449 if (plen < 4 /* as RFC2373, prefixlen is at least 4 */ 450 || plen > 127) { 451 syslog(LOG_INFO, "<%s> deleted interface" 452 "route's" 453 "plen %d is invalid for a prefix", 454 __FUNCTION__, plen); 455 return; 456 } 457 prefix = find_prefix(rai, addr, plen); 458 if (prefix == NULL) { 459 if (dflag > 1) { 460 syslog(LOG_DEBUG, 461 "<%s> prefix(%s/%d) was " 462 "deleted on %s, " 463 "but it was not in list", 464 __FUNCTION__, 465 inet_ntop(AF_INET6, 466 addr, (char *)addrbuf, 467 INET6_ADDRSTRLEN), 468 plen, 469 rai->ifname); 470 } 471 return; 472 } 473 delete_prefix(rai, prefix); 474 break; 475 case RTM_NEWADDR: 476 case RTM_DELADDR: 477 /* init ifflags because it may have changed */ 478 iflist[ifindex]->ifm_flags = 479 if_getflags(ifindex, 480 iflist[ifindex]->ifm_flags); 481 break; 482 case RTM_IFINFO: 483 iflist[ifindex]->ifm_flags = get_ifm_flags(next); 484 break; 485 default: 486 /* should not reach here */ 487 if (dflag > 1) { 488 syslog(LOG_DEBUG, 489 "<%s:%d> unknown rtmsg %d on %s", 490 __FUNCTION__, __LINE__, type, 491 if_indextoname(ifindex, ifname)); 492 } 493 return; 494 } 495 } 496 497 return; 498 } 499 500 void 501 rtadvd_input() 502 { 503 int i; 504 int *hlimp = NULL; 505 #ifdef OLDRAWSOCKET 506 struct ip6_hdr *ip; 507 #endif 508 struct icmp6_hdr *icp; 509 int ifindex = 0; 510 struct cmsghdr *cm; 511 struct in6_pktinfo *pi = NULL; 512 u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 513 struct in6_addr dst = in6addr_any; 514 515 /* 516 * Get message. We reset msg_controllen since the field could 517 * be modified if we had received a message before setting 518 * receive options. 519 */ 520 rcvmhdr.msg_controllen = rcvcmsgbuflen; 521 if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0) 522 return; 523 524 /* extract optional information via Advanced API */ 525 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); 526 cm; 527 cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { 528 if (cm->cmsg_level == IPPROTO_IPV6 && 529 cm->cmsg_type == IPV6_PKTINFO && 530 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 531 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 532 ifindex = pi->ipi6_ifindex; 533 dst = pi->ipi6_addr; 534 } 535 if (cm->cmsg_level == IPPROTO_IPV6 && 536 cm->cmsg_type == IPV6_HOPLIMIT && 537 cm->cmsg_len == CMSG_LEN(sizeof(int))) 538 hlimp = (int *)CMSG_DATA(cm); 539 } 540 if (ifindex == 0) { 541 syslog(LOG_ERR, 542 "<%s> failed to get receiving interface", 543 __FUNCTION__); 544 return; 545 } 546 if (hlimp == NULL) { 547 syslog(LOG_ERR, 548 "<%s> failed to get receiving hop limit", 549 __FUNCTION__); 550 return; 551 } 552 553 #ifdef OLDRAWSOCKET 554 if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) { 555 syslog(LOG_ERR, 556 "<%s> packet size(%d) is too short", 557 __FUNCTION__, i); 558 return; 559 } 560 561 ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base; 562 icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */ 563 #else 564 if (i < sizeof(struct icmp6_hdr)) { 565 syslog(LOG_ERR, 566 "<%s> packet size(%d) is too short", 567 __FUNCTION__, i); 568 return; 569 } 570 571 icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; 572 #endif 573 574 switch(icp->icmp6_type) { 575 case ND_ROUTER_SOLICIT: 576 /* 577 * Message verification - RFC-2461 6.1.1 578 * XXX: these checks must be done in the kernel as well, 579 * but we can't completely rely on them. 580 */ 581 if (*hlimp != 255) { 582 syslog(LOG_NOTICE, 583 "<%s> RS with invalid hop limit(%d) " 584 "received from %s on %s", 585 __FUNCTION__, *hlimp, 586 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 587 INET6_ADDRSTRLEN), 588 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 589 return; 590 } 591 if (icp->icmp6_code) { 592 syslog(LOG_NOTICE, 593 "<%s> RS with invalid ICMP6 code(%d) " 594 "received from %s on %s", 595 __FUNCTION__, icp->icmp6_code, 596 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 597 INET6_ADDRSTRLEN), 598 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 599 return; 600 } 601 if (i < sizeof(struct nd_router_solicit)) { 602 syslog(LOG_NOTICE, 603 "<%s> RS from %s on %s does not have enough " 604 "length (len = %d)", 605 __FUNCTION__, 606 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 607 INET6_ADDRSTRLEN), 608 if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); 609 return; 610 } 611 rs_input(i, (struct nd_router_solicit *)icp, pi, &from); 612 break; 613 case ND_ROUTER_ADVERT: 614 /* 615 * Message verification - RFC-2461 6.1.2 616 * XXX: there's a same dilemma as above... 617 */ 618 if (*hlimp != 255) { 619 syslog(LOG_NOTICE, 620 "<%s> RA with invalid hop limit(%d) " 621 "received from %s on %s", 622 __FUNCTION__, *hlimp, 623 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 624 INET6_ADDRSTRLEN), 625 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 626 return; 627 } 628 if (icp->icmp6_code) { 629 syslog(LOG_NOTICE, 630 "<%s> RA with invalid ICMP6 code(%d) " 631 "received from %s on %s", 632 __FUNCTION__, icp->icmp6_code, 633 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 634 INET6_ADDRSTRLEN), 635 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 636 return; 637 } 638 if (i < sizeof(struct nd_router_advert)) { 639 syslog(LOG_NOTICE, 640 "<%s> RA from %s on %s does not have enough " 641 "length (len = %d)", 642 __FUNCTION__, 643 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 644 INET6_ADDRSTRLEN), 645 if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); 646 return; 647 } 648 ra_input(i, (struct nd_router_advert *)icp, pi, &from); 649 break; 650 case ICMP6_ROUTER_RENUMBERING: 651 if (accept_rr == 0) { 652 syslog(LOG_ERR, 653 "<%s> received a router renumbering " 654 "message, but not allowed to be accepted", 655 __FUNCTION__); 656 break; 657 } 658 rr_input(i, (struct icmp6_router_renum *)icp, pi, &from, 659 &dst); 660 break; 661 default: 662 /* 663 * Note that this case is POSSIBLE, especially just 664 * after invocation of the daemon. This is because we 665 * could receive message after opening the socket and 666 * before setting ICMP6 type filter(see sock_open()). 667 */ 668 syslog(LOG_ERR, 669 "<%s> invalid icmp type(%d)", 670 __FUNCTION__, icp->icmp6_type); 671 return; 672 } 673 674 return; 675 } 676 677 static void 678 rs_input(int len, struct nd_router_solicit *rs, 679 struct in6_pktinfo *pi, struct sockaddr_in6 *from) 680 { 681 u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 682 union nd_opts ndopts; 683 struct rainfo *ra; 684 685 syslog(LOG_DEBUG, 686 "<%s> RS received from %s on %s", 687 __FUNCTION__, 688 inet_ntop(AF_INET6, &from->sin6_addr, 689 ntopbuf, INET6_ADDRSTRLEN), 690 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 691 692 /* ND option check */ 693 memset(&ndopts, 0, sizeof(ndopts)); 694 if (nd6_options((struct nd_opt_hdr *)(rs + 1), 695 len - sizeof(struct nd_router_solicit), 696 &ndopts, NDOPT_FLAG_SRCLINKADDR)) { 697 syslog(LOG_DEBUG, 698 "<%s> ND option check failed for an RS from %s on %s", 699 __FUNCTION__, 700 inet_ntop(AF_INET6, &from->sin6_addr, 701 ntopbuf, INET6_ADDRSTRLEN), 702 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 703 return; 704 } 705 706 /* 707 * If the IP source address is the unspecified address, there 708 * must be no source link-layer address option in the message. 709 * (RFC-2461 6.1.1) 710 */ 711 if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) && 712 ndopts.nd_opts_src_lladdr) { 713 syslog(LOG_ERR, 714 "<%s> RS from unspecified src on %s has a link-layer" 715 " address option", 716 __FUNCTION__, 717 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 718 goto done; 719 } 720 721 ra = ralist; 722 while (ra != NULL) { 723 if (pi->ipi6_ifindex == ra->ifindex) 724 break; 725 ra = ra->next; 726 } 727 if (ra == NULL) { 728 syslog(LOG_INFO, 729 "<%s> RS received on non advertising interface(%s)", 730 __FUNCTION__, 731 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 732 goto done; 733 } 734 735 ra->rsinput++; /* increment statistics */ 736 737 /* 738 * Decide whether to send RA according to the rate-limit 739 * consideration. 740 */ 741 { 742 long delay; /* must not be greater than 1000000 */ 743 struct timeval interval, now, min_delay, tm_tmp, *rest; 744 745 /* 746 * If there is already a waiting RS packet, don't 747 * update the timer. 748 */ 749 if (ra->waiting++) 750 goto done; 751 752 /* 753 * Compute a random delay. If the computed value 754 * corresponds to a time later than the time the next 755 * multicast RA is scheduled to be sent, ignore the random 756 * delay and send the advertisement at the 757 * already-scheduled time. RFC-2461 6.2.6 758 */ 759 delay = random() % MAX_RA_DELAY_TIME; 760 interval.tv_sec = 0; 761 interval.tv_usec = delay; 762 rest = rtadvd_timer_rest(ra->timer); 763 if (TIMEVAL_LT(*rest, interval)) { 764 syslog(LOG_DEBUG, 765 "<%s> random delay is larger than " 766 "the rest of normal timer", 767 __FUNCTION__); 768 interval = *rest; 769 } 770 771 /* 772 * If we sent a multicast Router Advertisement within 773 * the last MIN_DELAY_BETWEEN_RAS seconds, schedule 774 * the advertisement to be sent at a time corresponding to 775 * MIN_DELAY_BETWEEN_RAS plus the random value after the 776 * previous advertisement was sent. 777 */ 778 gettimeofday(&now, NULL); 779 TIMEVAL_SUB(&now, &ra->lastsent, &tm_tmp); 780 min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS; 781 min_delay.tv_usec = 0; 782 if (TIMEVAL_LT(tm_tmp, min_delay)) { 783 TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay); 784 TIMEVAL_ADD(&min_delay, &interval, &interval); 785 } 786 rtadvd_set_timer(&interval, ra->timer); 787 goto done; 788 } 789 790 done: 791 free_ndopts(&ndopts); 792 return; 793 } 794 795 static void 796 ra_input(int len, struct nd_router_advert *ra, 797 struct in6_pktinfo *pi, struct sockaddr_in6 *from) 798 { 799 struct rainfo *rai; 800 u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 801 union nd_opts ndopts; 802 char *on_off[] = {"OFF", "ON"}; 803 u_int32_t reachabletime, retranstimer, mtu; 804 int inconsistent = 0; 805 806 syslog(LOG_DEBUG, 807 "<%s> RA received from %s on %s", 808 __FUNCTION__, 809 inet_ntop(AF_INET6, &from->sin6_addr, 810 ntopbuf, INET6_ADDRSTRLEN), 811 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 812 813 /* ND option check */ 814 memset(&ndopts, 0, sizeof(ndopts)); 815 if (nd6_options((struct nd_opt_hdr *)(ra + 1), 816 len - sizeof(struct nd_router_advert), 817 &ndopts, 818 NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { 819 syslog(LOG_ERR, 820 "<%s> ND option check failed for an RA from %s on %s", 821 __FUNCTION__, 822 inet_ntop(AF_INET6, &from->sin6_addr, 823 ntopbuf, INET6_ADDRSTRLEN), 824 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 825 return; 826 } 827 828 /* 829 * RA consistency check according to RFC-2461 6.2.7 830 */ 831 if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) { 832 syslog(LOG_INFO, 833 "<%s> received RA from %s on non-advertising" 834 " interface(%s)", 835 __FUNCTION__, 836 inet_ntop(AF_INET6, &from->sin6_addr, 837 ntopbuf, INET6_ADDRSTRLEN), 838 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 839 goto done; 840 } 841 rai->rainput++; /* increment statistics */ 842 843 /* Cur Hop Limit value */ 844 if (ra->nd_ra_curhoplimit && rai->hoplimit && 845 ra->nd_ra_curhoplimit != rai->hoplimit) { 846 syslog(LOG_WARNING, 847 "<%s> CurHopLimit inconsistent on %s:" 848 " %d from %s, %d from us", 849 __FUNCTION__, 850 rai->ifname, 851 ra->nd_ra_curhoplimit, 852 inet_ntop(AF_INET6, &from->sin6_addr, 853 ntopbuf, INET6_ADDRSTRLEN), 854 rai->hoplimit); 855 inconsistent++; 856 } 857 /* M flag */ 858 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 859 rai->managedflg) { 860 syslog(LOG_WARNING, 861 "<%s> M flag inconsistent on %s:" 862 " %s from %s, %s from us", 863 __FUNCTION__, 864 rai->ifname, 865 on_off[!rai->managedflg], 866 inet_ntop(AF_INET6, &from->sin6_addr, 867 ntopbuf, INET6_ADDRSTRLEN), 868 on_off[rai->managedflg]); 869 inconsistent++; 870 } 871 /* O flag */ 872 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 873 rai->otherflg) { 874 syslog(LOG_WARNING, 875 "<%s> O flag inconsistent on %s:" 876 " %s from %s, %s from us", 877 __FUNCTION__, 878 rai->ifname, 879 on_off[!rai->otherflg], 880 inet_ntop(AF_INET6, &from->sin6_addr, 881 ntopbuf, INET6_ADDRSTRLEN), 882 on_off[rai->otherflg]); 883 inconsistent++; 884 } 885 /* Reachable Time */ 886 reachabletime = ntohl(ra->nd_ra_reachable); 887 if (reachabletime && rai->reachabletime && 888 reachabletime != rai->reachabletime) { 889 syslog(LOG_WARNING, 890 "<%s> ReachableTime inconsistent on %s:" 891 " %d from %s, %d from us", 892 __FUNCTION__, 893 rai->ifname, 894 reachabletime, 895 inet_ntop(AF_INET6, &from->sin6_addr, 896 ntopbuf, INET6_ADDRSTRLEN), 897 rai->reachabletime); 898 inconsistent++; 899 } 900 /* Retrans Timer */ 901 retranstimer = ntohl(ra->nd_ra_retransmit); 902 if (retranstimer && rai->retranstimer && 903 retranstimer != rai->retranstimer) { 904 syslog(LOG_WARNING, 905 "<%s> RetranceTimer inconsistent on %s:" 906 " %d from %s, %d from us", 907 __FUNCTION__, 908 rai->ifname, 909 retranstimer, 910 inet_ntop(AF_INET6, &from->sin6_addr, 911 ntopbuf, INET6_ADDRSTRLEN), 912 rai->retranstimer); 913 inconsistent++; 914 } 915 /* Values in the MTU options */ 916 if (ndopts.nd_opts_mtu) { 917 mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 918 if (mtu && rai->linkmtu && mtu != rai->linkmtu) { 919 syslog(LOG_WARNING, 920 "<%s> MTU option value inconsistent on %s:" 921 " %d from %s, %d from us", 922 __FUNCTION__, 923 rai->ifname, mtu, 924 inet_ntop(AF_INET6, &from->sin6_addr, 925 ntopbuf, INET6_ADDRSTRLEN), 926 rai->linkmtu); 927 inconsistent++; 928 } 929 } 930 /* Preferred and Valid Lifetimes for prefixes */ 931 { 932 struct nd_optlist *optp = ndopts.nd_opts_list; 933 934 if (ndopts.nd_opts_pi) { 935 if (prefix_check(ndopts.nd_opts_pi, rai, from)) 936 inconsistent++; 937 } 938 while (optp) { 939 if (prefix_check((struct nd_opt_prefix_info *)optp->opt, 940 rai, from)) 941 inconsistent++; 942 optp = optp->next; 943 } 944 } 945 946 if (inconsistent) { 947 printf("RA input %d inconsistents\n", inconsistent); 948 rai->rainconsistent++; 949 } 950 951 done: 952 free_ndopts(&ndopts); 953 return; 954 } 955 956 /* return a non-zero value if the received prefix is inconsitent with ours */ 957 static int 958 prefix_check(struct nd_opt_prefix_info *pinfo, 959 struct rainfo *rai, struct sockaddr_in6 *from) 960 { 961 u_int32_t preferred_time, valid_time; 962 struct prefix *pp; 963 int inconsistent = 0; 964 u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; 965 966 #if 0 /* impossible */ 967 if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) 968 return(0); 969 #endif 970 971 /* 972 * log if the adveritsed prefix has link-local scope(sanity check?) 973 */ 974 if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) { 975 syslog(LOG_INFO, 976 "<%s> link-local prefix %s/%d is advertised " 977 "from %s on %s", 978 __FUNCTION__, 979 inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, 980 prefixbuf, INET6_ADDRSTRLEN), 981 pinfo->nd_opt_pi_prefix_len, 982 inet_ntop(AF_INET6, &from->sin6_addr, 983 ntopbuf, INET6_ADDRSTRLEN), 984 rai->ifname); 985 } 986 987 if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix, 988 pinfo->nd_opt_pi_prefix_len)) == NULL) { 989 syslog(LOG_INFO, 990 "<%s> prefix %s/%d from %s on %s is not in our list", 991 __FUNCTION__, 992 inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, 993 prefixbuf, INET6_ADDRSTRLEN), 994 pinfo->nd_opt_pi_prefix_len, 995 inet_ntop(AF_INET6, &from->sin6_addr, 996 ntopbuf, INET6_ADDRSTRLEN), 997 rai->ifname); 998 return(0); 999 } 1000 1001 preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); 1002 if (preferred_time != pp->preflifetime) { 1003 syslog(LOG_WARNING, 1004 "<%s> prefeerred lifetime for %s/%d" 1005 " inconsistent on %s:" 1006 " %d from %s, %d from us", 1007 __FUNCTION__, 1008 inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, 1009 prefixbuf, INET6_ADDRSTRLEN), 1010 pinfo->nd_opt_pi_prefix_len, 1011 rai->ifname, preferred_time, 1012 inet_ntop(AF_INET6, &from->sin6_addr, 1013 ntopbuf, INET6_ADDRSTRLEN), 1014 pp->preflifetime); 1015 inconsistent++; 1016 } 1017 1018 valid_time = ntohl(pinfo->nd_opt_pi_valid_time); 1019 if (valid_time != pp->validlifetime) { 1020 syslog(LOG_WARNING, 1021 "<%s> valid lifetime for %s/%d" 1022 " inconsistent on %s:" 1023 " %d from %s, %d from us", 1024 __FUNCTION__, 1025 inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, 1026 prefixbuf, INET6_ADDRSTRLEN), 1027 pinfo->nd_opt_pi_prefix_len, 1028 rai->ifname, valid_time, 1029 inet_ntop(AF_INET6, &from->sin6_addr, 1030 ntopbuf, INET6_ADDRSTRLEN), 1031 pp->validlifetime); 1032 inconsistent++; 1033 } 1034 1035 return(inconsistent); 1036 } 1037 1038 struct prefix * 1039 find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen) 1040 { 1041 struct prefix *pp; 1042 int bytelen, bitlen; 1043 1044 for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) { 1045 if (plen != pp->prefixlen) 1046 continue; 1047 bytelen = plen / 8; 1048 bitlen = plen % 8; 1049 if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen)) 1050 continue; 1051 if (prefix->s6_addr[bytelen] >> (8 - bitlen) == 1052 pp->prefix.s6_addr[bytelen] >> (8 - bitlen)) 1053 return(pp); 1054 } 1055 1056 return(NULL); 1057 } 1058 1059 static int 1060 nd6_options(struct nd_opt_hdr *hdr, int limit, 1061 union nd_opts *ndopts, u_int32_t optflags) 1062 { 1063 int optlen = 0; 1064 1065 for (; limit > 0; limit -= optlen) { 1066 hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen); 1067 optlen = hdr->nd_opt_len << 3; 1068 if (hdr->nd_opt_len == 0) { 1069 syslog(LOG_ERR, 1070 "<%s> bad ND option length(0) (type = %d)", 1071 __FUNCTION__, hdr->nd_opt_type); 1072 goto bad; 1073 } 1074 1075 if (hdr->nd_opt_type > ND_OPT_MTU) { 1076 syslog(LOG_INFO, 1077 "<%s> unknown ND option(type %d)", 1078 __FUNCTION__, 1079 hdr->nd_opt_type); 1080 continue; 1081 } 1082 1083 if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) { 1084 syslog(LOG_INFO, 1085 "<%s> unexpected ND option(type %d)", 1086 __FUNCTION__, 1087 hdr->nd_opt_type); 1088 continue; 1089 } 1090 1091 switch(hdr->nd_opt_type) { 1092 case ND_OPT_SOURCE_LINKADDR: 1093 case ND_OPT_TARGET_LINKADDR: 1094 case ND_OPT_REDIRECTED_HEADER: 1095 case ND_OPT_MTU: 1096 if (ndopts->nd_opt_array[hdr->nd_opt_type]) { 1097 syslog(LOG_INFO, 1098 "<%s> duplicated ND option" 1099 " (type = %d)", 1100 __FUNCTION__, 1101 hdr->nd_opt_type); 1102 } 1103 ndopts->nd_opt_array[hdr->nd_opt_type] = hdr; 1104 break; 1105 case ND_OPT_PREFIX_INFORMATION: 1106 { 1107 struct nd_optlist *pfxlist; 1108 1109 if (ndopts->nd_opts_pi == 0) { 1110 ndopts->nd_opts_pi = 1111 (struct nd_opt_prefix_info *)hdr; 1112 continue; 1113 } 1114 if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) { 1115 syslog(LOG_ERR, 1116 "<%s> can't allocate memory", 1117 __FUNCTION__); 1118 goto bad; 1119 } 1120 pfxlist->next = ndopts->nd_opts_list; 1121 pfxlist->opt = hdr; 1122 ndopts->nd_opts_list = pfxlist; 1123 1124 break; 1125 } 1126 default: /* impossible */ 1127 break; 1128 } 1129 } 1130 1131 return(0); 1132 1133 bad: 1134 free_ndopts(ndopts); 1135 1136 return(-1); 1137 } 1138 1139 static void 1140 free_ndopts(union nd_opts *ndopts) 1141 { 1142 struct nd_optlist *opt = ndopts->nd_opts_list, *next; 1143 1144 while(opt) { 1145 next = opt->next; 1146 free(opt); 1147 opt = next; 1148 } 1149 } 1150 1151 void 1152 sock_open() 1153 { 1154 struct icmp6_filter filt; 1155 struct ipv6_mreq mreq; 1156 struct rainfo *ra = ralist; 1157 int on; 1158 /* XXX: should be max MTU attached to the node */ 1159 static u_char answer[1500]; 1160 1161 rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 1162 CMSG_SPACE(sizeof(int)); 1163 rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen); 1164 if (rcvcmsgbuf == NULL) { 1165 syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__); 1166 exit(1); 1167 } 1168 1169 sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 1170 CMSG_SPACE(sizeof(int)); 1171 sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen); 1172 if (sndcmsgbuf == NULL) { 1173 syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__); 1174 exit(1); 1175 } 1176 1177 if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 1178 syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, 1179 strerror(errno)); 1180 exit(1); 1181 } 1182 1183 /* specify to tell receiving interface */ 1184 on = 1; 1185 #ifdef IPV6_RECVPKTINFO 1186 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 1187 sizeof(on)) < 0) { 1188 syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", 1189 __FUNCTION__, strerror(errno)); 1190 exit(1); 1191 } 1192 #else /* old adv. API */ 1193 if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 1194 sizeof(on)) < 0) { 1195 syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", 1196 __FUNCTION__, strerror(errno)); 1197 exit(1); 1198 } 1199 #endif 1200 1201 on = 1; 1202 /* specify to tell value of hoplimit field of received IP6 hdr */ 1203 #ifdef IPV6_RECVHOPLIMIT 1204 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 1205 sizeof(on)) < 0) { 1206 syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", 1207 __FUNCTION__, strerror(errno)); 1208 exit(1); 1209 } 1210 #else /* old adv. API */ 1211 if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 1212 sizeof(on)) < 0) { 1213 syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s", 1214 __FUNCTION__, strerror(errno)); 1215 exit(1); 1216 } 1217 #endif 1218 1219 ICMP6_FILTER_SETBLOCKALL(&filt); 1220 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); 1221 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); 1222 if (accept_rr) 1223 ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); 1224 if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 1225 sizeof(filt)) < 0) { 1226 syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", 1227 __FUNCTION__, strerror(errno)); 1228 exit(1); 1229 } 1230 1231 /* 1232 * join all routers multicast address on each advertising interface. 1233 */ 1234 if (inet_pton(AF_INET6, ALLROUTERS, &mreq.ipv6mr_multiaddr.s6_addr) 1235 != 1) { 1236 syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", 1237 __FUNCTION__); 1238 exit(1); 1239 } 1240 while(ra) { 1241 mreq.ipv6mr_interface = ra->ifindex; 1242 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 1243 &mreq, 1244 sizeof(mreq)) < 0) { 1245 syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", 1246 __FUNCTION__, ra->ifname, strerror(errno)); 1247 exit(1); 1248 } 1249 ra = ra->next; 1250 } 1251 1252 /* initialize msghdr for receiving packets */ 1253 rcviov[0].iov_base = (caddr_t)answer; 1254 rcviov[0].iov_len = sizeof(answer); 1255 rcvmhdr.msg_name = (caddr_t)&from; 1256 rcvmhdr.msg_namelen = sizeof(from); 1257 rcvmhdr.msg_iov = rcviov; 1258 rcvmhdr.msg_iovlen = 1; 1259 rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 1260 rcvmhdr.msg_controllen = rcvcmsgbuflen; 1261 1262 /* initialize msghdr for sending packets */ 1263 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 1264 sndmhdr.msg_iov = sndiov; 1265 sndmhdr.msg_iovlen = 1; 1266 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 1267 sndmhdr.msg_controllen = sndcmsgbuflen; 1268 1269 return; 1270 } 1271 1272 /* open a routing socket to watch the routing table */ 1273 static void 1274 rtsock_open() 1275 { 1276 if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 1277 syslog(LOG_ERR, 1278 "<%s> socket: %s", __FUNCTION__, strerror(errno)); 1279 exit(1); 1280 } 1281 } 1282 1283 static struct rainfo * 1284 if_indextorainfo(int index) 1285 { 1286 struct rainfo *rai = ralist; 1287 1288 for (rai = ralist; rai; rai = rai->next) { 1289 if (rai->ifindex == index) 1290 return(rai); 1291 } 1292 1293 return(NULL); /* search failed */ 1294 } 1295 1296 static void 1297 ra_output(rainfo) 1298 struct rainfo *rainfo; 1299 { 1300 int i; 1301 1302 struct cmsghdr *cm; 1303 struct in6_pktinfo *pi; 1304 1305 sndmhdr.msg_name = (caddr_t)&sin6_allnodes; 1306 sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data; 1307 sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen; 1308 1309 cm = CMSG_FIRSTHDR(&sndmhdr); 1310 /* specify the outgoing interface */ 1311 cm->cmsg_level = IPPROTO_IPV6; 1312 cm->cmsg_type = IPV6_PKTINFO; 1313 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1314 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 1315 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 1316 pi->ipi6_ifindex = rainfo->ifindex; 1317 1318 /* specify the hop limit of the packet */ 1319 { 1320 int hoplimit = 255; 1321 1322 cm = CMSG_NXTHDR(&sndmhdr, cm); 1323 cm->cmsg_level = IPPROTO_IPV6; 1324 cm->cmsg_type = IPV6_HOPLIMIT; 1325 cm->cmsg_len = CMSG_LEN(sizeof(int)); 1326 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 1327 } 1328 1329 syslog(LOG_DEBUG, 1330 "<%s> send RA on %s, # of waitings = %d", 1331 __FUNCTION__, rainfo->ifname, rainfo->waiting); 1332 1333 i = sendmsg(sock, &sndmhdr, 0); 1334 1335 if (i < 0 || i != rainfo->ra_datalen) { 1336 if (i < 0) { 1337 syslog(LOG_ERR, "<%s> sendmsg on %s: %s", 1338 __FUNCTION__, rainfo->ifname, 1339 strerror(errno)); 1340 } 1341 } 1342 1343 /* update counter */ 1344 if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) 1345 rainfo->initcounter++; 1346 rainfo->raoutput++; 1347 1348 /* update timestamp */ 1349 gettimeofday(&rainfo->lastsent, NULL); 1350 1351 /* reset waiting conter */ 1352 rainfo->waiting = 0; 1353 } 1354 1355 /* process RA timer */ 1356 void 1357 ra_timeout(void *data) 1358 { 1359 struct rainfo *rai = (struct rainfo *)data; 1360 1361 #ifdef notyet 1362 /* if necessary, reconstruct the packet. */ 1363 #endif 1364 1365 syslog(LOG_DEBUG, 1366 "<%s> RA timer on %s is expired", 1367 __FUNCTION__, rai->ifname); 1368 1369 if (iflist[rai->ifindex]->ifm_flags & IFF_UP) 1370 ra_output(rai); 1371 else 1372 syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", 1373 __FUNCTION__, rai->ifname); 1374 } 1375 1376 /* update RA timer */ 1377 void 1378 ra_timer_update(void *data, struct timeval *tm) 1379 { 1380 struct rainfo *rai = (struct rainfo *)data; 1381 long interval; 1382 1383 /* 1384 * Whenever a multicast advertisement is sent from an interface, 1385 * the timer is reset to a uniformly-distributed random value 1386 * between the interface's configured MinRtrAdvInterval and 1387 * MaxRtrAdvInterval(discovery-v2-02 6.2.4). 1388 */ 1389 interval = rai->mininterval; 1390 interval += random() % (rai->maxinterval - rai->mininterval); 1391 1392 /* 1393 * For the first few advertisements (up to 1394 * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval 1395 * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer 1396 * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead. 1397 * (RFC-2461 6.2.4) 1398 */ 1399 if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && 1400 interval > MAX_INITIAL_RTR_ADVERT_INTERVAL) 1401 interval = MAX_INITIAL_RTR_ADVERT_INTERVAL; 1402 1403 tm->tv_sec = interval; 1404 tm->tv_usec = 0; 1405 1406 syslog(LOG_DEBUG, 1407 "<%s> RA timer on %s is set to %ld:%ld", 1408 __FUNCTION__, rai->ifname, 1409 (long int)tm->tv_sec, (long int)tm->tv_usec); 1410 1411 return; 1412 } 1413