unix: remove always true check from uipc_attach
[freebsd/src.git] / usr.sbin / rtadvd / if.c
blobe1702a0aa72a3172999c4aaf300e4c4cfb97b6bf
1 /* $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $ */
3 /*-
4 * SPDX-License-Identifier: BSD-3-Clause
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
8 * All rights reserved.
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.
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.
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>
56 #include "pathnames.h"
57 #include "rtadvd.h"
58 #include "if.h"
60 #define ROUNDUP(a, size) \
61 (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
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)))
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,
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,
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,
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 };
90 char *mcastif;
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 *);
97 static void
98 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
100 int i;
102 for (i = 0; i < RTAX_MAX; i++) {
103 if (addrs & (1 << i)) {
104 rti_info[i] = sa;
105 NEXT_SA(sa);
107 else
108 rti_info[i] = NULL;
112 #define ROUNDUP8(a) (1 + (((a) - 1) | 7))
114 lladdropt_length(struct sockaddr_dl *sdl)
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);
126 void
127 lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
129 char *addr;
131 ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
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);
149 rtbuf_len(void)
151 size_t len;
152 int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
154 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
155 return (-1);
157 return (len);
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)
166 struct rt_msghdr *rtm;
167 struct ifa_msghdr *ifam;
168 struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];
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;
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;
189 if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
190 continue;
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;
203 if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
204 IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
205 continue;
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;
213 if (rti_info[RTAX_NETMASK] == NULL)
214 continue;
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;
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;
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;
237 if (ifindex && ifam->ifam_index != ifindex)
238 continue;
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 */
253 return ((char *)rtm);
255 #undef FILTER_MATCH
257 struct in6_addr *
258 get_addr(char *buf)
260 struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
261 struct sockaddr *sa, *rti_info[RTAX_MAX];
263 sa = (struct sockaddr *)(rtm + 1);
264 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
266 return (&SIN6(rti_info[RTAX_DST])->sin6_addr);
270 get_rtm_ifindex(char *buf)
272 struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
273 struct sockaddr *sa, *rti_info[RTAX_MAX];
275 sa = (struct sockaddr *)(rtm + 1);
276 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
278 return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
282 get_prefixlen(char *buf)
284 struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
285 struct sockaddr *sa, *rti_info[RTAX_MAX];
286 char *p, *lim;
288 sa = (struct sockaddr *)(rtm + 1);
289 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
290 sa = rti_info[RTAX_NETMASK];
292 p = (char *)(&SIN6(sa)->sin6_addr);
293 lim = (char *)sa + sa->sa_len;
294 return prefixlen(p, lim);
298 prefixlen(unsigned char *p, unsigned char *lim)
300 int masklen;
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);
335 return (masklen);
338 struct ifinfo *
339 update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname)
341 struct ifinfo *ifi;
342 int ifindex;
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;
357 if (ifi == NULL) {
358 /* A new ifinfo element is needed. */
359 syslog(LOG_DEBUG, "<%s> new entry: %s", __func__,
360 ifname);
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);
370 ifi->ifi_persist = 1;
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);
380 update_ifinfo_nd_flags(struct ifinfo *ifi)
382 struct in6_ndireq nd;
383 int s;
384 int error;
386 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
387 syslog(LOG_ERR,
388 "<%s> socket() failed.", __func__);
389 return (1);
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);
402 ifi->ifi_nd_flags = nd.ndi.flags;
403 close(s);
405 return (0);
408 #define MAX_SYSCTL_TRY 5
410 struct ifinfo *
411 update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex)
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;
423 syslog(LOG_DEBUG, "<%s> enter", __func__);
425 ntry = 0;
426 do {
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.
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);
442 if ((msg = malloc(len)) == NULL) {
443 syslog(LOG_ERR, "<%s> malloc failed", __func__);
444 exit(1);
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);
454 free(msg);
455 msg = NULL;
457 } while (msg == NULL);
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;
465 syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu",
466 __func__, ifm, lim, (char *)lim - (char *)ifm);
468 if (ifm->ifm_version != RTM_VERSION) {
469 syslog(LOG_ERR,
470 "<%s> ifm_vesrion mismatch", __func__);
471 exit(1);
473 if (ifm->ifm_msglen == 0) {
474 syslog(LOG_WARNING,
475 "<%s> ifm_msglen is 0", __func__);
476 free(msg);
477 return (NULL);
480 ifi_new = 0;
481 if (ifm->ifm_type == RTM_IFINFO) {
482 struct ifreq ifr;
483 int s;
484 char ifname[IFNAMSIZ];
486 syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. "
487 "ifm_index = %d, ifindex = %d",
488 __func__, ifm->ifm_index, ifindex);
490 /* when ifindex is specified */
491 if (ifindex != UPDATE_IFINFO_ALL &&
492 ifindex != ifm->ifm_index)
493 continue;
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;
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;
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;
521 /* ifindex */
522 ifi->ifi_ifindex = ifm->ifm_index;
524 /* ifname */
525 strlcpy(ifi->ifi_ifname, ifname, IFNAMSIZ);
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;
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;
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;
562 close(s);
564 /* ND flags */
565 error = update_ifinfo_nd_flags(ifi);
566 if (error) {
567 if (ifi_new)
568 free(ifi);
569 continue;
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));
581 } else
582 memset(&ifi->ifi_sdl, 0,
583 sizeof(ifi->ifi_sdl));
585 /* flags */
586 ifi->ifi_flags = ifm->ifm_flags;
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);
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);
605 free(msg);
607 if (mcastif != NULL) {
608 error = sock_mc_rr_update(&sock, mcastif);
609 if (error)
610 exit(1);
613 return (ifi);
616 static struct if_msghdr *
617 get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim)
619 struct ifa_msghdr *ifam;
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);
629 if (ifam->ifam_type != RTM_NEWADDR)
630 break;
633 return ((struct if_msghdr *)ifam);
637 getinet6sysctl(int code)
639 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
640 int value;
641 size_t size;
643 mib[3] = code;
644 size = sizeof(value);
645 if (sysctl(mib, nitems(mib), &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);
652 else
653 return (value);
658 sock_mc_join(struct sockinfo *s, int ifindex)
660 struct ipv6_mreq mreq;
661 char ifname[IFNAMSIZ];
663 syslog(LOG_DEBUG, "<%s> enter", __func__);
665 if (ifindex == 0)
666 return (1);
669 * join all routers multicast address on each advertising
670 * interface.
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));
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);
687 syslog(LOG_DEBUG,
688 "<%s> %s: join link-local all-routers MC group",
689 __func__, if_indextoname(ifindex, ifname));
691 return (0);
695 sock_mc_leave(struct sockinfo *s, int ifindex)
697 struct ipv6_mreq mreq;
698 char ifname[IFNAMSIZ];
700 syslog(LOG_DEBUG, "<%s> enter", __func__);
702 if (ifindex == 0)
703 return (1);
706 * join all routers multicast address on each advertising
707 * interface.
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));
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);
725 syslog(LOG_DEBUG,
726 "<%s> %s: leave link-local all-routers MC group",
727 __func__, if_indextoname(ifindex, ifname));
729 return (0);
733 sock_mc_rr_update(struct sockinfo *s, char *mif)
735 struct ipv6_mreq mreq;
737 syslog(LOG_DEBUG, "<%s> enter", __func__);
739 if (mif == NULL)
740 return (1);
742 * When attending router renumbering, join all-routers site-local
743 * multicast group.
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);
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);
764 syslog(LOG_DEBUG,
765 "<%s> %s: join site-local all-routers MC group",
766 __func__, mif);
768 return (0);