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