1ae326725SJun-ichiro itojun Hagino /* $FreeBSD$ */ 233841545SHajimu UMEMOTO /* $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $ */ 3b26e03e9SKris Kennaway 49a4365d0SYoshinobu Inoue /* 59a4365d0SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 637241896SHiroki Sato * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 79a4365d0SYoshinobu Inoue * All rights reserved. 89a4365d0SYoshinobu Inoue * 99a4365d0SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 109a4365d0SYoshinobu Inoue * modification, are permitted provided that the following conditions 119a4365d0SYoshinobu Inoue * are met: 129a4365d0SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 139a4365d0SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 149a4365d0SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 159a4365d0SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 169a4365d0SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 179a4365d0SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 189a4365d0SYoshinobu Inoue * may be used to endorse or promote products derived from this software 199a4365d0SYoshinobu Inoue * without specific prior written permission. 209a4365d0SYoshinobu Inoue * 219a4365d0SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 229a4365d0SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239a4365d0SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249a4365d0SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 259a4365d0SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269a4365d0SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279a4365d0SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289a4365d0SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299a4365d0SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309a4365d0SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319a4365d0SYoshinobu Inoue * SUCH DAMAGE. 329a4365d0SYoshinobu Inoue */ 339a4365d0SYoshinobu Inoue 349a4365d0SYoshinobu Inoue #include <sys/param.h> 359a4365d0SYoshinobu Inoue #include <sys/socket.h> 369a4365d0SYoshinobu Inoue #include <sys/sysctl.h> 379a4365d0SYoshinobu Inoue #include <sys/ioctl.h> 389a4365d0SYoshinobu Inoue #include <net/if.h> 399a4365d0SYoshinobu Inoue #include <net/if_dl.h> 4037241896SHiroki Sato #include <net/if_types.h> 4137241896SHiroki Sato #include <net/ethernet.h> 4237241896SHiroki Sato #include <net/route.h> 439a4365d0SYoshinobu Inoue #include <netinet/in.h> 4437241896SHiroki Sato #include <netinet/in_var.h> 4537241896SHiroki Sato #include <netinet/ip6.h> 469a4365d0SYoshinobu Inoue #include <netinet/icmp6.h> 4737241896SHiroki Sato #include <netinet6/nd6.h> 489a4365d0SYoshinobu Inoue #include <unistd.h> 499a4365d0SYoshinobu Inoue #include <errno.h> 50db82af41SHiroki Sato #include <netdb.h> 519a4365d0SYoshinobu Inoue #include <stdlib.h> 529a4365d0SYoshinobu Inoue #include <string.h> 539a4365d0SYoshinobu Inoue #include <syslog.h> 5437241896SHiroki Sato 5537241896SHiroki Sato #include "pathnames.h" 569a4365d0SYoshinobu Inoue #include "rtadvd.h" 579a4365d0SYoshinobu Inoue #include "if.h" 589a4365d0SYoshinobu Inoue 599a4365d0SYoshinobu Inoue #define ROUNDUP(a, size) \ 609a4365d0SYoshinobu Inoue (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 619a4365d0SYoshinobu Inoue 62db82af41SHiroki Sato #define NEXT_SA(ap) \ 63db82af41SHiroki Sato (ap) = (struct sockaddr *)((caddr_t)(ap) + \ 64db82af41SHiroki Sato ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \ 659a4365d0SYoshinobu Inoue sizeof(u_long))) 669a4365d0SYoshinobu Inoue 6737241896SHiroki Sato struct sockaddr_in6 sin6_linklocal_allnodes = { 6837241896SHiroki Sato .sin6_len = sizeof(sin6_linklocal_allnodes), 6937241896SHiroki Sato .sin6_family = AF_INET6, 7037241896SHiroki Sato .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, 7137241896SHiroki Sato }; 729a4365d0SYoshinobu Inoue 7337241896SHiroki Sato struct sockaddr_in6 sin6_linklocal_allrouters = { 7437241896SHiroki Sato .sin6_len = sizeof(sin6_linklocal_allrouters), 7537241896SHiroki Sato .sin6_family = AF_INET6, 7637241896SHiroki Sato .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, 7737241896SHiroki Sato }; 7837241896SHiroki Sato 7937241896SHiroki Sato struct sockaddr_in6 sin6_sitelocal_allrouters = { 8037241896SHiroki Sato .sin6_len = sizeof(sin6_sitelocal_allrouters), 8137241896SHiroki Sato .sin6_family = AF_INET6, 8237241896SHiroki Sato .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT, 8337241896SHiroki Sato }; 8437241896SHiroki Sato 8537241896SHiroki Sato struct sockinfo sock = { .si_fd = -1, .si_name = NULL }; 8637241896SHiroki Sato struct sockinfo rtsock = { .si_fd = -1, .si_name = NULL }; 8737241896SHiroki Sato struct sockinfo ctrlsock = { .si_fd = -1, .si_name = _PATH_CTRL_SOCK }; 8837241896SHiroki Sato 8937241896SHiroki Sato char *mcastif; 9037241896SHiroki Sato 9137241896SHiroki Sato static void get_rtaddrs(int, struct sockaddr *, 9237241896SHiroki Sato struct sockaddr **); 9337241896SHiroki Sato static struct if_msghdr *get_next_msghdr(struct if_msghdr *, 9437241896SHiroki Sato struct if_msghdr *); 959a4365d0SYoshinobu Inoue 969a4365d0SYoshinobu Inoue static void 979a4365d0SYoshinobu Inoue get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 989a4365d0SYoshinobu Inoue { 999a4365d0SYoshinobu Inoue int i; 1009a4365d0SYoshinobu Inoue 1019a4365d0SYoshinobu Inoue for (i = 0; i < RTAX_MAX; i++) { 1029a4365d0SYoshinobu Inoue if (addrs & (1 << i)) { 1039a4365d0SYoshinobu Inoue rti_info[i] = sa; 1049a4365d0SYoshinobu Inoue NEXT_SA(sa); 1059a4365d0SYoshinobu Inoue } 1069a4365d0SYoshinobu Inoue else 1079a4365d0SYoshinobu Inoue rti_info[i] = NULL; 1089a4365d0SYoshinobu Inoue } 1099a4365d0SYoshinobu Inoue } 1109a4365d0SYoshinobu Inoue 1119a4365d0SYoshinobu Inoue #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 1129a4365d0SYoshinobu Inoue int 1139a4365d0SYoshinobu Inoue lladdropt_length(struct sockaddr_dl *sdl) 1149a4365d0SYoshinobu Inoue { 1159a4365d0SYoshinobu Inoue switch (sdl->sdl_type) { 1169a4365d0SYoshinobu Inoue case IFT_ETHER: 1179a4365d0SYoshinobu Inoue return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 1189a4365d0SYoshinobu Inoue default: 1199a4365d0SYoshinobu Inoue return (0); 1209a4365d0SYoshinobu Inoue } 1219a4365d0SYoshinobu Inoue } 1229a4365d0SYoshinobu Inoue 1239a4365d0SYoshinobu Inoue void 1249a4365d0SYoshinobu Inoue lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 1259a4365d0SYoshinobu Inoue { 1269a4365d0SYoshinobu Inoue char *addr; 1279a4365d0SYoshinobu Inoue 1289a4365d0SYoshinobu Inoue ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 1299a4365d0SYoshinobu Inoue 1309a4365d0SYoshinobu Inoue switch (sdl->sdl_type) { 1319a4365d0SYoshinobu Inoue case IFT_ETHER: 1329a4365d0SYoshinobu Inoue ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 1339a4365d0SYoshinobu Inoue addr = (char *)(ndopt + 1); 1349a4365d0SYoshinobu Inoue memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 1359a4365d0SYoshinobu Inoue break; 1369a4365d0SYoshinobu Inoue default: 137fa19f9beSHajimu UMEMOTO syslog(LOG_ERR, "<%s> unsupported link type(%d)", 1381533bed0SHajimu UMEMOTO __func__, sdl->sdl_type); 1399a4365d0SYoshinobu Inoue exit(1); 1409a4365d0SYoshinobu Inoue } 1419a4365d0SYoshinobu Inoue 1429a4365d0SYoshinobu Inoue return; 1439a4365d0SYoshinobu Inoue } 1449a4365d0SYoshinobu Inoue 1459a4365d0SYoshinobu Inoue int 146db82af41SHiroki Sato rtbuf_len(void) 1479a4365d0SYoshinobu Inoue { 1489a4365d0SYoshinobu Inoue size_t len; 1499a4365d0SYoshinobu Inoue int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; 1509a4365d0SYoshinobu Inoue 1519a4365d0SYoshinobu Inoue if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 1529a4365d0SYoshinobu Inoue return (-1); 1539a4365d0SYoshinobu Inoue 1549a4365d0SYoshinobu Inoue return (len); 1559a4365d0SYoshinobu Inoue } 1569a4365d0SYoshinobu Inoue 1579a4365d0SYoshinobu Inoue #define FILTER_MATCH(type, filter) ((0x1 << type) & filter) 1589a4365d0SYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)(s)) 1599a4365d0SYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)(s)) 1609a4365d0SYoshinobu Inoue char * 1619a4365d0SYoshinobu Inoue get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) 1629a4365d0SYoshinobu Inoue { 1639a4365d0SYoshinobu Inoue struct rt_msghdr *rtm; 1649a4365d0SYoshinobu Inoue struct ifa_msghdr *ifam; 1659a4365d0SYoshinobu Inoue struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; 1669a4365d0SYoshinobu Inoue 1679a4365d0SYoshinobu Inoue *lenp = 0; 1689a4365d0SYoshinobu Inoue for (rtm = (struct rt_msghdr *)buf; 1699a4365d0SYoshinobu Inoue rtm < (struct rt_msghdr *)lim; 1709a4365d0SYoshinobu Inoue rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { 1719a4365d0SYoshinobu Inoue /* just for safety */ 1729a4365d0SYoshinobu Inoue if (!rtm->rtm_msglen) { 1739a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " 1741533bed0SHajimu UMEMOTO "(buf=%p lim=%p rtm=%p)", __func__, 1759a4365d0SYoshinobu Inoue buf, lim, rtm); 1769a4365d0SYoshinobu Inoue break; 1779a4365d0SYoshinobu Inoue } 178db82af41SHiroki Sato if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { 179db82af41SHiroki Sato syslog(LOG_WARNING, 180db82af41SHiroki Sato "<%s> routing message version mismatch " 181db82af41SHiroki Sato "(buf=%p lim=%p rtm=%p)", __func__, 182db82af41SHiroki Sato buf, lim, rtm); 1839a4365d0SYoshinobu Inoue continue; 1849a4365d0SYoshinobu Inoue } 1859a4365d0SYoshinobu Inoue 186db82af41SHiroki Sato if (FILTER_MATCH(rtm->rtm_type, filter) == 0) 187db82af41SHiroki Sato continue; 188db82af41SHiroki Sato 1899a4365d0SYoshinobu Inoue switch (rtm->rtm_type) { 1909a4365d0SYoshinobu Inoue case RTM_GET: 1919a4365d0SYoshinobu Inoue case RTM_ADD: 1929a4365d0SYoshinobu Inoue case RTM_DELETE: 1939a4365d0SYoshinobu Inoue /* address related checks */ 1949a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 1959a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 1969a4365d0SYoshinobu Inoue if ((dst = rti_info[RTAX_DST]) == NULL || 1979a4365d0SYoshinobu Inoue dst->sa_family != AF_INET6) 1989a4365d0SYoshinobu Inoue continue; 1999a4365d0SYoshinobu Inoue 2009a4365d0SYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || 2019a4365d0SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) 2029a4365d0SYoshinobu Inoue continue; 2039a4365d0SYoshinobu Inoue 2049a4365d0SYoshinobu Inoue if ((gw = rti_info[RTAX_GATEWAY]) == NULL || 2059a4365d0SYoshinobu Inoue gw->sa_family != AF_LINK) 2069a4365d0SYoshinobu Inoue continue; 2079a4365d0SYoshinobu Inoue if (ifindex && SDL(gw)->sdl_index != ifindex) 2089a4365d0SYoshinobu Inoue continue; 2099a4365d0SYoshinobu Inoue 2109a4365d0SYoshinobu Inoue if (rti_info[RTAX_NETMASK] == NULL) 2119a4365d0SYoshinobu Inoue continue; 2129a4365d0SYoshinobu Inoue 2139a4365d0SYoshinobu Inoue /* found */ 2149a4365d0SYoshinobu Inoue *lenp = rtm->rtm_msglen; 2159a4365d0SYoshinobu Inoue return (char *)rtm; 2169a4365d0SYoshinobu Inoue /* NOTREACHED */ 2179a4365d0SYoshinobu Inoue case RTM_NEWADDR: 2189a4365d0SYoshinobu Inoue case RTM_DELADDR: 2199a4365d0SYoshinobu Inoue ifam = (struct ifa_msghdr *)rtm; 2209a4365d0SYoshinobu Inoue 2219a4365d0SYoshinobu Inoue /* address related checks */ 2229a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(ifam + 1); 2239a4365d0SYoshinobu Inoue get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 2249a4365d0SYoshinobu Inoue if ((ifa = rti_info[RTAX_IFA]) == NULL || 2259a4365d0SYoshinobu Inoue (ifa->sa_family != AF_INET && 2269a4365d0SYoshinobu Inoue ifa->sa_family != AF_INET6)) 2279a4365d0SYoshinobu Inoue continue; 2289a4365d0SYoshinobu Inoue 2299a4365d0SYoshinobu Inoue if (ifa->sa_family == AF_INET6 && 2309a4365d0SYoshinobu Inoue (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || 2319a4365d0SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) 2329a4365d0SYoshinobu Inoue continue; 2339a4365d0SYoshinobu Inoue 2349a4365d0SYoshinobu Inoue if (ifindex && ifam->ifam_index != ifindex) 2359a4365d0SYoshinobu Inoue continue; 2369a4365d0SYoshinobu Inoue 2379a4365d0SYoshinobu Inoue /* found */ 2389a4365d0SYoshinobu Inoue *lenp = ifam->ifam_msglen; 2399a4365d0SYoshinobu Inoue return (char *)rtm; 2409a4365d0SYoshinobu Inoue /* NOTREACHED */ 2419a4365d0SYoshinobu Inoue case RTM_IFINFO: 242db82af41SHiroki Sato case RTM_IFANNOUNCE: 2439a4365d0SYoshinobu Inoue /* found */ 2449a4365d0SYoshinobu Inoue *lenp = rtm->rtm_msglen; 2459a4365d0SYoshinobu Inoue return (char *)rtm; 2469a4365d0SYoshinobu Inoue /* NOTREACHED */ 2479a4365d0SYoshinobu Inoue } 2489a4365d0SYoshinobu Inoue } 2499a4365d0SYoshinobu Inoue 250db82af41SHiroki Sato return ((char *)rtm); 2519a4365d0SYoshinobu Inoue } 25233841545SHajimu UMEMOTO #undef FILTER_MATCH 2539a4365d0SYoshinobu Inoue 2549a4365d0SYoshinobu Inoue struct in6_addr * 2559a4365d0SYoshinobu Inoue get_addr(char *buf) 2569a4365d0SYoshinobu Inoue { 2579a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2589a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 2599a4365d0SYoshinobu Inoue 2609a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2619a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2629a4365d0SYoshinobu Inoue 2639a4365d0SYoshinobu Inoue return (&SIN6(rti_info[RTAX_DST])->sin6_addr); 2649a4365d0SYoshinobu Inoue } 2659a4365d0SYoshinobu Inoue 2669a4365d0SYoshinobu Inoue int 2679a4365d0SYoshinobu Inoue get_rtm_ifindex(char *buf) 2689a4365d0SYoshinobu Inoue { 2699a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2709a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 2719a4365d0SYoshinobu Inoue 2729a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2739a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2749a4365d0SYoshinobu Inoue 2759a4365d0SYoshinobu Inoue return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); 2769a4365d0SYoshinobu Inoue } 2779a4365d0SYoshinobu Inoue 2789a4365d0SYoshinobu Inoue int 2799a4365d0SYoshinobu Inoue get_prefixlen(char *buf) 2809a4365d0SYoshinobu Inoue { 2819a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2829a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 28337241896SHiroki Sato char *p, *lim; 2849a4365d0SYoshinobu Inoue 2859a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2869a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2879a4365d0SYoshinobu Inoue sa = rti_info[RTAX_NETMASK]; 2889a4365d0SYoshinobu Inoue 28937241896SHiroki Sato p = (char *)(&SIN6(sa)->sin6_addr); 29037241896SHiroki Sato lim = (char *)sa + sa->sa_len; 2917c991abcSHajimu UMEMOTO return prefixlen(p, lim); 2927c991abcSHajimu UMEMOTO } 2937c991abcSHajimu UMEMOTO 2947c991abcSHajimu UMEMOTO int 29537241896SHiroki Sato prefixlen(unsigned char *p, unsigned char *lim) 2967c991abcSHajimu UMEMOTO { 2977c991abcSHajimu UMEMOTO int masklen; 2987c991abcSHajimu UMEMOTO 2999a4365d0SYoshinobu Inoue for (masklen = 0; p < lim; p++) { 3009a4365d0SYoshinobu Inoue switch (*p) { 3019a4365d0SYoshinobu Inoue case 0xff: 3029a4365d0SYoshinobu Inoue masklen += 8; 3039a4365d0SYoshinobu Inoue break; 3049a4365d0SYoshinobu Inoue case 0xfe: 3059a4365d0SYoshinobu Inoue masklen += 7; 3069a4365d0SYoshinobu Inoue break; 3079a4365d0SYoshinobu Inoue case 0xfc: 3089a4365d0SYoshinobu Inoue masklen += 6; 3099a4365d0SYoshinobu Inoue break; 3109a4365d0SYoshinobu Inoue case 0xf8: 3119a4365d0SYoshinobu Inoue masklen += 5; 3129a4365d0SYoshinobu Inoue break; 3139a4365d0SYoshinobu Inoue case 0xf0: 3149a4365d0SYoshinobu Inoue masklen += 4; 3159a4365d0SYoshinobu Inoue break; 3169a4365d0SYoshinobu Inoue case 0xe0: 3179a4365d0SYoshinobu Inoue masklen += 3; 3189a4365d0SYoshinobu Inoue break; 3199a4365d0SYoshinobu Inoue case 0xc0: 3209a4365d0SYoshinobu Inoue masklen += 2; 3219a4365d0SYoshinobu Inoue break; 3229a4365d0SYoshinobu Inoue case 0x80: 3239a4365d0SYoshinobu Inoue masklen += 1; 3249a4365d0SYoshinobu Inoue break; 3259a4365d0SYoshinobu Inoue case 0x00: 3269a4365d0SYoshinobu Inoue break; 3279a4365d0SYoshinobu Inoue default: 3289a4365d0SYoshinobu Inoue return (-1); 3299a4365d0SYoshinobu Inoue } 3309a4365d0SYoshinobu Inoue } 3319a4365d0SYoshinobu Inoue 3329a4365d0SYoshinobu Inoue return (masklen); 3339a4365d0SYoshinobu Inoue } 3349a4365d0SYoshinobu Inoue 33537241896SHiroki Sato struct ifinfo * 33637241896SHiroki Sato update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname) 3379a4365d0SYoshinobu Inoue { 33837241896SHiroki Sato struct ifinfo *ifi; 33937241896SHiroki Sato int ifindex; 3409a4365d0SYoshinobu Inoue 34137241896SHiroki Sato ifi = NULL; 34237241896SHiroki Sato ifindex = if_nametoindex(ifname); 34337241896SHiroki Sato TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 34437241896SHiroki Sato if (ifindex != 0) { 34537241896SHiroki Sato if (ifindex == ifi->ifi_ifindex) 34637241896SHiroki Sato break; 3479a4365d0SYoshinobu Inoue } else { 34837241896SHiroki Sato if (strncmp(ifname, ifi->ifi_ifname, 34937241896SHiroki Sato sizeof(ifi->ifi_ifname)) == 0) 35037241896SHiroki Sato break; 35137241896SHiroki Sato } 35237241896SHiroki Sato } 35337241896SHiroki Sato 35437241896SHiroki Sato if (ifi == NULL) { 35537241896SHiroki Sato /* A new ifinfo element is needed. */ 35637241896SHiroki Sato syslog(LOG_DEBUG, "<%s> new entry: %s", __func__, 35737241896SHiroki Sato ifname); 35837241896SHiroki Sato 35937241896SHiroki Sato ELM_MALLOC(ifi, exit(1)); 36037241896SHiroki Sato ifi->ifi_ifindex = 0; 361*6bce9a10SXin LI strlcpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)); 36237241896SHiroki Sato ifi->ifi_rainfo = NULL; 36337241896SHiroki Sato ifi->ifi_state = IFI_STATE_UNCONFIGURED; 36437241896SHiroki Sato TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 36537241896SHiroki Sato } 36637241896SHiroki Sato 36737241896SHiroki Sato ifi->ifi_persist = 1; 36837241896SHiroki Sato 36937241896SHiroki Sato syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__, 37037241896SHiroki Sato ifi->ifi_ifname); 37137241896SHiroki Sato syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__, 37237241896SHiroki Sato ifi->ifi_ifname, ifi->ifi_state); 37337241896SHiroki Sato return (ifi); 37437241896SHiroki Sato } 37537241896SHiroki Sato 37637241896SHiroki Sato int 37737241896SHiroki Sato update_ifinfo_nd_flags(struct ifinfo *ifi) 37837241896SHiroki Sato { 37937241896SHiroki Sato struct in6_ndireq nd; 38037241896SHiroki Sato int s; 38137241896SHiroki Sato int error; 38237241896SHiroki Sato 38337241896SHiroki Sato if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 38437241896SHiroki Sato syslog(LOG_ERR, 38537241896SHiroki Sato "<%s> socket() failed.", __func__); 38637241896SHiroki Sato return (1); 38737241896SHiroki Sato } 38837241896SHiroki Sato /* ND flags */ 38937241896SHiroki Sato memset(&nd, 0, sizeof(nd)); 39037241896SHiroki Sato strncpy(nd.ifname, ifi->ifi_ifname, 39137241896SHiroki Sato sizeof(nd.ifname)); 39237241896SHiroki Sato error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd); 39337241896SHiroki Sato if (error) { 39437241896SHiroki Sato close(s); 39542f725eeSHiroki Sato if (errno != EPFNOSUPPORT) 39642f725eeSHiroki Sato syslog(LOG_ERR, "<%s> ioctl() failed.", __func__); 39737241896SHiroki Sato return (1); 39837241896SHiroki Sato } 39937241896SHiroki Sato ifi->ifi_nd_flags = nd.ndi.flags; 40037241896SHiroki Sato close(s); 40137241896SHiroki Sato 40237241896SHiroki Sato return (0); 40337241896SHiroki Sato } 40437241896SHiroki Sato 40537241896SHiroki Sato struct ifinfo * 40637241896SHiroki Sato update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) 40737241896SHiroki Sato { 40837241896SHiroki Sato struct if_msghdr *ifm; 40937241896SHiroki Sato struct ifinfo *ifi = NULL; 41037241896SHiroki Sato struct sockaddr *sa; 41137241896SHiroki Sato struct sockaddr *rti_info[RTAX_MAX]; 41237241896SHiroki Sato char *msg; 41337241896SHiroki Sato size_t len; 41437241896SHiroki Sato char *lim; 41537241896SHiroki Sato int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; 41637241896SHiroki Sato int error; 41737241896SHiroki Sato 41837241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 41937241896SHiroki Sato 42037241896SHiroki Sato if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) < 42137241896SHiroki Sato 0) { 42237241896SHiroki Sato syslog(LOG_ERR, 42337241896SHiroki Sato "<%s> sysctl: NET_RT_IFLIST size get failed", __func__); 4249a4365d0SYoshinobu Inoue exit(1); 4259a4365d0SYoshinobu Inoue } 42637241896SHiroki Sato if ((msg = malloc(len)) == NULL) { 42737241896SHiroki Sato syslog(LOG_ERR, "<%s> malloc failed", __func__); 42837241896SHiroki Sato exit(1); 42937241896SHiroki Sato } 43037241896SHiroki Sato if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) < 43137241896SHiroki Sato 0) { 43237241896SHiroki Sato syslog(LOG_ERR, 43337241896SHiroki Sato "<%s> sysctl: NET_RT_IFLIST get failed", __func__); 43437241896SHiroki Sato exit(1); 43537241896SHiroki Sato } 43637241896SHiroki Sato 43737241896SHiroki Sato lim = msg + len; 43837241896SHiroki Sato for (ifm = (struct if_msghdr *)msg; 43937241896SHiroki Sato ifm != NULL && ifm < (struct if_msghdr *)lim; 44037241896SHiroki Sato ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) { 44137241896SHiroki Sato int ifi_new; 44237241896SHiroki Sato 44337241896SHiroki Sato syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu", 44437241896SHiroki Sato __func__, ifm, lim, (char *)lim - (char *)ifm); 44537241896SHiroki Sato 44637241896SHiroki Sato if (ifm->ifm_version != RTM_VERSION) { 44737241896SHiroki Sato syslog(LOG_ERR, 44837241896SHiroki Sato "<%s> ifm_vesrion mismatch", __func__); 44937241896SHiroki Sato exit(1); 45037241896SHiroki Sato } 45137241896SHiroki Sato if (ifm->ifm_msglen == 0) { 45237241896SHiroki Sato syslog(LOG_WARNING, 45337241896SHiroki Sato "<%s> ifm_msglen is 0", __func__); 45437241896SHiroki Sato free(msg); 45537241896SHiroki Sato return (NULL); 45637241896SHiroki Sato } 45737241896SHiroki Sato 45837241896SHiroki Sato ifi_new = 0; 45937241896SHiroki Sato if (ifm->ifm_type == RTM_IFINFO) { 46037241896SHiroki Sato struct ifreq ifr; 46137241896SHiroki Sato int s; 46237241896SHiroki Sato char ifname[IFNAMSIZ]; 46337241896SHiroki Sato 46437241896SHiroki Sato syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. " 46537241896SHiroki Sato "ifm_index = %d, ifindex = %d", 46637241896SHiroki Sato __func__, ifm->ifm_index, ifindex); 46737241896SHiroki Sato 46837241896SHiroki Sato /* when ifindex is specified */ 46937241896SHiroki Sato if (ifindex != UPDATE_IFINFO_ALL && 47037241896SHiroki Sato ifindex != ifm->ifm_index) 47137241896SHiroki Sato continue; 47237241896SHiroki Sato 47337241896SHiroki Sato /* lookup an entry with the same ifindex */ 47437241896SHiroki Sato TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 47537241896SHiroki Sato if (ifm->ifm_index == ifi->ifi_ifindex) 47637241896SHiroki Sato break; 47737241896SHiroki Sato if_indextoname(ifm->ifm_index, ifname); 47837241896SHiroki Sato if (strncmp(ifname, ifi->ifi_ifname, 47937241896SHiroki Sato sizeof(ifname)) == 0) 48037241896SHiroki Sato break; 48137241896SHiroki Sato } 48237241896SHiroki Sato if (ifi == NULL) { 48337241896SHiroki Sato syslog(LOG_DEBUG, 48437241896SHiroki Sato "<%s> new entry for idx=%d", 48537241896SHiroki Sato __func__, ifm->ifm_index); 48637241896SHiroki Sato ELM_MALLOC(ifi, exit(1)); 48737241896SHiroki Sato ifi->ifi_rainfo = NULL; 48837241896SHiroki Sato ifi->ifi_state = IFI_STATE_UNCONFIGURED; 48937241896SHiroki Sato ifi->ifi_persist = 0; 49037241896SHiroki Sato ifi_new = 1; 49137241896SHiroki Sato } 49237241896SHiroki Sato /* ifindex */ 49337241896SHiroki Sato ifi->ifi_ifindex = ifm->ifm_index; 49437241896SHiroki Sato 49537241896SHiroki Sato /* ifname */ 49637241896SHiroki Sato if_indextoname(ifm->ifm_index, ifi->ifi_ifname); 49737241896SHiroki Sato if (ifi->ifi_ifname == NULL) { 49837241896SHiroki Sato syslog(LOG_WARNING, 49937241896SHiroki Sato "<%s> ifname not found (idx=%d)", 50037241896SHiroki Sato __func__, ifm->ifm_index); 50137241896SHiroki Sato if (ifi_new) 50237241896SHiroki Sato free(ifi); 50337241896SHiroki Sato continue; 50437241896SHiroki Sato } 50537241896SHiroki Sato 50637241896SHiroki Sato if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 50737241896SHiroki Sato syslog(LOG_ERR, 50837241896SHiroki Sato "<%s> socket() failed.", __func__); 50937241896SHiroki Sato if (ifi_new) 51037241896SHiroki Sato free(ifi); 51137241896SHiroki Sato continue; 51237241896SHiroki Sato } 51337241896SHiroki Sato 51437241896SHiroki Sato /* MTU */ 51537241896SHiroki Sato ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu; 51637241896SHiroki Sato if (ifi->ifi_phymtu == 0) { 51737241896SHiroki Sato memset(&ifr, 0, sizeof(ifr)); 51837241896SHiroki Sato ifr.ifr_addr.sa_family = AF_INET6; 51937241896SHiroki Sato strncpy(ifr.ifr_name, ifi->ifi_ifname, 52037241896SHiroki Sato sizeof(ifr.ifr_name)); 52137241896SHiroki Sato error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr); 52237241896SHiroki Sato if (error) { 52337241896SHiroki Sato close(s); 52437241896SHiroki Sato syslog(LOG_ERR, 52537241896SHiroki Sato "<%s> ioctl() failed.", 52637241896SHiroki Sato __func__); 52737241896SHiroki Sato if (ifi_new) 52837241896SHiroki Sato free(ifi); 52937241896SHiroki Sato continue; 53037241896SHiroki Sato } 53137241896SHiroki Sato ifi->ifi_phymtu = ifr.ifr_mtu; 53237241896SHiroki Sato if (ifi->ifi_phymtu == 0) { 53337241896SHiroki Sato syslog(LOG_WARNING, 53437241896SHiroki Sato "<%s> no interface mtu info" 53537241896SHiroki Sato " on %s. %d will be used.", 53637241896SHiroki Sato __func__, ifi->ifi_ifname, 53737241896SHiroki Sato IPV6_MMTU); 53837241896SHiroki Sato ifi->ifi_phymtu = IPV6_MMTU; 53937241896SHiroki Sato } 54037241896SHiroki Sato } 54137241896SHiroki Sato close(s); 54237241896SHiroki Sato 54337241896SHiroki Sato /* ND flags */ 54437241896SHiroki Sato error = update_ifinfo_nd_flags(ifi); 54537241896SHiroki Sato if (error) { 54637241896SHiroki Sato if (ifi_new) 54737241896SHiroki Sato free(ifi); 54837241896SHiroki Sato continue; 54937241896SHiroki Sato } 55037241896SHiroki Sato 55137241896SHiroki Sato /* SDL */ 55237241896SHiroki Sato sa = (struct sockaddr *)(ifm + 1); 55337241896SHiroki Sato get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 55437241896SHiroki Sato if ((sa = rti_info[RTAX_IFP]) != NULL) { 55537241896SHiroki Sato if (sa->sa_family == AF_LINK) { 55637241896SHiroki Sato memcpy(&ifi->ifi_sdl, 55737241896SHiroki Sato (struct sockaddr_dl *)sa, 55837241896SHiroki Sato sizeof(ifi->ifi_sdl)); 55937241896SHiroki Sato } 56037241896SHiroki Sato } else 56137241896SHiroki Sato memset(&ifi->ifi_sdl, 0, 56237241896SHiroki Sato sizeof(ifi->ifi_sdl)); 56337241896SHiroki Sato 56437241896SHiroki Sato /* flags */ 56537241896SHiroki Sato ifi->ifi_flags = ifm->ifm_flags; 56637241896SHiroki Sato 56737241896SHiroki Sato /* type */ 56837241896SHiroki Sato ifi->ifi_type = ifm->ifm_type; 56937241896SHiroki Sato } else { 57037241896SHiroki Sato syslog(LOG_ERR, 57137241896SHiroki Sato "out of sync parsing NET_RT_IFLIST\n" 57237241896SHiroki Sato "expected %d, got %d\n msglen = %d\n", 57337241896SHiroki Sato RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen); 57437241896SHiroki Sato exit(1); 57537241896SHiroki Sato } 57637241896SHiroki Sato 57737241896SHiroki Sato if (ifi_new) { 57837241896SHiroki Sato syslog(LOG_DEBUG, 57937241896SHiroki Sato "<%s> adding %s(idx=%d) to ifilist", 58037241896SHiroki Sato __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 58137241896SHiroki Sato TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 58237241896SHiroki Sato } 58337241896SHiroki Sato } 58437241896SHiroki Sato free(msg); 58537241896SHiroki Sato 58637241896SHiroki Sato if (mcastif != NULL) { 58737241896SHiroki Sato error = sock_mc_rr_update(&sock, mcastif); 58837241896SHiroki Sato if (error) 58937241896SHiroki Sato exit(1); 59037241896SHiroki Sato } 59137241896SHiroki Sato 59237241896SHiroki Sato return (ifi); 59337241896SHiroki Sato } 59437241896SHiroki Sato 59537241896SHiroki Sato static struct if_msghdr * 59637241896SHiroki Sato get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim) 59737241896SHiroki Sato { 59837241896SHiroki Sato struct ifa_msghdr *ifam; 59937241896SHiroki Sato 60037241896SHiroki Sato for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen); 6019a4365d0SYoshinobu Inoue ifam < (struct ifa_msghdr *)lim; 60237241896SHiroki Sato ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) { 6039a4365d0SYoshinobu Inoue if (!ifam->ifam_msglen) { 60437241896SHiroki Sato syslog(LOG_WARNING, 60537241896SHiroki Sato "<%s> ifa_msglen is 0", __func__); 60637241896SHiroki Sato return (NULL); 6079a4365d0SYoshinobu Inoue } 6089a4365d0SYoshinobu Inoue if (ifam->ifam_type != RTM_NEWADDR) 6099a4365d0SYoshinobu Inoue break; 6109a4365d0SYoshinobu Inoue } 61137241896SHiroki Sato 61237241896SHiroki Sato return ((struct if_msghdr *)ifam); 6139a4365d0SYoshinobu Inoue } 6149a4365d0SYoshinobu Inoue 61537241896SHiroki Sato int 61637241896SHiroki Sato getinet6sysctl(int code) 6179a4365d0SYoshinobu Inoue { 61837241896SHiroki Sato int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 61937241896SHiroki Sato int value; 62037241896SHiroki Sato size_t size; 621db82af41SHiroki Sato 62237241896SHiroki Sato mib[3] = code; 62337241896SHiroki Sato size = sizeof(value); 62437241896SHiroki Sato if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 62537241896SHiroki Sato < 0) { 62637241896SHiroki Sato syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 62737241896SHiroki Sato __func__, code, 62837241896SHiroki Sato strerror(errno)); 62937241896SHiroki Sato return (-1); 6309a4365d0SYoshinobu Inoue } 63137241896SHiroki Sato else 63237241896SHiroki Sato return (value); 63337241896SHiroki Sato } 6349a4365d0SYoshinobu Inoue 63537241896SHiroki Sato 63637241896SHiroki Sato int 63737241896SHiroki Sato sock_mc_join(struct sockinfo *s, int ifindex) 63837241896SHiroki Sato { 63937241896SHiroki Sato struct ipv6_mreq mreq; 64037241896SHiroki Sato char ifname[IFNAMSIZ]; 64137241896SHiroki Sato 64237241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 64337241896SHiroki Sato 64437241896SHiroki Sato if (ifindex == 0) 64537241896SHiroki Sato return (1); 64637241896SHiroki Sato 64737241896SHiroki Sato /* 64837241896SHiroki Sato * join all routers multicast address on each advertising 64937241896SHiroki Sato * interface. 65037241896SHiroki Sato */ 65137241896SHiroki Sato memset(&mreq, 0, sizeof(mreq)); 65237241896SHiroki Sato /* XXX */ 65337241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 65437241896SHiroki Sato &sin6_linklocal_allrouters.sin6_addr, 65537241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 65637241896SHiroki Sato 65737241896SHiroki Sato mreq.ipv6mr_interface = ifindex; 65837241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 65937241896SHiroki Sato sizeof(mreq)) < 0) { 66037241896SHiroki Sato syslog(LOG_ERR, 66137241896SHiroki Sato "<%s> IPV6_JOIN_GROUP(link) on %s: %s", 66237241896SHiroki Sato __func__, if_indextoname(ifindex, ifname), 66337241896SHiroki Sato strerror(errno)); 66437241896SHiroki Sato return (1); 66537241896SHiroki Sato } 66637241896SHiroki Sato syslog(LOG_DEBUG, 66737241896SHiroki Sato "<%s> %s: join link-local all-routers MC group", 66837241896SHiroki Sato __func__, if_indextoname(ifindex, ifname)); 66937241896SHiroki Sato 67037241896SHiroki Sato return (0); 67137241896SHiroki Sato } 67237241896SHiroki Sato 67337241896SHiroki Sato int 67437241896SHiroki Sato sock_mc_leave(struct sockinfo *s, int ifindex) 67537241896SHiroki Sato { 67637241896SHiroki Sato struct ipv6_mreq mreq; 67737241896SHiroki Sato char ifname[IFNAMSIZ]; 67837241896SHiroki Sato 67937241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 68037241896SHiroki Sato 68137241896SHiroki Sato if (ifindex == 0) 68237241896SHiroki Sato return (1); 68337241896SHiroki Sato 68437241896SHiroki Sato /* 68537241896SHiroki Sato * join all routers multicast address on each advertising 68637241896SHiroki Sato * interface. 68737241896SHiroki Sato */ 68837241896SHiroki Sato 68937241896SHiroki Sato memset(&mreq, 0, sizeof(mreq)); 69037241896SHiroki Sato /* XXX */ 69137241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 69237241896SHiroki Sato &sin6_linklocal_allrouters.sin6_addr, 69337241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 69437241896SHiroki Sato 69537241896SHiroki Sato mreq.ipv6mr_interface = ifindex; 69637241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, 69737241896SHiroki Sato sizeof(mreq)) < 0) { 69837241896SHiroki Sato syslog(LOG_ERR, 69937241896SHiroki Sato "<%s> IPV6_JOIN_LEAVE(link) on %s: %s", 70037241896SHiroki Sato __func__, if_indextoname(ifindex, ifname), 70137241896SHiroki Sato strerror(errno)); 70237241896SHiroki Sato return (1); 70337241896SHiroki Sato } 70437241896SHiroki Sato syslog(LOG_DEBUG, 70537241896SHiroki Sato "<%s> %s: leave link-local all-routers MC group", 70637241896SHiroki Sato __func__, if_indextoname(ifindex, ifname)); 70737241896SHiroki Sato 70837241896SHiroki Sato return (0); 70937241896SHiroki Sato } 71037241896SHiroki Sato 71137241896SHiroki Sato int 71237241896SHiroki Sato sock_mc_rr_update(struct sockinfo *s, char *mif) 71337241896SHiroki Sato { 71437241896SHiroki Sato struct ipv6_mreq mreq; 71537241896SHiroki Sato 71637241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 71737241896SHiroki Sato 71837241896SHiroki Sato if (mif == NULL) 71937241896SHiroki Sato return (1); 72037241896SHiroki Sato /* 72137241896SHiroki Sato * When attending router renumbering, join all-routers site-local 72237241896SHiroki Sato * multicast group. 72337241896SHiroki Sato */ 72437241896SHiroki Sato /* XXX */ 72537241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 72637241896SHiroki Sato &sin6_sitelocal_allrouters.sin6_addr, 72737241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 72837241896SHiroki Sato if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) { 72937241896SHiroki Sato syslog(LOG_ERR, 73037241896SHiroki Sato "<%s> invalid interface: %s", 73137241896SHiroki Sato __func__, mif); 73237241896SHiroki Sato return (1); 73337241896SHiroki Sato } 73437241896SHiroki Sato 73537241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 73637241896SHiroki Sato &mreq, sizeof(mreq)) < 0) { 73737241896SHiroki Sato syslog(LOG_ERR, 73837241896SHiroki Sato "<%s> IPV6_JOIN_GROUP(site) on %s: %s", 73937241896SHiroki Sato __func__, mif, strerror(errno)); 74037241896SHiroki Sato return (1); 74137241896SHiroki Sato } 74237241896SHiroki Sato 74337241896SHiroki Sato syslog(LOG_DEBUG, 74437241896SHiroki Sato "<%s> %s: join site-local all-routers MC group", 74537241896SHiroki Sato __func__, mif); 74637241896SHiroki Sato 74737241896SHiroki Sato return (0); 7489a4365d0SYoshinobu Inoue } 749