133841545SHajimu UMEMOTO /* $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $ */ 2b26e03e9SKris Kennaway 38a16b7a1SPedro F. Giffuni /*- 48a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 58a16b7a1SPedro F. Giffuni * 69a4365d0SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 737241896SHiroki Sato * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 89a4365d0SYoshinobu Inoue * All rights reserved. 99a4365d0SYoshinobu Inoue * 109a4365d0SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 119a4365d0SYoshinobu Inoue * modification, are permitted provided that the following conditions 129a4365d0SYoshinobu Inoue * are met: 139a4365d0SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 149a4365d0SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 159a4365d0SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 169a4365d0SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 179a4365d0SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 189a4365d0SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 199a4365d0SYoshinobu Inoue * may be used to endorse or promote products derived from this software 209a4365d0SYoshinobu Inoue * without specific prior written permission. 219a4365d0SYoshinobu Inoue * 229a4365d0SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 239a4365d0SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 249a4365d0SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 259a4365d0SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 269a4365d0SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 279a4365d0SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 289a4365d0SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 299a4365d0SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 309a4365d0SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 319a4365d0SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 329a4365d0SYoshinobu Inoue * SUCH DAMAGE. 339a4365d0SYoshinobu Inoue */ 349a4365d0SYoshinobu Inoue 359a4365d0SYoshinobu Inoue #include <sys/param.h> 369a4365d0SYoshinobu Inoue #include <sys/socket.h> 379a4365d0SYoshinobu Inoue #include <sys/sysctl.h> 389a4365d0SYoshinobu Inoue #include <sys/ioctl.h> 399a4365d0SYoshinobu Inoue #include <net/if.h> 409a4365d0SYoshinobu Inoue #include <net/if_dl.h> 4137241896SHiroki Sato #include <net/if_types.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: 118374d225eSHiroki Sato case IFT_L2VLAN: 119374d225eSHiroki Sato case IFT_BRIDGE: 1209a4365d0SYoshinobu Inoue return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 1219a4365d0SYoshinobu Inoue default: 1229a4365d0SYoshinobu Inoue return (0); 1239a4365d0SYoshinobu Inoue } 1249a4365d0SYoshinobu Inoue } 1259a4365d0SYoshinobu Inoue 1269a4365d0SYoshinobu Inoue void 1279a4365d0SYoshinobu Inoue lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 1289a4365d0SYoshinobu Inoue { 1299a4365d0SYoshinobu Inoue char *addr; 1309a4365d0SYoshinobu Inoue 1319a4365d0SYoshinobu Inoue ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 1329a4365d0SYoshinobu Inoue 1339a4365d0SYoshinobu Inoue switch (sdl->sdl_type) { 1349a4365d0SYoshinobu Inoue case IFT_ETHER: 135374d225eSHiroki Sato case IFT_L2VLAN: 136374d225eSHiroki Sato case IFT_BRIDGE: 1379a4365d0SYoshinobu Inoue ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 1389a4365d0SYoshinobu Inoue addr = (char *)(ndopt + 1); 1399a4365d0SYoshinobu Inoue memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 1409a4365d0SYoshinobu Inoue break; 1419a4365d0SYoshinobu Inoue default: 142fa19f9beSHajimu UMEMOTO syslog(LOG_ERR, "<%s> unsupported link type(%d)", 1431533bed0SHajimu UMEMOTO __func__, sdl->sdl_type); 1449a4365d0SYoshinobu Inoue exit(1); 1459a4365d0SYoshinobu Inoue } 1469a4365d0SYoshinobu Inoue } 1479a4365d0SYoshinobu Inoue 1489a4365d0SYoshinobu Inoue int 149db82af41SHiroki Sato rtbuf_len(void) 1509a4365d0SYoshinobu Inoue { 1519a4365d0SYoshinobu Inoue size_t len; 1529a4365d0SYoshinobu Inoue int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; 1539a4365d0SYoshinobu Inoue 1549a4365d0SYoshinobu Inoue if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 1559a4365d0SYoshinobu Inoue return (-1); 1569a4365d0SYoshinobu Inoue 1579a4365d0SYoshinobu Inoue return (len); 1589a4365d0SYoshinobu Inoue } 1599a4365d0SYoshinobu Inoue 1609a4365d0SYoshinobu Inoue #define FILTER_MATCH(type, filter) ((0x1 << type) & filter) 1619a4365d0SYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)(s)) 1629a4365d0SYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)(s)) 1639a4365d0SYoshinobu Inoue char * 1649a4365d0SYoshinobu Inoue get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) 1659a4365d0SYoshinobu Inoue { 1669a4365d0SYoshinobu Inoue struct rt_msghdr *rtm; 1679a4365d0SYoshinobu Inoue struct ifa_msghdr *ifam; 1689a4365d0SYoshinobu Inoue struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; 1699a4365d0SYoshinobu Inoue 1709a4365d0SYoshinobu Inoue *lenp = 0; 1719a4365d0SYoshinobu Inoue for (rtm = (struct rt_msghdr *)buf; 1729a4365d0SYoshinobu Inoue rtm < (struct rt_msghdr *)lim; 1739a4365d0SYoshinobu Inoue rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { 1749a4365d0SYoshinobu Inoue /* just for safety */ 1759a4365d0SYoshinobu Inoue if (!rtm->rtm_msglen) { 1769a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " 1771533bed0SHajimu UMEMOTO "(buf=%p lim=%p rtm=%p)", __func__, 1789a4365d0SYoshinobu Inoue buf, lim, rtm); 1799a4365d0SYoshinobu Inoue break; 1809a4365d0SYoshinobu Inoue } 181db82af41SHiroki Sato if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { 182db82af41SHiroki Sato syslog(LOG_WARNING, 183db82af41SHiroki Sato "<%s> routing message version mismatch " 184db82af41SHiroki Sato "(buf=%p lim=%p rtm=%p)", __func__, 185db82af41SHiroki Sato buf, lim, rtm); 1869a4365d0SYoshinobu Inoue continue; 1879a4365d0SYoshinobu Inoue } 1889a4365d0SYoshinobu Inoue 189db82af41SHiroki Sato if (FILTER_MATCH(rtm->rtm_type, filter) == 0) 190db82af41SHiroki Sato continue; 191db82af41SHiroki Sato 1929a4365d0SYoshinobu Inoue switch (rtm->rtm_type) { 1939a4365d0SYoshinobu Inoue case RTM_GET: 1949a4365d0SYoshinobu Inoue case RTM_ADD: 1959a4365d0SYoshinobu Inoue case RTM_DELETE: 1969a4365d0SYoshinobu Inoue /* address related checks */ 1979a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 1989a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 1999a4365d0SYoshinobu Inoue if ((dst = rti_info[RTAX_DST]) == NULL || 2009a4365d0SYoshinobu Inoue dst->sa_family != AF_INET6) 2019a4365d0SYoshinobu Inoue continue; 2029a4365d0SYoshinobu Inoue 2039a4365d0SYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || 2049a4365d0SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) 2059a4365d0SYoshinobu Inoue continue; 2069a4365d0SYoshinobu Inoue 2079a4365d0SYoshinobu Inoue if ((gw = rti_info[RTAX_GATEWAY]) == NULL || 2089a4365d0SYoshinobu Inoue gw->sa_family != AF_LINK) 2099a4365d0SYoshinobu Inoue continue; 2109a4365d0SYoshinobu Inoue if (ifindex && SDL(gw)->sdl_index != ifindex) 2119a4365d0SYoshinobu Inoue continue; 2129a4365d0SYoshinobu Inoue 2139a4365d0SYoshinobu Inoue if (rti_info[RTAX_NETMASK] == NULL) 2149a4365d0SYoshinobu Inoue continue; 2159a4365d0SYoshinobu Inoue 2169a4365d0SYoshinobu Inoue /* found */ 2179a4365d0SYoshinobu Inoue *lenp = rtm->rtm_msglen; 2189a4365d0SYoshinobu Inoue return (char *)rtm; 2199a4365d0SYoshinobu Inoue /* NOTREACHED */ 2209a4365d0SYoshinobu Inoue case RTM_NEWADDR: 2219a4365d0SYoshinobu Inoue case RTM_DELADDR: 2229a4365d0SYoshinobu Inoue ifam = (struct ifa_msghdr *)rtm; 2239a4365d0SYoshinobu Inoue 2249a4365d0SYoshinobu Inoue /* address related checks */ 2259a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(ifam + 1); 2269a4365d0SYoshinobu Inoue get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 2279a4365d0SYoshinobu Inoue if ((ifa = rti_info[RTAX_IFA]) == NULL || 2289a4365d0SYoshinobu Inoue (ifa->sa_family != AF_INET && 2299a4365d0SYoshinobu Inoue ifa->sa_family != AF_INET6)) 2309a4365d0SYoshinobu Inoue continue; 2319a4365d0SYoshinobu Inoue 2329a4365d0SYoshinobu Inoue if (ifa->sa_family == AF_INET6 && 2339a4365d0SYoshinobu Inoue (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || 2349a4365d0SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) 2359a4365d0SYoshinobu Inoue continue; 2369a4365d0SYoshinobu Inoue 2379a4365d0SYoshinobu Inoue if (ifindex && ifam->ifam_index != ifindex) 2389a4365d0SYoshinobu Inoue continue; 2399a4365d0SYoshinobu Inoue 2409a4365d0SYoshinobu Inoue /* found */ 2419a4365d0SYoshinobu Inoue *lenp = ifam->ifam_msglen; 2429a4365d0SYoshinobu Inoue return (char *)rtm; 2439a4365d0SYoshinobu Inoue /* NOTREACHED */ 2449a4365d0SYoshinobu Inoue case RTM_IFINFO: 245db82af41SHiroki Sato case RTM_IFANNOUNCE: 2469a4365d0SYoshinobu Inoue /* found */ 2479a4365d0SYoshinobu Inoue *lenp = rtm->rtm_msglen; 2489a4365d0SYoshinobu Inoue return (char *)rtm; 2499a4365d0SYoshinobu Inoue /* NOTREACHED */ 2509a4365d0SYoshinobu Inoue } 2519a4365d0SYoshinobu Inoue } 2529a4365d0SYoshinobu Inoue 253db82af41SHiroki Sato return ((char *)rtm); 2549a4365d0SYoshinobu Inoue } 25533841545SHajimu UMEMOTO #undef FILTER_MATCH 2569a4365d0SYoshinobu Inoue 2579a4365d0SYoshinobu Inoue struct in6_addr * 2589a4365d0SYoshinobu Inoue get_addr(char *buf) 2599a4365d0SYoshinobu Inoue { 2609a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2619a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 2629a4365d0SYoshinobu Inoue 2639a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2649a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2659a4365d0SYoshinobu Inoue 2669a4365d0SYoshinobu Inoue return (&SIN6(rti_info[RTAX_DST])->sin6_addr); 2679a4365d0SYoshinobu Inoue } 2689a4365d0SYoshinobu Inoue 2699a4365d0SYoshinobu Inoue int 2709a4365d0SYoshinobu Inoue get_rtm_ifindex(char *buf) 2719a4365d0SYoshinobu Inoue { 2729a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2739a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 2749a4365d0SYoshinobu Inoue 2759a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2769a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2779a4365d0SYoshinobu Inoue 2789a4365d0SYoshinobu Inoue return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); 2799a4365d0SYoshinobu Inoue } 2809a4365d0SYoshinobu Inoue 2819a4365d0SYoshinobu Inoue int 2829a4365d0SYoshinobu Inoue get_prefixlen(char *buf) 2839a4365d0SYoshinobu Inoue { 2849a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 2859a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 28637241896SHiroki Sato char *p, *lim; 2879a4365d0SYoshinobu Inoue 2889a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 2899a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 2909a4365d0SYoshinobu Inoue sa = rti_info[RTAX_NETMASK]; 2919a4365d0SYoshinobu Inoue 29237241896SHiroki Sato p = (char *)(&SIN6(sa)->sin6_addr); 29337241896SHiroki Sato lim = (char *)sa + sa->sa_len; 2947c991abcSHajimu UMEMOTO return prefixlen(p, lim); 2957c991abcSHajimu UMEMOTO } 2967c991abcSHajimu UMEMOTO 2977c991abcSHajimu UMEMOTO int 29837241896SHiroki Sato prefixlen(unsigned char *p, unsigned char *lim) 2997c991abcSHajimu UMEMOTO { 3007c991abcSHajimu UMEMOTO int masklen; 3017c991abcSHajimu UMEMOTO 3029a4365d0SYoshinobu Inoue for (masklen = 0; p < lim; p++) { 3039a4365d0SYoshinobu Inoue switch (*p) { 3049a4365d0SYoshinobu Inoue case 0xff: 3059a4365d0SYoshinobu Inoue masklen += 8; 3069a4365d0SYoshinobu Inoue break; 3079a4365d0SYoshinobu Inoue case 0xfe: 3089a4365d0SYoshinobu Inoue masklen += 7; 3099a4365d0SYoshinobu Inoue break; 3109a4365d0SYoshinobu Inoue case 0xfc: 3119a4365d0SYoshinobu Inoue masklen += 6; 3129a4365d0SYoshinobu Inoue break; 3139a4365d0SYoshinobu Inoue case 0xf8: 3149a4365d0SYoshinobu Inoue masklen += 5; 3159a4365d0SYoshinobu Inoue break; 3169a4365d0SYoshinobu Inoue case 0xf0: 3179a4365d0SYoshinobu Inoue masklen += 4; 3189a4365d0SYoshinobu Inoue break; 3199a4365d0SYoshinobu Inoue case 0xe0: 3209a4365d0SYoshinobu Inoue masklen += 3; 3219a4365d0SYoshinobu Inoue break; 3229a4365d0SYoshinobu Inoue case 0xc0: 3239a4365d0SYoshinobu Inoue masklen += 2; 3249a4365d0SYoshinobu Inoue break; 3259a4365d0SYoshinobu Inoue case 0x80: 3269a4365d0SYoshinobu Inoue masklen += 1; 3279a4365d0SYoshinobu Inoue break; 3289a4365d0SYoshinobu Inoue case 0x00: 3299a4365d0SYoshinobu Inoue break; 3309a4365d0SYoshinobu Inoue default: 3319a4365d0SYoshinobu Inoue return (-1); 3329a4365d0SYoshinobu Inoue } 3339a4365d0SYoshinobu Inoue } 3349a4365d0SYoshinobu Inoue 3359a4365d0SYoshinobu Inoue return (masklen); 3369a4365d0SYoshinobu Inoue } 3379a4365d0SYoshinobu Inoue 33837241896SHiroki Sato struct ifinfo * 33937241896SHiroki Sato update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname) 3409a4365d0SYoshinobu Inoue { 34137241896SHiroki Sato struct ifinfo *ifi; 34237241896SHiroki Sato int ifindex; 3439a4365d0SYoshinobu Inoue 34437241896SHiroki Sato ifi = NULL; 34537241896SHiroki Sato ifindex = if_nametoindex(ifname); 34637241896SHiroki Sato TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 34737241896SHiroki Sato if (ifindex != 0) { 34837241896SHiroki Sato if (ifindex == ifi->ifi_ifindex) 34937241896SHiroki Sato break; 3509a4365d0SYoshinobu Inoue } else { 35137241896SHiroki Sato if (strncmp(ifname, ifi->ifi_ifname, 35237241896SHiroki Sato sizeof(ifi->ifi_ifname)) == 0) 35337241896SHiroki Sato break; 35437241896SHiroki Sato } 35537241896SHiroki Sato } 35637241896SHiroki Sato 35737241896SHiroki Sato if (ifi == NULL) { 35837241896SHiroki Sato /* A new ifinfo element is needed. */ 35937241896SHiroki Sato syslog(LOG_DEBUG, "<%s> new entry: %s", __func__, 36037241896SHiroki Sato ifname); 36137241896SHiroki Sato 36237241896SHiroki Sato ELM_MALLOC(ifi, exit(1)); 36337241896SHiroki Sato ifi->ifi_ifindex = 0; 3646bce9a10SXin LI strlcpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)); 36537241896SHiroki Sato ifi->ifi_rainfo = NULL; 36637241896SHiroki Sato ifi->ifi_state = IFI_STATE_UNCONFIGURED; 36737241896SHiroki Sato TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 36837241896SHiroki Sato } 36937241896SHiroki Sato 37037241896SHiroki Sato ifi->ifi_persist = 1; 37137241896SHiroki Sato 37237241896SHiroki Sato syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__, 37337241896SHiroki Sato ifi->ifi_ifname); 37437241896SHiroki Sato syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__, 37537241896SHiroki Sato ifi->ifi_ifname, ifi->ifi_state); 37637241896SHiroki Sato return (ifi); 37737241896SHiroki Sato } 37837241896SHiroki Sato 37937241896SHiroki Sato int 38037241896SHiroki Sato update_ifinfo_nd_flags(struct ifinfo *ifi) 38137241896SHiroki Sato { 38237241896SHiroki Sato struct in6_ndireq nd; 38337241896SHiroki Sato int s; 38437241896SHiroki Sato int error; 38537241896SHiroki Sato 38637241896SHiroki Sato if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 38737241896SHiroki Sato syslog(LOG_ERR, 38837241896SHiroki Sato "<%s> socket() failed.", __func__); 38937241896SHiroki Sato return (1); 39037241896SHiroki Sato } 39137241896SHiroki Sato /* ND flags */ 39237241896SHiroki Sato memset(&nd, 0, sizeof(nd)); 3938afa1c3dSDon Lewis strlcpy(nd.ifname, ifi->ifi_ifname, 39437241896SHiroki Sato sizeof(nd.ifname)); 39537241896SHiroki Sato error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd); 39637241896SHiroki Sato if (error) { 39737241896SHiroki Sato close(s); 39842f725eeSHiroki Sato if (errno != EPFNOSUPPORT) 39942f725eeSHiroki Sato syslog(LOG_ERR, "<%s> ioctl() failed.", __func__); 40037241896SHiroki Sato return (1); 40137241896SHiroki Sato } 40237241896SHiroki Sato ifi->ifi_nd_flags = nd.ndi.flags; 40337241896SHiroki Sato close(s); 40437241896SHiroki Sato 40537241896SHiroki Sato return (0); 40637241896SHiroki Sato } 40737241896SHiroki Sato 408180d54d0SMark Johnston #define MAX_SYSCTL_TRY 5 409180d54d0SMark Johnston 41037241896SHiroki Sato struct ifinfo * 41137241896SHiroki Sato update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) 41237241896SHiroki Sato { 41337241896SHiroki Sato struct if_msghdr *ifm; 41437241896SHiroki Sato struct ifinfo *ifi = NULL; 41537241896SHiroki Sato struct sockaddr *sa; 41637241896SHiroki Sato struct sockaddr *rti_info[RTAX_MAX]; 41737241896SHiroki Sato char *msg; 41837241896SHiroki Sato size_t len; 41937241896SHiroki Sato char *lim; 42037241896SHiroki Sato int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; 421180d54d0SMark Johnston int error, ntry; 42237241896SHiroki Sato 42337241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 42437241896SHiroki Sato 425180d54d0SMark Johnston ntry = 0; 426180d54d0SMark Johnston do { 427180d54d0SMark Johnston /* 428180d54d0SMark Johnston * We'll try to get addresses several times in case that 429180d54d0SMark Johnston * the number of addresses is unexpectedly increased during 430180d54d0SMark Johnston * the two sysctl calls. This should rarely happen. 431180d54d0SMark Johnston * Portability note: since FreeBSD does not add margin of 432180d54d0SMark Johnston * memory at the first sysctl, the possibility of failure on 433180d54d0SMark Johnston * the second sysctl call is a bit higher. 434180d54d0SMark Johnston */ 435180d54d0SMark Johnston 436180d54d0SMark Johnston if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) < 0) { 43737241896SHiroki Sato syslog(LOG_ERR, 438180d54d0SMark Johnston "<%s> sysctl: NET_RT_IFLIST size get failed", 439180d54d0SMark Johnston __func__); 4409a4365d0SYoshinobu Inoue exit(1); 4419a4365d0SYoshinobu Inoue } 44237241896SHiroki Sato if ((msg = malloc(len)) == NULL) { 44337241896SHiroki Sato syslog(LOG_ERR, "<%s> malloc failed", __func__); 44437241896SHiroki Sato exit(1); 44537241896SHiroki Sato } 446180d54d0SMark Johnston if (sysctl(mib, nitems(mib), msg, &len, NULL, 0) < 0) { 447180d54d0SMark Johnston if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { 448180d54d0SMark Johnston free(msg); 44937241896SHiroki Sato syslog(LOG_ERR, 450180d54d0SMark Johnston "<%s> sysctl: NET_RT_IFLIST get failed", 451180d54d0SMark Johnston __func__); 45237241896SHiroki Sato exit(1); 45337241896SHiroki Sato } 454180d54d0SMark Johnston free(msg); 455180d54d0SMark Johnston msg = NULL; 456180d54d0SMark Johnston } 457180d54d0SMark Johnston } while (msg == NULL); 45837241896SHiroki Sato 45937241896SHiroki Sato lim = msg + len; 46037241896SHiroki Sato for (ifm = (struct if_msghdr *)msg; 46137241896SHiroki Sato ifm != NULL && ifm < (struct if_msghdr *)lim; 46237241896SHiroki Sato ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) { 46337241896SHiroki Sato int ifi_new; 46437241896SHiroki Sato 46537241896SHiroki Sato syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu", 46637241896SHiroki Sato __func__, ifm, lim, (char *)lim - (char *)ifm); 46737241896SHiroki Sato 46837241896SHiroki Sato if (ifm->ifm_version != RTM_VERSION) { 46937241896SHiroki Sato syslog(LOG_ERR, 47037241896SHiroki Sato "<%s> ifm_vesrion mismatch", __func__); 47137241896SHiroki Sato exit(1); 47237241896SHiroki Sato } 47337241896SHiroki Sato if (ifm->ifm_msglen == 0) { 47437241896SHiroki Sato syslog(LOG_WARNING, 47537241896SHiroki Sato "<%s> ifm_msglen is 0", __func__); 47637241896SHiroki Sato free(msg); 47737241896SHiroki Sato return (NULL); 47837241896SHiroki Sato } 47937241896SHiroki Sato 48037241896SHiroki Sato ifi_new = 0; 48137241896SHiroki Sato if (ifm->ifm_type == RTM_IFINFO) { 48237241896SHiroki Sato struct ifreq ifr; 48337241896SHiroki Sato int s; 48437241896SHiroki Sato char ifname[IFNAMSIZ]; 48537241896SHiroki Sato 48637241896SHiroki Sato syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. " 48737241896SHiroki Sato "ifm_index = %d, ifindex = %d", 48837241896SHiroki Sato __func__, ifm->ifm_index, ifindex); 48937241896SHiroki Sato 49037241896SHiroki Sato /* when ifindex is specified */ 49137241896SHiroki Sato if (ifindex != UPDATE_IFINFO_ALL && 49237241896SHiroki Sato ifindex != ifm->ifm_index) 49337241896SHiroki Sato continue; 49437241896SHiroki Sato 4955ffb56f0SFabien Thomas /* ifname */ 4965ffb56f0SFabien Thomas if (if_indextoname(ifm->ifm_index, ifname) == NULL) { 4975ffb56f0SFabien Thomas syslog(LOG_WARNING, 4985ffb56f0SFabien Thomas "<%s> ifname not found (idx=%d)", 4995ffb56f0SFabien Thomas __func__, ifm->ifm_index); 5005ffb56f0SFabien Thomas continue; 5015ffb56f0SFabien Thomas } 5025ffb56f0SFabien Thomas 50337241896SHiroki Sato /* lookup an entry with the same ifindex */ 50437241896SHiroki Sato TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 50537241896SHiroki Sato if (ifm->ifm_index == ifi->ifi_ifindex) 50637241896SHiroki Sato break; 50737241896SHiroki Sato if (strncmp(ifname, ifi->ifi_ifname, 50837241896SHiroki Sato sizeof(ifname)) == 0) 50937241896SHiroki Sato break; 51037241896SHiroki Sato } 51137241896SHiroki Sato if (ifi == NULL) { 51237241896SHiroki Sato syslog(LOG_DEBUG, 51337241896SHiroki Sato "<%s> new entry for idx=%d", 51437241896SHiroki Sato __func__, ifm->ifm_index); 51537241896SHiroki Sato ELM_MALLOC(ifi, exit(1)); 51637241896SHiroki Sato ifi->ifi_rainfo = NULL; 51737241896SHiroki Sato ifi->ifi_state = IFI_STATE_UNCONFIGURED; 51837241896SHiroki Sato ifi->ifi_persist = 0; 51937241896SHiroki Sato ifi_new = 1; 52037241896SHiroki Sato } 52137241896SHiroki Sato /* ifindex */ 52237241896SHiroki Sato ifi->ifi_ifindex = ifm->ifm_index; 52337241896SHiroki Sato 52437241896SHiroki Sato /* ifname */ 5255ffb56f0SFabien Thomas strlcpy(ifi->ifi_ifname, ifname, IFNAMSIZ); 52637241896SHiroki Sato 52737241896SHiroki Sato if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 52837241896SHiroki Sato syslog(LOG_ERR, 52937241896SHiroki Sato "<%s> socket() failed.", __func__); 53037241896SHiroki Sato if (ifi_new) 53137241896SHiroki Sato free(ifi); 53237241896SHiroki Sato continue; 53337241896SHiroki Sato } 53437241896SHiroki Sato 53537241896SHiroki Sato /* MTU */ 53637241896SHiroki Sato ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu; 53737241896SHiroki Sato if (ifi->ifi_phymtu == 0) { 53837241896SHiroki Sato memset(&ifr, 0, sizeof(ifr)); 53937241896SHiroki Sato ifr.ifr_addr.sa_family = AF_INET6; 5408afa1c3dSDon Lewis strlcpy(ifr.ifr_name, ifi->ifi_ifname, 54137241896SHiroki Sato sizeof(ifr.ifr_name)); 54237241896SHiroki Sato error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr); 54337241896SHiroki Sato if (error) { 54437241896SHiroki Sato close(s); 54537241896SHiroki Sato syslog(LOG_ERR, 54637241896SHiroki Sato "<%s> ioctl() failed.", 54737241896SHiroki Sato __func__); 54837241896SHiroki Sato if (ifi_new) 54937241896SHiroki Sato free(ifi); 55037241896SHiroki Sato continue; 55137241896SHiroki Sato } 55237241896SHiroki Sato ifi->ifi_phymtu = ifr.ifr_mtu; 55337241896SHiroki Sato if (ifi->ifi_phymtu == 0) { 55437241896SHiroki Sato syslog(LOG_WARNING, 55537241896SHiroki Sato "<%s> no interface mtu info" 55637241896SHiroki Sato " on %s. %d will be used.", 55737241896SHiroki Sato __func__, ifi->ifi_ifname, 55837241896SHiroki Sato IPV6_MMTU); 55937241896SHiroki Sato ifi->ifi_phymtu = IPV6_MMTU; 56037241896SHiroki Sato } 56137241896SHiroki Sato } 56237241896SHiroki Sato close(s); 56337241896SHiroki Sato 56437241896SHiroki Sato /* ND flags */ 56537241896SHiroki Sato error = update_ifinfo_nd_flags(ifi); 56637241896SHiroki Sato if (error) { 56737241896SHiroki Sato if (ifi_new) 56837241896SHiroki Sato free(ifi); 56937241896SHiroki Sato continue; 57037241896SHiroki Sato } 57137241896SHiroki Sato 57237241896SHiroki Sato /* SDL */ 57337241896SHiroki Sato sa = (struct sockaddr *)(ifm + 1); 57437241896SHiroki Sato get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 57537241896SHiroki Sato if ((sa = rti_info[RTAX_IFP]) != NULL) { 57637241896SHiroki Sato if (sa->sa_family == AF_LINK) { 57737241896SHiroki Sato memcpy(&ifi->ifi_sdl, 57837241896SHiroki Sato (struct sockaddr_dl *)sa, 57937241896SHiroki Sato sizeof(ifi->ifi_sdl)); 58037241896SHiroki Sato } 58137241896SHiroki Sato } else 58237241896SHiroki Sato memset(&ifi->ifi_sdl, 0, 58337241896SHiroki Sato sizeof(ifi->ifi_sdl)); 58437241896SHiroki Sato 58537241896SHiroki Sato /* flags */ 58637241896SHiroki Sato ifi->ifi_flags = ifm->ifm_flags; 58737241896SHiroki Sato 58837241896SHiroki Sato /* type */ 58937241896SHiroki Sato ifi->ifi_type = ifm->ifm_type; 59037241896SHiroki Sato } else { 59137241896SHiroki Sato syslog(LOG_ERR, 59237241896SHiroki Sato "out of sync parsing NET_RT_IFLIST\n" 59337241896SHiroki Sato "expected %d, got %d\n msglen = %d\n", 59437241896SHiroki Sato RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen); 59537241896SHiroki Sato exit(1); 59637241896SHiroki Sato } 59737241896SHiroki Sato 59837241896SHiroki Sato if (ifi_new) { 59937241896SHiroki Sato syslog(LOG_DEBUG, 60037241896SHiroki Sato "<%s> adding %s(idx=%d) to ifilist", 60137241896SHiroki Sato __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 60237241896SHiroki Sato TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 60337241896SHiroki Sato } 60437241896SHiroki Sato } 60537241896SHiroki Sato free(msg); 60637241896SHiroki Sato 60737241896SHiroki Sato if (mcastif != NULL) { 60837241896SHiroki Sato error = sock_mc_rr_update(&sock, mcastif); 60937241896SHiroki Sato if (error) 61037241896SHiroki Sato exit(1); 61137241896SHiroki Sato } 61237241896SHiroki Sato 61337241896SHiroki Sato return (ifi); 61437241896SHiroki Sato } 61537241896SHiroki Sato 61637241896SHiroki Sato static struct if_msghdr * 61737241896SHiroki Sato get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim) 61837241896SHiroki Sato { 61937241896SHiroki Sato struct ifa_msghdr *ifam; 62037241896SHiroki Sato 62137241896SHiroki Sato for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen); 6229a4365d0SYoshinobu Inoue ifam < (struct ifa_msghdr *)lim; 62337241896SHiroki Sato ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) { 6249a4365d0SYoshinobu Inoue if (!ifam->ifam_msglen) { 62537241896SHiroki Sato syslog(LOG_WARNING, 62637241896SHiroki Sato "<%s> ifa_msglen is 0", __func__); 62737241896SHiroki Sato return (NULL); 6289a4365d0SYoshinobu Inoue } 6299a4365d0SYoshinobu Inoue if (ifam->ifam_type != RTM_NEWADDR) 6309a4365d0SYoshinobu Inoue break; 6319a4365d0SYoshinobu Inoue } 63237241896SHiroki Sato 63337241896SHiroki Sato return ((struct if_msghdr *)ifam); 6349a4365d0SYoshinobu Inoue } 6359a4365d0SYoshinobu Inoue 63637241896SHiroki Sato int 63737241896SHiroki Sato getinet6sysctl(int code) 6389a4365d0SYoshinobu Inoue { 63937241896SHiroki Sato int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 64037241896SHiroki Sato int value; 64137241896SHiroki Sato size_t size; 642db82af41SHiroki Sato 64337241896SHiroki Sato mib[3] = code; 64437241896SHiroki Sato size = sizeof(value); 645*93e96d6cSElyes Haouas if (sysctl(mib, nitems(mib), &value, &size, NULL, 0) 64637241896SHiroki Sato < 0) { 64737241896SHiroki Sato syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 64837241896SHiroki Sato __func__, code, 64937241896SHiroki Sato strerror(errno)); 65037241896SHiroki Sato return (-1); 6519a4365d0SYoshinobu Inoue } 65237241896SHiroki Sato else 65337241896SHiroki Sato return (value); 65437241896SHiroki Sato } 6559a4365d0SYoshinobu Inoue 65637241896SHiroki Sato 65737241896SHiroki Sato int 65837241896SHiroki Sato sock_mc_join(struct sockinfo *s, int ifindex) 65937241896SHiroki Sato { 66037241896SHiroki Sato struct ipv6_mreq mreq; 66137241896SHiroki Sato char ifname[IFNAMSIZ]; 66237241896SHiroki Sato 66337241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 66437241896SHiroki Sato 66537241896SHiroki Sato if (ifindex == 0) 66637241896SHiroki Sato return (1); 66737241896SHiroki Sato 66837241896SHiroki Sato /* 66937241896SHiroki Sato * join all routers multicast address on each advertising 67037241896SHiroki Sato * interface. 67137241896SHiroki Sato */ 67237241896SHiroki Sato memset(&mreq, 0, sizeof(mreq)); 67337241896SHiroki Sato /* XXX */ 67437241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 67537241896SHiroki Sato &sin6_linklocal_allrouters.sin6_addr, 67637241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 67737241896SHiroki Sato 67837241896SHiroki Sato mreq.ipv6mr_interface = ifindex; 67937241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 68037241896SHiroki Sato sizeof(mreq)) < 0) { 68137241896SHiroki Sato syslog(LOG_ERR, 68237241896SHiroki Sato "<%s> IPV6_JOIN_GROUP(link) on %s: %s", 68337241896SHiroki Sato __func__, if_indextoname(ifindex, ifname), 68437241896SHiroki Sato strerror(errno)); 68537241896SHiroki Sato return (1); 68637241896SHiroki Sato } 68737241896SHiroki Sato syslog(LOG_DEBUG, 68837241896SHiroki Sato "<%s> %s: join link-local all-routers MC group", 68937241896SHiroki Sato __func__, if_indextoname(ifindex, ifname)); 69037241896SHiroki Sato 69137241896SHiroki Sato return (0); 69237241896SHiroki Sato } 69337241896SHiroki Sato 69437241896SHiroki Sato int 69537241896SHiroki Sato sock_mc_leave(struct sockinfo *s, int ifindex) 69637241896SHiroki Sato { 69737241896SHiroki Sato struct ipv6_mreq mreq; 69837241896SHiroki Sato char ifname[IFNAMSIZ]; 69937241896SHiroki Sato 70037241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 70137241896SHiroki Sato 70237241896SHiroki Sato if (ifindex == 0) 70337241896SHiroki Sato return (1); 70437241896SHiroki Sato 70537241896SHiroki Sato /* 70637241896SHiroki Sato * join all routers multicast address on each advertising 70737241896SHiroki Sato * interface. 70837241896SHiroki Sato */ 70937241896SHiroki Sato 71037241896SHiroki Sato memset(&mreq, 0, sizeof(mreq)); 71137241896SHiroki Sato /* XXX */ 71237241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 71337241896SHiroki Sato &sin6_linklocal_allrouters.sin6_addr, 71437241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 71537241896SHiroki Sato 71637241896SHiroki Sato mreq.ipv6mr_interface = ifindex; 71737241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, 71837241896SHiroki Sato sizeof(mreq)) < 0) { 71937241896SHiroki Sato syslog(LOG_ERR, 72037241896SHiroki Sato "<%s> IPV6_JOIN_LEAVE(link) on %s: %s", 72137241896SHiroki Sato __func__, if_indextoname(ifindex, ifname), 72237241896SHiroki Sato strerror(errno)); 72337241896SHiroki Sato return (1); 72437241896SHiroki Sato } 72537241896SHiroki Sato syslog(LOG_DEBUG, 72637241896SHiroki Sato "<%s> %s: leave link-local all-routers MC group", 72737241896SHiroki Sato __func__, if_indextoname(ifindex, ifname)); 72837241896SHiroki Sato 72937241896SHiroki Sato return (0); 73037241896SHiroki Sato } 73137241896SHiroki Sato 73237241896SHiroki Sato int 73337241896SHiroki Sato sock_mc_rr_update(struct sockinfo *s, char *mif) 73437241896SHiroki Sato { 73537241896SHiroki Sato struct ipv6_mreq mreq; 73637241896SHiroki Sato 73737241896SHiroki Sato syslog(LOG_DEBUG, "<%s> enter", __func__); 73837241896SHiroki Sato 73937241896SHiroki Sato if (mif == NULL) 74037241896SHiroki Sato return (1); 74137241896SHiroki Sato /* 74237241896SHiroki Sato * When attending router renumbering, join all-routers site-local 74337241896SHiroki Sato * multicast group. 74437241896SHiroki Sato */ 74537241896SHiroki Sato /* XXX */ 74637241896SHiroki Sato memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 74737241896SHiroki Sato &sin6_sitelocal_allrouters.sin6_addr, 74837241896SHiroki Sato sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 74937241896SHiroki Sato if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) { 75037241896SHiroki Sato syslog(LOG_ERR, 75137241896SHiroki Sato "<%s> invalid interface: %s", 75237241896SHiroki Sato __func__, mif); 75337241896SHiroki Sato return (1); 75437241896SHiroki Sato } 75537241896SHiroki Sato 75637241896SHiroki Sato if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 75737241896SHiroki Sato &mreq, sizeof(mreq)) < 0) { 75837241896SHiroki Sato syslog(LOG_ERR, 75937241896SHiroki Sato "<%s> IPV6_JOIN_GROUP(site) on %s: %s", 76037241896SHiroki Sato __func__, mif, strerror(errno)); 76137241896SHiroki Sato return (1); 76237241896SHiroki Sato } 76337241896SHiroki Sato 76437241896SHiroki Sato syslog(LOG_DEBUG, 76537241896SHiroki Sato "<%s> %s: join site-local all-routers MC group", 76637241896SHiroki Sato __func__, mif); 76737241896SHiroki Sato 76837241896SHiroki Sato return (0); 7699a4365d0SYoshinobu Inoue } 770