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