1 /* $FreeBSD$ */ 2 /* $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/socket.h> 36 #include <sys/sysctl.h> 37 #include <sys/ioctl.h> 38 #include <net/if.h> 39 #include <net/if_dl.h> 40 #include <net/if_types.h> 41 #include <net/if_var.h> 42 #include <net/ethernet.h> 43 #include <net/route.h> 44 #include <netinet/in.h> 45 #include <netinet/in_var.h> 46 #include <netinet/ip6.h> 47 #include <netinet/icmp6.h> 48 #include <netinet6/nd6.h> 49 #include <unistd.h> 50 #include <errno.h> 51 #include <netdb.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <syslog.h> 55 56 #include "pathnames.h" 57 #include "rtadvd.h" 58 #include "if.h" 59 60 #define ROUNDUP(a, size) \ 61 (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 62 63 #define NEXT_SA(ap) \ 64 (ap) = (struct sockaddr *)((caddr_t)(ap) + \ 65 ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \ 66 sizeof(u_long))) 67 68 struct sockaddr_in6 sin6_linklocal_allnodes = { 69 .sin6_len = sizeof(sin6_linklocal_allnodes), 70 .sin6_family = AF_INET6, 71 .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, 72 }; 73 74 struct sockaddr_in6 sin6_linklocal_allrouters = { 75 .sin6_len = sizeof(sin6_linklocal_allrouters), 76 .sin6_family = AF_INET6, 77 .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, 78 }; 79 80 struct sockaddr_in6 sin6_sitelocal_allrouters = { 81 .sin6_len = sizeof(sin6_sitelocal_allrouters), 82 .sin6_family = AF_INET6, 83 .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT, 84 }; 85 86 struct sockinfo sock = { .si_fd = -1, .si_name = NULL }; 87 struct sockinfo rtsock = { .si_fd = -1, .si_name = NULL }; 88 struct sockinfo ctrlsock = { .si_fd = -1, .si_name = _PATH_CTRL_SOCK }; 89 90 char *mcastif; 91 92 static void get_rtaddrs(int, struct sockaddr *, 93 struct sockaddr **); 94 static struct if_msghdr *get_next_msghdr(struct if_msghdr *, 95 struct if_msghdr *); 96 97 static void 98 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 99 { 100 int i; 101 102 for (i = 0; i < RTAX_MAX; i++) { 103 if (addrs & (1 << i)) { 104 rti_info[i] = sa; 105 NEXT_SA(sa); 106 } 107 else 108 rti_info[i] = NULL; 109 } 110 } 111 112 #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 113 int 114 lladdropt_length(struct sockaddr_dl *sdl) 115 { 116 switch (sdl->sdl_type) { 117 case IFT_ETHER: 118 return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 119 default: 120 return (0); 121 } 122 } 123 124 void 125 lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 126 { 127 char *addr; 128 129 ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 130 131 switch (sdl->sdl_type) { 132 case IFT_ETHER: 133 ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 134 addr = (char *)(ndopt + 1); 135 memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 136 break; 137 default: 138 syslog(LOG_ERR, "<%s> unsupported link type(%d)", 139 __func__, sdl->sdl_type); 140 exit(1); 141 } 142 143 return; 144 } 145 146 int 147 rtbuf_len(void) 148 { 149 size_t len; 150 int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; 151 152 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 153 return (-1); 154 155 return (len); 156 } 157 158 #define FILTER_MATCH(type, filter) ((0x1 << type) & filter) 159 #define SIN6(s) ((struct sockaddr_in6 *)(s)) 160 #define SDL(s) ((struct sockaddr_dl *)(s)) 161 char * 162 get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) 163 { 164 struct rt_msghdr *rtm; 165 struct ifa_msghdr *ifam; 166 struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; 167 168 *lenp = 0; 169 for (rtm = (struct rt_msghdr *)buf; 170 rtm < (struct rt_msghdr *)lim; 171 rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { 172 /* just for safety */ 173 if (!rtm->rtm_msglen) { 174 syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " 175 "(buf=%p lim=%p rtm=%p)", __func__, 176 buf, lim, rtm); 177 break; 178 } 179 if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { 180 syslog(LOG_WARNING, 181 "<%s> routing message version mismatch " 182 "(buf=%p lim=%p rtm=%p)", __func__, 183 buf, lim, rtm); 184 continue; 185 } 186 187 if (FILTER_MATCH(rtm->rtm_type, filter) == 0) 188 continue; 189 190 switch (rtm->rtm_type) { 191 case RTM_GET: 192 case RTM_ADD: 193 case RTM_DELETE: 194 /* address related checks */ 195 sa = (struct sockaddr *)(rtm + 1); 196 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 197 if ((dst = rti_info[RTAX_DST]) == NULL || 198 dst->sa_family != AF_INET6) 199 continue; 200 201 if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || 202 IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) 203 continue; 204 205 if ((gw = rti_info[RTAX_GATEWAY]) == NULL || 206 gw->sa_family != AF_LINK) 207 continue; 208 if (ifindex && SDL(gw)->sdl_index != ifindex) 209 continue; 210 211 if (rti_info[RTAX_NETMASK] == NULL) 212 continue; 213 214 /* found */ 215 *lenp = rtm->rtm_msglen; 216 return (char *)rtm; 217 /* NOTREACHED */ 218 case RTM_NEWADDR: 219 case RTM_DELADDR: 220 ifam = (struct ifa_msghdr *)rtm; 221 222 /* address related checks */ 223 sa = (struct sockaddr *)(ifam + 1); 224 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 225 if ((ifa = rti_info[RTAX_IFA]) == NULL || 226 (ifa->sa_family != AF_INET && 227 ifa->sa_family != AF_INET6)) 228 continue; 229 230 if (ifa->sa_family == AF_INET6 && 231 (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || 232 IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) 233 continue; 234 235 if (ifindex && ifam->ifam_index != ifindex) 236 continue; 237 238 /* found */ 239 *lenp = ifam->ifam_msglen; 240 return (char *)rtm; 241 /* NOTREACHED */ 242 case RTM_IFINFO: 243 case RTM_IFANNOUNCE: 244 /* found */ 245 *lenp = rtm->rtm_msglen; 246 return (char *)rtm; 247 /* NOTREACHED */ 248 } 249 } 250 251 return ((char *)rtm); 252 } 253 #undef FILTER_MATCH 254 255 struct in6_addr * 256 get_addr(char *buf) 257 { 258 struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 259 struct sockaddr *sa, *rti_info[RTAX_MAX]; 260 261 sa = (struct sockaddr *)(rtm + 1); 262 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 263 264 return (&SIN6(rti_info[RTAX_DST])->sin6_addr); 265 } 266 267 int 268 get_rtm_ifindex(char *buf) 269 { 270 struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 271 struct sockaddr *sa, *rti_info[RTAX_MAX]; 272 273 sa = (struct sockaddr *)(rtm + 1); 274 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 275 276 return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); 277 } 278 279 int 280 get_prefixlen(char *buf) 281 { 282 struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 283 struct sockaddr *sa, *rti_info[RTAX_MAX]; 284 char *p, *lim; 285 286 sa = (struct sockaddr *)(rtm + 1); 287 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 288 sa = rti_info[RTAX_NETMASK]; 289 290 p = (char *)(&SIN6(sa)->sin6_addr); 291 lim = (char *)sa + sa->sa_len; 292 return prefixlen(p, lim); 293 } 294 295 int 296 prefixlen(unsigned char *p, unsigned char *lim) 297 { 298 int masklen; 299 300 for (masklen = 0; p < lim; p++) { 301 switch (*p) { 302 case 0xff: 303 masklen += 8; 304 break; 305 case 0xfe: 306 masklen += 7; 307 break; 308 case 0xfc: 309 masklen += 6; 310 break; 311 case 0xf8: 312 masklen += 5; 313 break; 314 case 0xf0: 315 masklen += 4; 316 break; 317 case 0xe0: 318 masklen += 3; 319 break; 320 case 0xc0: 321 masklen += 2; 322 break; 323 case 0x80: 324 masklen += 1; 325 break; 326 case 0x00: 327 break; 328 default: 329 return (-1); 330 } 331 } 332 333 return (masklen); 334 } 335 336 struct ifinfo * 337 update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname) 338 { 339 struct ifinfo *ifi; 340 int ifindex; 341 342 ifi = NULL; 343 ifindex = if_nametoindex(ifname); 344 TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 345 if (ifindex != 0) { 346 if (ifindex == ifi->ifi_ifindex) 347 break; 348 } else { 349 if (strncmp(ifname, ifi->ifi_ifname, 350 sizeof(ifi->ifi_ifname)) == 0) 351 break; 352 } 353 } 354 355 if (ifi == NULL) { 356 /* A new ifinfo element is needed. */ 357 syslog(LOG_DEBUG, "<%s> new entry: %s", __func__, 358 ifname); 359 360 ELM_MALLOC(ifi, exit(1)); 361 ifi->ifi_ifindex = 0; 362 strncpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)-1); 363 ifi->ifi_ifname[sizeof(ifi->ifi_ifname)-1] = '\0'; 364 ifi->ifi_rainfo = NULL; 365 ifi->ifi_state = IFI_STATE_UNCONFIGURED; 366 TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 367 } 368 369 ifi->ifi_persist = 1; 370 371 syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__, 372 ifi->ifi_ifname); 373 syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__, 374 ifi->ifi_ifname, ifi->ifi_state); 375 return (ifi); 376 } 377 378 int 379 update_ifinfo_nd_flags(struct ifinfo *ifi) 380 { 381 struct in6_ndireq nd; 382 int s; 383 int error; 384 385 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 386 syslog(LOG_ERR, 387 "<%s> socket() failed.", __func__); 388 return (1); 389 } 390 /* ND flags */ 391 memset(&nd, 0, sizeof(nd)); 392 strncpy(nd.ifname, ifi->ifi_ifname, 393 sizeof(nd.ifname)); 394 error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd); 395 if (error) { 396 close(s); 397 if (errno != EPFNOSUPPORT) 398 syslog(LOG_ERR, "<%s> ioctl() failed.", __func__); 399 return (1); 400 } 401 ifi->ifi_nd_flags = nd.ndi.flags; 402 close(s); 403 404 return (0); 405 } 406 407 struct ifinfo * 408 update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) 409 { 410 struct if_msghdr *ifm; 411 struct ifinfo *ifi = NULL; 412 struct sockaddr *sa; 413 struct sockaddr *rti_info[RTAX_MAX]; 414 char *msg; 415 size_t len; 416 char *lim; 417 int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; 418 int error; 419 420 syslog(LOG_DEBUG, "<%s> enter", __func__); 421 422 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) < 423 0) { 424 syslog(LOG_ERR, 425 "<%s> sysctl: NET_RT_IFLIST size get failed", __func__); 426 exit(1); 427 } 428 if ((msg = malloc(len)) == NULL) { 429 syslog(LOG_ERR, "<%s> malloc failed", __func__); 430 exit(1); 431 } 432 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) < 433 0) { 434 syslog(LOG_ERR, 435 "<%s> sysctl: NET_RT_IFLIST get failed", __func__); 436 exit(1); 437 } 438 439 lim = msg + len; 440 for (ifm = (struct if_msghdr *)msg; 441 ifm != NULL && ifm < (struct if_msghdr *)lim; 442 ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) { 443 int ifi_new; 444 445 syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu", 446 __func__, ifm, lim, (char *)lim - (char *)ifm); 447 448 if (ifm->ifm_version != RTM_VERSION) { 449 syslog(LOG_ERR, 450 "<%s> ifm_vesrion mismatch", __func__); 451 exit(1); 452 } 453 if (ifm->ifm_msglen == 0) { 454 syslog(LOG_WARNING, 455 "<%s> ifm_msglen is 0", __func__); 456 free(msg); 457 return (NULL); 458 } 459 460 ifi_new = 0; 461 if (ifm->ifm_type == RTM_IFINFO) { 462 struct ifreq ifr; 463 int s; 464 char ifname[IFNAMSIZ]; 465 466 syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. " 467 "ifm_index = %d, ifindex = %d", 468 __func__, ifm->ifm_index, ifindex); 469 470 /* when ifindex is specified */ 471 if (ifindex != UPDATE_IFINFO_ALL && 472 ifindex != ifm->ifm_index) 473 continue; 474 475 /* lookup an entry with the same ifindex */ 476 TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 477 if (ifm->ifm_index == ifi->ifi_ifindex) 478 break; 479 if_indextoname(ifm->ifm_index, ifname); 480 if (strncmp(ifname, ifi->ifi_ifname, 481 sizeof(ifname)) == 0) 482 break; 483 } 484 if (ifi == NULL) { 485 syslog(LOG_DEBUG, 486 "<%s> new entry for idx=%d", 487 __func__, ifm->ifm_index); 488 ELM_MALLOC(ifi, exit(1)); 489 ifi->ifi_rainfo = NULL; 490 ifi->ifi_state = IFI_STATE_UNCONFIGURED; 491 ifi->ifi_persist = 0; 492 ifi_new = 1; 493 } 494 /* ifindex */ 495 ifi->ifi_ifindex = ifm->ifm_index; 496 497 /* ifname */ 498 if_indextoname(ifm->ifm_index, ifi->ifi_ifname); 499 if (ifi->ifi_ifname == NULL) { 500 syslog(LOG_WARNING, 501 "<%s> ifname not found (idx=%d)", 502 __func__, ifm->ifm_index); 503 if (ifi_new) 504 free(ifi); 505 continue; 506 } 507 508 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 509 syslog(LOG_ERR, 510 "<%s> socket() failed.", __func__); 511 if (ifi_new) 512 free(ifi); 513 continue; 514 } 515 516 /* MTU */ 517 ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu; 518 if (ifi->ifi_phymtu == 0) { 519 memset(&ifr, 0, sizeof(ifr)); 520 ifr.ifr_addr.sa_family = AF_INET6; 521 strncpy(ifr.ifr_name, ifi->ifi_ifname, 522 sizeof(ifr.ifr_name)); 523 error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr); 524 if (error) { 525 close(s); 526 syslog(LOG_ERR, 527 "<%s> ioctl() failed.", 528 __func__); 529 if (ifi_new) 530 free(ifi); 531 continue; 532 } 533 ifi->ifi_phymtu = ifr.ifr_mtu; 534 if (ifi->ifi_phymtu == 0) { 535 syslog(LOG_WARNING, 536 "<%s> no interface mtu info" 537 " on %s. %d will be used.", 538 __func__, ifi->ifi_ifname, 539 IPV6_MMTU); 540 ifi->ifi_phymtu = IPV6_MMTU; 541 } 542 } 543 close(s); 544 545 /* ND flags */ 546 error = update_ifinfo_nd_flags(ifi); 547 if (error) { 548 if (ifi_new) 549 free(ifi); 550 continue; 551 } 552 553 /* SDL */ 554 sa = (struct sockaddr *)(ifm + 1); 555 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 556 if ((sa = rti_info[RTAX_IFP]) != NULL) { 557 if (sa->sa_family == AF_LINK) { 558 memcpy(&ifi->ifi_sdl, 559 (struct sockaddr_dl *)sa, 560 sizeof(ifi->ifi_sdl)); 561 } 562 } else 563 memset(&ifi->ifi_sdl, 0, 564 sizeof(ifi->ifi_sdl)); 565 566 /* flags */ 567 ifi->ifi_flags = ifm->ifm_flags; 568 569 /* type */ 570 ifi->ifi_type = ifm->ifm_type; 571 } else { 572 syslog(LOG_ERR, 573 "out of sync parsing NET_RT_IFLIST\n" 574 "expected %d, got %d\n msglen = %d\n", 575 RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen); 576 exit(1); 577 } 578 579 if (ifi_new) { 580 syslog(LOG_DEBUG, 581 "<%s> adding %s(idx=%d) to ifilist", 582 __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 583 TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 584 } 585 } 586 free(msg); 587 588 if (mcastif != NULL) { 589 error = sock_mc_rr_update(&sock, mcastif); 590 if (error) 591 exit(1); 592 } 593 594 return (ifi); 595 } 596 597 static struct if_msghdr * 598 get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim) 599 { 600 struct ifa_msghdr *ifam; 601 602 for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen); 603 ifam < (struct ifa_msghdr *)lim; 604 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) { 605 if (!ifam->ifam_msglen) { 606 syslog(LOG_WARNING, 607 "<%s> ifa_msglen is 0", __func__); 608 return (NULL); 609 } 610 if (ifam->ifam_type != RTM_NEWADDR) 611 break; 612 } 613 614 return ((struct if_msghdr *)ifam); 615 } 616 617 int 618 getinet6sysctl(int code) 619 { 620 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 621 int value; 622 size_t size; 623 624 mib[3] = code; 625 size = sizeof(value); 626 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 627 < 0) { 628 syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 629 __func__, code, 630 strerror(errno)); 631 return (-1); 632 } 633 else 634 return (value); 635 } 636 637 638 int 639 sock_mc_join(struct sockinfo *s, int ifindex) 640 { 641 struct ipv6_mreq mreq; 642 char ifname[IFNAMSIZ]; 643 644 syslog(LOG_DEBUG, "<%s> enter", __func__); 645 646 if (ifindex == 0) 647 return (1); 648 649 /* 650 * join all routers multicast address on each advertising 651 * interface. 652 */ 653 memset(&mreq, 0, sizeof(mreq)); 654 /* XXX */ 655 memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 656 &sin6_linklocal_allrouters.sin6_addr, 657 sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 658 659 mreq.ipv6mr_interface = ifindex; 660 if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 661 sizeof(mreq)) < 0) { 662 syslog(LOG_ERR, 663 "<%s> IPV6_JOIN_GROUP(link) on %s: %s", 664 __func__, if_indextoname(ifindex, ifname), 665 strerror(errno)); 666 return (1); 667 } 668 syslog(LOG_DEBUG, 669 "<%s> %s: join link-local all-routers MC group", 670 __func__, if_indextoname(ifindex, ifname)); 671 672 return (0); 673 } 674 675 int 676 sock_mc_leave(struct sockinfo *s, int ifindex) 677 { 678 struct ipv6_mreq mreq; 679 char ifname[IFNAMSIZ]; 680 681 syslog(LOG_DEBUG, "<%s> enter", __func__); 682 683 if (ifindex == 0) 684 return (1); 685 686 /* 687 * join all routers multicast address on each advertising 688 * interface. 689 */ 690 691 memset(&mreq, 0, sizeof(mreq)); 692 /* XXX */ 693 memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 694 &sin6_linklocal_allrouters.sin6_addr, 695 sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 696 697 mreq.ipv6mr_interface = ifindex; 698 if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, 699 sizeof(mreq)) < 0) { 700 syslog(LOG_ERR, 701 "<%s> IPV6_JOIN_LEAVE(link) on %s: %s", 702 __func__, if_indextoname(ifindex, ifname), 703 strerror(errno)); 704 return (1); 705 } 706 syslog(LOG_DEBUG, 707 "<%s> %s: leave link-local all-routers MC group", 708 __func__, if_indextoname(ifindex, ifname)); 709 710 return (0); 711 } 712 713 int 714 sock_mc_rr_update(struct sockinfo *s, char *mif) 715 { 716 struct ipv6_mreq mreq; 717 718 syslog(LOG_DEBUG, "<%s> enter", __func__); 719 720 if (mif == NULL) 721 return (1); 722 /* 723 * When attending router renumbering, join all-routers site-local 724 * multicast group. 725 */ 726 /* XXX */ 727 memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 728 &sin6_sitelocal_allrouters.sin6_addr, 729 sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 730 if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) { 731 syslog(LOG_ERR, 732 "<%s> invalid interface: %s", 733 __func__, mif); 734 return (1); 735 } 736 737 if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 738 &mreq, sizeof(mreq)) < 0) { 739 syslog(LOG_ERR, 740 "<%s> IPV6_JOIN_GROUP(site) on %s: %s", 741 __func__, mif, strerror(errno)); 742 return (1); 743 } 744 745 syslog(LOG_DEBUG, 746 "<%s> %s: join site-local all-routers MC group", 747 __func__, mif); 748 749 return (0); 750 } 751