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/if_var.h> 4237241896SHiroki Sato #include <net/ethernet.h> 4337241896SHiroki Sato #include <net/route.h> 449a4365d0SYoshinobu Inoue #include <netinet/in.h> 4537241896SHiroki Sato #include <netinet/in_var.h> 4637241896SHiroki Sato #include <netinet/ip6.h> 479a4365d0SYoshinobu Inoue #include <netinet/icmp6.h> 4837241896SHiroki Sato #include <netinet6/nd6.h> 499a4365d0SYoshinobu Inoue #include <unistd.h> 509a4365d0SYoshinobu Inoue #include <errno.h> 51db82af41SHiroki Sato #include <netdb.h> 529a4365d0SYoshinobu Inoue #include <stdlib.h> 539a4365d0SYoshinobu Inoue #include <string.h> 549a4365d0SYoshinobu Inoue #include <syslog.h> 5537241896SHiroki Sato 5637241896SHiroki Sato #include "pathnames.h" 579a4365d0SYoshinobu Inoue #include "rtadvd.h" 589a4365d0SYoshinobu Inoue #include "if.h" 599a4365d0SYoshinobu Inoue 609a4365d0SYoshinobu Inoue #define ROUNDUP(a, size) \ 619a4365d0SYoshinobu Inoue (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 629a4365d0SYoshinobu Inoue 63db82af41SHiroki Sato #define NEXT_SA(ap) \ 64db82af41SHiroki Sato (ap) = (struct sockaddr *)((caddr_t)(ap) + \ 65db82af41SHiroki Sato ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \ 669a4365d0SYoshinobu Inoue sizeof(u_long))) 679a4365d0SYoshinobu Inoue 6837241896SHiroki Sato struct sockaddr_in6 sin6_linklocal_allnodes = { 6937241896SHiroki Sato .sin6_len = sizeof(sin6_linklocal_allnodes), 7037241896SHiroki Sato .sin6_family = AF_INET6, 7137241896SHiroki Sato .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, 7237241896SHiroki Sato }; 739a4365d0SYoshinobu Inoue 7437241896SHiroki Sato struct sockaddr_in6 sin6_linklocal_allrouters = { 7537241896SHiroki Sato .sin6_len = sizeof(sin6_linklocal_allrouters), 7637241896SHiroki Sato .sin6_family = AF_INET6, 7737241896SHiroki Sato .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, 7837241896SHiroki Sato }; 7937241896SHiroki Sato 8037241896SHiroki Sato struct sockaddr_in6 sin6_sitelocal_allrouters = { 8137241896SHiroki Sato .sin6_len = sizeof(sin6_sitelocal_allrouters), 8237241896SHiroki Sato .sin6_family = AF_INET6, 8337241896SHiroki Sato .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT, 8437241896SHiroki Sato }; 8537241896SHiroki Sato 8637241896SHiroki Sato struct sockinfo sock = { .si_fd = -1, .si_name = NULL }; 8737241896SHiroki Sato struct sockinfo rtsock = { .si_fd = -1, .si_name = NULL }; 8837241896SHiroki Sato struct sockinfo ctrlsock = { .si_fd = -1, .si_name = _PATH_CTRL_SOCK }; 8937241896SHiroki Sato 9037241896SHiroki Sato char *mcastif; 9137241896SHiroki Sato 9237241896SHiroki Sato static void get_rtaddrs(int, struct sockaddr *, 9337241896SHiroki Sato struct sockaddr **); 9437241896SHiroki Sato static struct if_msghdr *get_next_msghdr(struct if_msghdr *, 9537241896SHiroki Sato struct if_msghdr *); 969a4365d0SYoshinobu Inoue 979a4365d0SYoshinobu Inoue static void 989a4365d0SYoshinobu Inoue get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 999a4365d0SYoshinobu Inoue { 1009a4365d0SYoshinobu Inoue int i; 1019a4365d0SYoshinobu Inoue 1029a4365d0SYoshinobu Inoue for (i = 0; i < RTAX_MAX; i++) { 1039a4365d0SYoshinobu Inoue if (addrs & (1 << i)) { 1049a4365d0SYoshinobu Inoue rti_info[i] = sa; 1059a4365d0SYoshinobu Inoue NEXT_SA(sa); 1069a4365d0SYoshinobu Inoue } 1079a4365d0SYoshinobu Inoue else 1089a4365d0SYoshinobu Inoue rti_info[i] = NULL; 1099a4365d0SYoshinobu Inoue } 1109a4365d0SYoshinobu Inoue } 1119a4365d0SYoshinobu Inoue 1129a4365d0SYoshinobu Inoue #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 1139a4365d0SYoshinobu Inoue int 1149a4365d0SYoshinobu Inoue lladdropt_length(struct sockaddr_dl *sdl) 1159a4365d0SYoshinobu Inoue { 1169a4365d0SYoshinobu Inoue switch (sdl->sdl_type) { 1179a4365d0SYoshinobu Inoue case IFT_ETHER: 1189a4365d0SYoshinobu Inoue return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 1199a4365d0SYoshinobu Inoue default: 1209a4365d0SYoshinobu Inoue return (0); 1219a4365d0SYoshinobu Inoue } 1229a4365d0SYoshinobu Inoue } 1239a4365d0SYoshinobu Inoue 1249a4365d0SYoshinobu Inoue void 1259a4365d0SYoshinobu Inoue lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 1269a4365d0SYoshinobu Inoue { 1279a4365d0SYoshinobu Inoue char *addr; 1289a4365d0SYoshinobu Inoue 1299a4365d0SYoshinobu Inoue ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 1309a4365d0SYoshinobu Inoue 1319a4365d0SYoshinobu Inoue switch (sdl->sdl_type) { 1329a4365d0SYoshinobu Inoue case IFT_ETHER: 1339a4365d0SYoshinobu Inoue ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 1349a4365d0SYoshinobu Inoue addr = (char *)(ndopt + 1); 1359a4365d0SYoshinobu Inoue memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 1369a4365d0SYoshinobu Inoue break; 1379a4365d0SYoshinobu Inoue default: 138fa19f9beSHajimu UMEMOTO syslog(LOG_ERR, "<%s> unsupported link type(%d)", 1391533bed0SHajimu UMEMOTO __func__, sdl->sdl_type); 1409a4365d0SYoshinobu Inoue exit(1); 1419a4365d0SYoshinobu Inoue } 1429a4365d0SYoshinobu Inoue 1439a4365d0SYoshinobu Inoue return; 1449a4365d0SYoshinobu Inoue } 1459a4365d0SYoshinobu Inoue 1469a4365d0SYoshinobu Inoue int 147db82af41SHiroki Sato rtbuf_len(void) 1489a4365d0SYoshinobu Inoue { 1499a4365d0SYoshinobu Inoue size_t len; 1509a4365d0SYoshinobu Inoue int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; 1519a4365d0SYoshinobu Inoue 1529a4365d0SYoshinobu Inoue if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 1539a4365d0SYoshinobu Inoue return (-1); 1549a4365d0SYoshinobu Inoue 1559a4365d0SYoshinobu Inoue return (len); 1569a4365d0SYoshinobu Inoue } 1579a4365d0SYoshinobu Inoue 1589a4365d0SYoshinobu Inoue #define FILTER_MATCH(type, filter) ((0x1 << type) & filter) 1599a4365d0SYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)(s)) 1609a4365d0SYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)(s)) 1619a4365d0SYoshinobu Inoue char * 1629a4365d0SYoshinobu Inoue get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) 1639a4365d0SYoshinobu Inoue { 1649a4365d0SYoshinobu Inoue struct rt_msghdr *rtm; 1659a4365d0SYoshinobu Inoue struct ifa_msghdr *ifam; 1669a4365d0SYoshinobu Inoue struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; 1679a4365d0SYoshinobu Inoue 1689a4365d0SYoshinobu Inoue *lenp = 0; 1699a4365d0SYoshinobu Inoue for (rtm = (struct rt_msghdr *)buf; 1709a4365d0SYoshinobu Inoue rtm < (struct rt_msghdr *)lim; 1719a4365d0SYoshinobu Inoue rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { 1729a4365d0SYoshinobu Inoue /* just for safety */ 1739a4365d0SYoshinobu Inoue if (!rtm->rtm_msglen) { 1749a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " 1751533bed0SHajimu UMEMOTO "(buf=%p lim=%p rtm=%p)", __func__, 1769a4365d0SYoshinobu Inoue buf, lim, rtm); 1779a4365d0SYoshinobu Inoue break; 1789a4365d0SYoshinobu Inoue } 179db82af41SHiroki Sato if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { 180db82af41SHiroki Sato syslog(LOG_WARNING, 181db82af41SHiroki Sato "<%s> routing message version mismatch " 182db82af41SHiroki Sato "(buf=%p lim=%p rtm=%p)", __func__, 183db82af41SHiroki Sato buf, lim, rtm); 1849a4365d0SYoshinobu Inoue continue; 1859a4365d0SYoshinobu Inoue } 1869a4365d0SYoshinobu Inoue 187db82af41SHiroki Sato if (FILTER_MATCH(rtm->rtm_type, filter) == 0) 188db82af41SHiroki Sato continue; 189db82af41SHiroki Sato 1909a4365d0SYoshinobu Inoue switch (rtm->rtm_type) { 1919a4365d0SYoshinobu Inoue case RTM_GET: 1929a4365d0SYoshinobu Inoue case RTM_ADD: 1939a4365d0SYoshinobu Inoue case RTM_DELETE: 1949a4365d0SYoshinobu Inoue /* address related checks */ 1959a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 1969a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 1979a4365d0SYoshinobu Inoue if ((dst = rti_info[RTAX_DST]) == NULL || 1989a4365d0SYoshinobu Inoue dst->sa_family != AF_INET6) 1999a4365d0SYoshinobu Inoue continue; 2009a4365d0SYoshinobu Inoue 2019a4365d0SYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || 2029a4365d0SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) 2039a4365d0SYoshinobu Inoue continue; 2049a4365d0SYoshinobu Inoue 2059a4365d0SYoshinobu Inoue if ((gw = rti_info[RTAX_GATEWAY]) == NULL || 2069a4365d0SYoshinobu Inoue gw->sa_family != AF_LINK) 2079a4365d0SYoshinobu Inoue continue; 2089a4365d0SYoshinobu Inoue if (ifindex && SDL(gw)->sdl_index != ifindex) 2099a4365d0SYoshinobu Inoue continue; 2109a4365d0SYoshinobu Inoue 2119a4365d0SYoshinobu Inoue if (rti_info[RTAX_NETMASK] == NULL) 2129a4365d0SYoshinobu Inoue continue; 2139a4365d0SYoshinobu Inoue 2149a4365d0SYoshinobu Inoue /* found */ 2159a4365d0SYoshinobu Inoue *lenp = rtm->rtm_msglen; 2169a4365d0SYoshinobu Inoue return (char *)rtm; 2179a4365d0SYoshinobu Inoue /* NOTREACHED */ 2189a4365d0SYoshinobu Inoue case RTM_NEWADDR: 2199a4365d0SYoshinobu Inoue case RTM_DELADDR: 2209a4365d0SYoshinobu Inoue ifam = (struct ifa_msghdr *)rtm; 2219a4365d0SYoshinobu Inoue 2229a4365d0SYoshinobu Inoue /* address related checks */ 2239a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(ifam + 1); 2249a4365d0SYoshinobu Inoue get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 2259a4365d0SYoshinobu Inoue if ((ifa = rti_info[RTAX_IFA]) == NULL || 2269a4365d0SYoshinobu Inoue (ifa->sa_family != AF_INET && 2279a4365d0SYoshinobu Inoue ifa->sa_family != AF_INET6)) 2289a4365d0SYoshinobu Inoue continue; 2299a4365d0SYoshinobu Inoue 2309a4365d0SYoshinobu Inoue if (ifa->sa_family == AF_INET6 && 2319a4365d0SYoshinobu Inoue (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || 2329a4365d0SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) 2339a4365d0SYoshinobu Inoue continue; 2349a4365d0SYoshinobu Inoue 2359a4365d0SYoshinobu Inoue if (ifindex && ifam->ifam_index != ifindex) 2369a4365d0SYoshinobu Inoue continue; 2379a4365d0SYoshinobu Inoue 2389a4365d0SYoshinobu Inoue /* found */ 2399a4365d0SYoshinobu Inoue *lenp = ifam->ifam_msglen; 2409a4365d0SYoshinobu Inoue return (char *)rtm; 2419a4365d0SYoshinobu Inoue /* NOTREACHED */ 2429a4365d0SYoshinobu Inoue case RTM_IFINFO: 243db82af41SHiroki Sato case RTM_IFANNOUNCE: 2449a4365d0SYoshinobu Inoue /* found */ 2459a4365d0SYoshinobu Inoue *lenp = rtm->rtm_msglen; 2469a4365d0SYoshinobu Inoue return (char *)rtm; 2479a4365d0SYoshinobu Inoue /* NOTREACHED */ 2489a4365d0SYoshinobu Inoue } 2499a4365d0SYoshinobu Inoue } 2509a4365d0SYoshinobu Inoue 251db82af41SHiroki Sato return ((char *)rtm); 2529a4365d0SYoshinobu Inoue } 25333841545SHajimu UMEMOTO #undef FILTER_MATCH 2549a4365d0SYoshinobu Inoue 2559a4365d0SYoshinobu Inoue struct in6_addr * 2569a4365d0SYoshinobu Inoue get_addr(char *buf) 2579a4365d0SYoshinobu Inoue { 2589a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2599a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 2609a4365d0SYoshinobu Inoue 2619a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2629a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2639a4365d0SYoshinobu Inoue 2649a4365d0SYoshinobu Inoue return (&SIN6(rti_info[RTAX_DST])->sin6_addr); 2659a4365d0SYoshinobu Inoue } 2669a4365d0SYoshinobu Inoue 2679a4365d0SYoshinobu Inoue int 2689a4365d0SYoshinobu Inoue get_rtm_ifindex(char *buf) 2699a4365d0SYoshinobu Inoue { 2709a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2719a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 2729a4365d0SYoshinobu Inoue 2739a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2749a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2759a4365d0SYoshinobu Inoue 2769a4365d0SYoshinobu Inoue return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); 2779a4365d0SYoshinobu Inoue } 2789a4365d0SYoshinobu Inoue 2799a4365d0SYoshinobu Inoue int 2809a4365d0SYoshinobu Inoue get_prefixlen(char *buf) 2819a4365d0SYoshinobu Inoue { 2829a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2839a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 28437241896SHiroki Sato char *p, *lim; 2859a4365d0SYoshinobu Inoue 2869a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2879a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2889a4365d0SYoshinobu Inoue sa = rti_info[RTAX_NETMASK]; 2899a4365d0SYoshinobu Inoue 29037241896SHiroki Sato p = (char *)(&SIN6(sa)->sin6_addr); 29137241896SHiroki Sato lim = (char *)sa + sa->sa_len; 2927c991abcSHajimu UMEMOTO return prefixlen(p, lim); 2937c991abcSHajimu UMEMOTO } 2947c991abcSHajimu UMEMOTO 2957c991abcSHajimu UMEMOTO int 29637241896SHiroki Sato prefixlen(unsigned char *p, unsigned char *lim) 2977c991abcSHajimu UMEMOTO { 2987c991abcSHajimu UMEMOTO int masklen; 2997c991abcSHajimu UMEMOTO 3009a4365d0SYoshinobu Inoue for (masklen = 0; p < lim; p++) { 3019a4365d0SYoshinobu Inoue switch (*p) { 3029a4365d0SYoshinobu Inoue case 0xff: 3039a4365d0SYoshinobu Inoue masklen += 8; 3049a4365d0SYoshinobu Inoue break; 3059a4365d0SYoshinobu Inoue case 0xfe: 3069a4365d0SYoshinobu Inoue masklen += 7; 3079a4365d0SYoshinobu Inoue break; 3089a4365d0SYoshinobu Inoue case 0xfc: 3099a4365d0SYoshinobu Inoue masklen += 6; 3109a4365d0SYoshinobu Inoue break; 3119a4365d0SYoshinobu Inoue case 0xf8: 3129a4365d0SYoshinobu Inoue masklen += 5; 3139a4365d0SYoshinobu Inoue break; 3149a4365d0SYoshinobu Inoue case 0xf0: 3159a4365d0SYoshinobu Inoue masklen += 4; 3169a4365d0SYoshinobu Inoue break; 3179a4365d0SYoshinobu Inoue case 0xe0: 3189a4365d0SYoshinobu Inoue masklen += 3; 3199a4365d0SYoshinobu Inoue break; 3209a4365d0SYoshinobu Inoue case 0xc0: 3219a4365d0SYoshinobu Inoue masklen += 2; 3229a4365d0SYoshinobu Inoue break; 3239a4365d0SYoshinobu Inoue case 0x80: 3249a4365d0SYoshinobu Inoue masklen += 1; 3259a4365d0SYoshinobu Inoue break; 3269a4365d0SYoshinobu Inoue case 0x00: 3279a4365d0SYoshinobu Inoue break; 3289a4365d0SYoshinobu Inoue default: 3299a4365d0SYoshinobu Inoue return (-1); 3309a4365d0SYoshinobu Inoue } 3319a4365d0SYoshinobu Inoue } 3329a4365d0SYoshinobu Inoue 3339a4365d0SYoshinobu Inoue return (masklen); 3349a4365d0SYoshinobu Inoue } 3359a4365d0SYoshinobu Inoue 33637241896SHiroki Sato struct ifinfo * 33737241896SHiroki Sato update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname) 3389a4365d0SYoshinobu Inoue { 33937241896SHiroki Sato struct ifinfo *ifi; 34037241896SHiroki Sato int ifindex; 3419a4365d0SYoshinobu Inoue 34237241896SHiroki Sato ifi = NULL; 34337241896SHiroki Sato ifindex = if_nametoindex(ifname); 34437241896SHiroki Sato TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 34537241896SHiroki Sato if (ifindex != 0) { 34637241896SHiroki Sato if (ifindex == ifi->ifi_ifindex) 34737241896SHiroki Sato break; 3489a4365d0SYoshinobu Inoue } else { 34937241896SHiroki Sato if (strncmp(ifname, ifi->ifi_ifname, 35037241896SHiroki Sato sizeof(ifi->ifi_ifname)) == 0) 35137241896SHiroki Sato break; 35237241896SHiroki Sato } 35337241896SHiroki Sato } 35437241896SHiroki Sato 35537241896SHiroki Sato if (ifi == NULL) { 35637241896SHiroki Sato /* A new ifinfo element is needed. */ 35737241896SHiroki Sato syslog(LOG_DEBUG, "<%s> new entry: %s", __func__, 35837241896SHiroki Sato ifname); 35937241896SHiroki Sato 36037241896SHiroki Sato ELM_MALLOC(ifi, exit(1)); 36137241896SHiroki Sato ifi->ifi_ifindex = 0; 36237241896SHiroki Sato strncpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)-1); 36337241896SHiroki Sato ifi->ifi_ifname[sizeof(ifi->ifi_ifname)-1] = '\0'; 36437241896SHiroki Sato ifi->ifi_rainfo = NULL; 36537241896SHiroki Sato ifi->ifi_state = IFI_STATE_UNCONFIGURED; 36637241896SHiroki Sato TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 36737241896SHiroki Sato } 36837241896SHiroki Sato 36937241896SHiroki Sato ifi->ifi_persist = 1; 37037241896SHiroki Sato 37137241896SHiroki Sato syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__, 37237241896SHiroki Sato ifi->ifi_ifname); 37337241896SHiroki Sato syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__, 37437241896SHiroki Sato ifi->ifi_ifname, ifi->ifi_state); 37537241896SHiroki Sato return (ifi); 37637241896SHiroki Sato } 37737241896SHiroki Sato 37837241896SHiroki Sato int 37937241896SHiroki Sato update_ifinfo_nd_flags(struct ifinfo *ifi) 38037241896SHiroki Sato { 38137241896SHiroki Sato struct in6_ndireq nd; 38237241896SHiroki Sato int s; 38337241896SHiroki Sato int error; 38437241896SHiroki Sato 38537241896SHiroki Sato if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 38637241896SHiroki Sato syslog(LOG_ERR, 38737241896SHiroki Sato "<%s> socket() failed.", __func__); 38837241896SHiroki Sato return (1); 38937241896SHiroki Sato } 39037241896SHiroki Sato /* ND flags */ 39137241896SHiroki Sato memset(&nd, 0, sizeof(nd)); 39237241896SHiroki Sato strncpy(nd.ifname, ifi->ifi_ifname, 39337241896SHiroki Sato sizeof(nd.ifname)); 39437241896SHiroki Sato error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd); 39537241896SHiroki Sato if (error) { 39637241896SHiroki Sato close(s); 397*42f725eeSHiroki Sato if (errno != EPFNOSUPPORT) 398*42f725eeSHiroki Sato syslog(LOG_ERR, "<%s> ioctl() failed.", __func__); 39937241896SHiroki Sato return (1); 40037241896SHiroki Sato } 40137241896SHiroki Sato ifi->ifi_nd_flags = nd.ndi.flags; 40237241896SHiroki Sato close(s); 40337241896SHiroki Sato 40437241896SHiroki Sato return (0); 40537241896SHiroki Sato } 40637241896SHiroki Sato 40737241896SHiroki Sato struct ifinfo * 40837241896SHiroki Sato update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) 40937241896SHiroki Sato { 41037241896SHiroki Sato struct if_msghdr *ifm; 41137241896SHiroki Sato struct ifinfo *ifi = NULL; 41237241896SHiroki Sato struct sockaddr *sa; 41337241896SHiroki Sato struct sockaddr *rti_info[RTAX_MAX]; 41437241896SHiroki Sato char *msg; 41537241896SHiroki Sato size_t len; 41637241896SHiroki Sato char *lim; 41737241896SHiroki Sato int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; 41837241896SHiroki Sato int error; 41937241896SHiroki Sato 42037241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 42137241896SHiroki Sato 42237241896SHiroki Sato if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) < 42337241896SHiroki Sato 0) { 42437241896SHiroki Sato syslog(LOG_ERR, 42537241896SHiroki Sato "<%s> sysctl: NET_RT_IFLIST size get failed", __func__); 4269a4365d0SYoshinobu Inoue exit(1); 4279a4365d0SYoshinobu Inoue } 42837241896SHiroki Sato if ((msg = malloc(len)) == NULL) { 42937241896SHiroki Sato syslog(LOG_ERR, "<%s> malloc failed", __func__); 43037241896SHiroki Sato exit(1); 43137241896SHiroki Sato } 43237241896SHiroki Sato if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) < 43337241896SHiroki Sato 0) { 43437241896SHiroki Sato syslog(LOG_ERR, 43537241896SHiroki Sato "<%s> sysctl: NET_RT_IFLIST get failed", __func__); 43637241896SHiroki Sato exit(1); 43737241896SHiroki Sato } 43837241896SHiroki Sato 43937241896SHiroki Sato lim = msg + len; 44037241896SHiroki Sato for (ifm = (struct if_msghdr *)msg; 44137241896SHiroki Sato ifm != NULL && ifm < (struct if_msghdr *)lim; 44237241896SHiroki Sato ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) { 44337241896SHiroki Sato int ifi_new; 44437241896SHiroki Sato 44537241896SHiroki Sato syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu", 44637241896SHiroki Sato __func__, ifm, lim, (char *)lim - (char *)ifm); 44737241896SHiroki Sato 44837241896SHiroki Sato if (ifm->ifm_version != RTM_VERSION) { 44937241896SHiroki Sato syslog(LOG_ERR, 45037241896SHiroki Sato "<%s> ifm_vesrion mismatch", __func__); 45137241896SHiroki Sato exit(1); 45237241896SHiroki Sato } 45337241896SHiroki Sato if (ifm->ifm_msglen == 0) { 45437241896SHiroki Sato syslog(LOG_WARNING, 45537241896SHiroki Sato "<%s> ifm_msglen is 0", __func__); 45637241896SHiroki Sato free(msg); 45737241896SHiroki Sato return (NULL); 45837241896SHiroki Sato } 45937241896SHiroki Sato 46037241896SHiroki Sato ifi_new = 0; 46137241896SHiroki Sato if (ifm->ifm_type == RTM_IFINFO) { 46237241896SHiroki Sato struct ifreq ifr; 46337241896SHiroki Sato int s; 46437241896SHiroki Sato char ifname[IFNAMSIZ]; 46537241896SHiroki Sato 46637241896SHiroki Sato syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. " 46737241896SHiroki Sato "ifm_index = %d, ifindex = %d", 46837241896SHiroki Sato __func__, ifm->ifm_index, ifindex); 46937241896SHiroki Sato 47037241896SHiroki Sato /* when ifindex is specified */ 47137241896SHiroki Sato if (ifindex != UPDATE_IFINFO_ALL && 47237241896SHiroki Sato ifindex != ifm->ifm_index) 47337241896SHiroki Sato continue; 47437241896SHiroki Sato 47537241896SHiroki Sato /* lookup an entry with the same ifindex */ 47637241896SHiroki Sato TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 47737241896SHiroki Sato if (ifm->ifm_index == ifi->ifi_ifindex) 47837241896SHiroki Sato break; 47937241896SHiroki Sato if_indextoname(ifm->ifm_index, ifname); 48037241896SHiroki Sato if (strncmp(ifname, ifi->ifi_ifname, 48137241896SHiroki Sato sizeof(ifname)) == 0) 48237241896SHiroki Sato break; 48337241896SHiroki Sato } 48437241896SHiroki Sato if (ifi == NULL) { 48537241896SHiroki Sato syslog(LOG_DEBUG, 48637241896SHiroki Sato "<%s> new entry for idx=%d", 48737241896SHiroki Sato __func__, ifm->ifm_index); 48837241896SHiroki Sato ELM_MALLOC(ifi, exit(1)); 48937241896SHiroki Sato ifi->ifi_rainfo = NULL; 49037241896SHiroki Sato ifi->ifi_state = IFI_STATE_UNCONFIGURED; 49137241896SHiroki Sato ifi->ifi_persist = 0; 49237241896SHiroki Sato ifi_new = 1; 49337241896SHiroki Sato } 49437241896SHiroki Sato /* ifindex */ 49537241896SHiroki Sato ifi->ifi_ifindex = ifm->ifm_index; 49637241896SHiroki Sato 49737241896SHiroki Sato /* ifname */ 49837241896SHiroki Sato if_indextoname(ifm->ifm_index, ifi->ifi_ifname); 49937241896SHiroki Sato if (ifi->ifi_ifname == NULL) { 50037241896SHiroki Sato syslog(LOG_WARNING, 50137241896SHiroki Sato "<%s> ifname not found (idx=%d)", 50237241896SHiroki Sato __func__, ifm->ifm_index); 50337241896SHiroki Sato if (ifi_new) 50437241896SHiroki Sato free(ifi); 50537241896SHiroki Sato continue; 50637241896SHiroki Sato } 50737241896SHiroki Sato 50837241896SHiroki Sato if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 50937241896SHiroki Sato syslog(LOG_ERR, 51037241896SHiroki Sato "<%s> socket() failed.", __func__); 51137241896SHiroki Sato if (ifi_new) 51237241896SHiroki Sato free(ifi); 51337241896SHiroki Sato continue; 51437241896SHiroki Sato } 51537241896SHiroki Sato 51637241896SHiroki Sato /* MTU */ 51737241896SHiroki Sato ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu; 51837241896SHiroki Sato if (ifi->ifi_phymtu == 0) { 51937241896SHiroki Sato memset(&ifr, 0, sizeof(ifr)); 52037241896SHiroki Sato ifr.ifr_addr.sa_family = AF_INET6; 52137241896SHiroki Sato strncpy(ifr.ifr_name, ifi->ifi_ifname, 52237241896SHiroki Sato sizeof(ifr.ifr_name)); 52337241896SHiroki Sato error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr); 52437241896SHiroki Sato if (error) { 52537241896SHiroki Sato close(s); 52637241896SHiroki Sato syslog(LOG_ERR, 52737241896SHiroki Sato "<%s> ioctl() failed.", 52837241896SHiroki Sato __func__); 52937241896SHiroki Sato if (ifi_new) 53037241896SHiroki Sato free(ifi); 53137241896SHiroki Sato continue; 53237241896SHiroki Sato } 53337241896SHiroki Sato ifi->ifi_phymtu = ifr.ifr_mtu; 53437241896SHiroki Sato if (ifi->ifi_phymtu == 0) { 53537241896SHiroki Sato syslog(LOG_WARNING, 53637241896SHiroki Sato "<%s> no interface mtu info" 53737241896SHiroki Sato " on %s. %d will be used.", 53837241896SHiroki Sato __func__, ifi->ifi_ifname, 53937241896SHiroki Sato IPV6_MMTU); 54037241896SHiroki Sato ifi->ifi_phymtu = IPV6_MMTU; 54137241896SHiroki Sato } 54237241896SHiroki Sato } 54337241896SHiroki Sato close(s); 54437241896SHiroki Sato 54537241896SHiroki Sato /* ND flags */ 54637241896SHiroki Sato error = update_ifinfo_nd_flags(ifi); 54737241896SHiroki Sato if (error) { 54837241896SHiroki Sato if (ifi_new) 54937241896SHiroki Sato free(ifi); 55037241896SHiroki Sato continue; 55137241896SHiroki Sato } 55237241896SHiroki Sato 55337241896SHiroki Sato /* SDL */ 55437241896SHiroki Sato sa = (struct sockaddr *)(ifm + 1); 55537241896SHiroki Sato get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 55637241896SHiroki Sato if ((sa = rti_info[RTAX_IFP]) != NULL) { 55737241896SHiroki Sato if (sa->sa_family == AF_LINK) { 55837241896SHiroki Sato memcpy(&ifi->ifi_sdl, 55937241896SHiroki Sato (struct sockaddr_dl *)sa, 56037241896SHiroki Sato sizeof(ifi->ifi_sdl)); 56137241896SHiroki Sato } 56237241896SHiroki Sato } else 56337241896SHiroki Sato memset(&ifi->ifi_sdl, 0, 56437241896SHiroki Sato sizeof(ifi->ifi_sdl)); 56537241896SHiroki Sato 56637241896SHiroki Sato /* flags */ 56737241896SHiroki Sato ifi->ifi_flags = ifm->ifm_flags; 56837241896SHiroki Sato 56937241896SHiroki Sato /* type */ 57037241896SHiroki Sato ifi->ifi_type = ifm->ifm_type; 57137241896SHiroki Sato } else { 57237241896SHiroki Sato syslog(LOG_ERR, 57337241896SHiroki Sato "out of sync parsing NET_RT_IFLIST\n" 57437241896SHiroki Sato "expected %d, got %d\n msglen = %d\n", 57537241896SHiroki Sato RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen); 57637241896SHiroki Sato exit(1); 57737241896SHiroki Sato } 57837241896SHiroki Sato 57937241896SHiroki Sato if (ifi_new) { 58037241896SHiroki Sato syslog(LOG_DEBUG, 58137241896SHiroki Sato "<%s> adding %s(idx=%d) to ifilist", 58237241896SHiroki Sato __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 58337241896SHiroki Sato TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 58437241896SHiroki Sato } 58537241896SHiroki Sato } 58637241896SHiroki Sato free(msg); 58737241896SHiroki Sato 58837241896SHiroki Sato if (mcastif != NULL) { 58937241896SHiroki Sato error = sock_mc_rr_update(&sock, mcastif); 59037241896SHiroki Sato if (error) 59137241896SHiroki Sato exit(1); 59237241896SHiroki Sato } 59337241896SHiroki Sato 59437241896SHiroki Sato return (ifi); 59537241896SHiroki Sato } 59637241896SHiroki Sato 59737241896SHiroki Sato static struct if_msghdr * 59837241896SHiroki Sato get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim) 59937241896SHiroki Sato { 60037241896SHiroki Sato struct ifa_msghdr *ifam; 60137241896SHiroki Sato 60237241896SHiroki Sato for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen); 6039a4365d0SYoshinobu Inoue ifam < (struct ifa_msghdr *)lim; 60437241896SHiroki Sato ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) { 6059a4365d0SYoshinobu Inoue if (!ifam->ifam_msglen) { 60637241896SHiroki Sato syslog(LOG_WARNING, 60737241896SHiroki Sato "<%s> ifa_msglen is 0", __func__); 60837241896SHiroki Sato return (NULL); 6099a4365d0SYoshinobu Inoue } 6109a4365d0SYoshinobu Inoue if (ifam->ifam_type != RTM_NEWADDR) 6119a4365d0SYoshinobu Inoue break; 6129a4365d0SYoshinobu Inoue } 61337241896SHiroki Sato 61437241896SHiroki Sato return ((struct if_msghdr *)ifam); 6159a4365d0SYoshinobu Inoue } 6169a4365d0SYoshinobu Inoue 61737241896SHiroki Sato int 61837241896SHiroki Sato getinet6sysctl(int code) 6199a4365d0SYoshinobu Inoue { 62037241896SHiroki Sato int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 62137241896SHiroki Sato int value; 62237241896SHiroki Sato size_t size; 623db82af41SHiroki Sato 62437241896SHiroki Sato mib[3] = code; 62537241896SHiroki Sato size = sizeof(value); 62637241896SHiroki Sato if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 62737241896SHiroki Sato < 0) { 62837241896SHiroki Sato syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 62937241896SHiroki Sato __func__, code, 63037241896SHiroki Sato strerror(errno)); 63137241896SHiroki Sato return (-1); 6329a4365d0SYoshinobu Inoue } 63337241896SHiroki Sato else 63437241896SHiroki Sato return (value); 63537241896SHiroki Sato } 6369a4365d0SYoshinobu Inoue 63737241896SHiroki Sato 63837241896SHiroki Sato int 63937241896SHiroki Sato sock_mc_join(struct sockinfo *s, int ifindex) 64037241896SHiroki Sato { 64137241896SHiroki Sato struct ipv6_mreq mreq; 64237241896SHiroki Sato char ifname[IFNAMSIZ]; 64337241896SHiroki Sato 64437241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 64537241896SHiroki Sato 64637241896SHiroki Sato if (ifindex == 0) 64737241896SHiroki Sato return (1); 64837241896SHiroki Sato 64937241896SHiroki Sato /* 65037241896SHiroki Sato * join all routers multicast address on each advertising 65137241896SHiroki Sato * interface. 65237241896SHiroki Sato */ 65337241896SHiroki Sato memset(&mreq, 0, sizeof(mreq)); 65437241896SHiroki Sato /* XXX */ 65537241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 65637241896SHiroki Sato &sin6_linklocal_allrouters.sin6_addr, 65737241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 65837241896SHiroki Sato 65937241896SHiroki Sato mreq.ipv6mr_interface = ifindex; 66037241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 66137241896SHiroki Sato sizeof(mreq)) < 0) { 66237241896SHiroki Sato syslog(LOG_ERR, 66337241896SHiroki Sato "<%s> IPV6_JOIN_GROUP(link) on %s: %s", 66437241896SHiroki Sato __func__, if_indextoname(ifindex, ifname), 66537241896SHiroki Sato strerror(errno)); 66637241896SHiroki Sato return (1); 66737241896SHiroki Sato } 66837241896SHiroki Sato syslog(LOG_DEBUG, 66937241896SHiroki Sato "<%s> %s: join link-local all-routers MC group", 67037241896SHiroki Sato __func__, if_indextoname(ifindex, ifname)); 67137241896SHiroki Sato 67237241896SHiroki Sato return (0); 67337241896SHiroki Sato } 67437241896SHiroki Sato 67537241896SHiroki Sato int 67637241896SHiroki Sato sock_mc_leave(struct sockinfo *s, int ifindex) 67737241896SHiroki Sato { 67837241896SHiroki Sato struct ipv6_mreq mreq; 67937241896SHiroki Sato char ifname[IFNAMSIZ]; 68037241896SHiroki Sato 68137241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 68237241896SHiroki Sato 68337241896SHiroki Sato if (ifindex == 0) 68437241896SHiroki Sato return (1); 68537241896SHiroki Sato 68637241896SHiroki Sato /* 68737241896SHiroki Sato * join all routers multicast address on each advertising 68837241896SHiroki Sato * interface. 68937241896SHiroki Sato */ 69037241896SHiroki Sato 69137241896SHiroki Sato memset(&mreq, 0, sizeof(mreq)); 69237241896SHiroki Sato /* XXX */ 69337241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 69437241896SHiroki Sato &sin6_linklocal_allrouters.sin6_addr, 69537241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 69637241896SHiroki Sato 69737241896SHiroki Sato mreq.ipv6mr_interface = ifindex; 69837241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, 69937241896SHiroki Sato sizeof(mreq)) < 0) { 70037241896SHiroki Sato syslog(LOG_ERR, 70137241896SHiroki Sato "<%s> IPV6_JOIN_LEAVE(link) on %s: %s", 70237241896SHiroki Sato __func__, if_indextoname(ifindex, ifname), 70337241896SHiroki Sato strerror(errno)); 70437241896SHiroki Sato return (1); 70537241896SHiroki Sato } 70637241896SHiroki Sato syslog(LOG_DEBUG, 70737241896SHiroki Sato "<%s> %s: leave link-local all-routers MC group", 70837241896SHiroki Sato __func__, if_indextoname(ifindex, ifname)); 70937241896SHiroki Sato 71037241896SHiroki Sato return (0); 71137241896SHiroki Sato } 71237241896SHiroki Sato 71337241896SHiroki Sato int 71437241896SHiroki Sato sock_mc_rr_update(struct sockinfo *s, char *mif) 71537241896SHiroki Sato { 71637241896SHiroki Sato struct ipv6_mreq mreq; 71737241896SHiroki Sato 71837241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 71937241896SHiroki Sato 72037241896SHiroki Sato if (mif == NULL) 72137241896SHiroki Sato return (1); 72237241896SHiroki Sato /* 72337241896SHiroki Sato * When attending router renumbering, join all-routers site-local 72437241896SHiroki Sato * multicast group. 72537241896SHiroki Sato */ 72637241896SHiroki Sato /* XXX */ 72737241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 72837241896SHiroki Sato &sin6_sitelocal_allrouters.sin6_addr, 72937241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 73037241896SHiroki Sato if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) { 73137241896SHiroki Sato syslog(LOG_ERR, 73237241896SHiroki Sato "<%s> invalid interface: %s", 73337241896SHiroki Sato __func__, mif); 73437241896SHiroki Sato return (1); 73537241896SHiroki Sato } 73637241896SHiroki Sato 73737241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 73837241896SHiroki Sato &mreq, sizeof(mreq)) < 0) { 73937241896SHiroki Sato syslog(LOG_ERR, 74037241896SHiroki Sato "<%s> IPV6_JOIN_GROUP(site) on %s: %s", 74137241896SHiroki Sato __func__, mif, strerror(errno)); 74237241896SHiroki Sato return (1); 74337241896SHiroki Sato } 74437241896SHiroki Sato 74537241896SHiroki Sato syslog(LOG_DEBUG, 74637241896SHiroki Sato "<%s> %s: join site-local all-routers MC group", 74737241896SHiroki Sato __func__, mif); 74837241896SHiroki Sato 74937241896SHiroki Sato return (0); 7509a4365d0SYoshinobu Inoue } 751