171333Sitojun/* $FreeBSD: stable/10/usr.sbin/rtadvd/if.c 308717 2016-11-16 03:54:41Z hrs $ */ 278064Sume/* $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $ */ 362656Skris 455505Sshin/* 555505Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6224144Shrs * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 755505Sshin * All rights reserved. 8222732Shrs * 955505Sshin * Redistribution and use in source and binary forms, with or without 1055505Sshin * modification, are permitted provided that the following conditions 1155505Sshin * are met: 1255505Sshin * 1. Redistributions of source code must retain the above copyright 1355505Sshin * notice, this list of conditions and the following disclaimer. 1455505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1555505Sshin * notice, this list of conditions and the following disclaimer in the 1655505Sshin * documentation and/or other materials provided with the distribution. 1755505Sshin * 3. Neither the name of the project nor the names of its contributors 1855505Sshin * may be used to endorse or promote products derived from this software 1955505Sshin * without specific prior written permission. 20222732Shrs * 2155505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2255505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2555505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155505Sshin * SUCH DAMAGE. 3255505Sshin */ 3355505Sshin 3455505Sshin#include <sys/param.h> 3555505Sshin#include <sys/socket.h> 3655505Sshin#include <sys/sysctl.h> 3755505Sshin#include <sys/ioctl.h> 3855505Sshin#include <net/if.h> 39224144Shrs#include <net/if_dl.h> 4055505Sshin#include <net/if_types.h> 41224144Shrs#include <net/if_var.h> 42118787Sume#include <net/ethernet.h> 4355505Sshin#include <net/route.h> 4455505Sshin#include <netinet/in.h> 45224144Shrs#include <netinet/in_var.h> 46224144Shrs#include <netinet/ip6.h> 4755505Sshin#include <netinet/icmp6.h> 48224144Shrs#include <netinet6/nd6.h> 4955505Sshin#include <unistd.h> 5055505Sshin#include <errno.h> 51222732Shrs#include <netdb.h> 5255505Sshin#include <stdlib.h> 5355505Sshin#include <string.h> 5455505Sshin#include <syslog.h> 55224144Shrs 56224144Shrs#include "pathnames.h" 5755505Sshin#include "rtadvd.h" 5855505Sshin#include "if.h" 5955505Sshin 60222732Shrs#define ROUNDUP(a, size) \ 6155505Sshin (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 6255505Sshin 63222732Shrs#define NEXT_SA(ap) \ 64222732Shrs (ap) = (struct sockaddr *)((caddr_t)(ap) + \ 65222732Shrs ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \ 66222732Shrs sizeof(u_long))) 6755505Sshin 68224144Shrsstruct sockaddr_in6 sin6_linklocal_allnodes = { 69224144Shrs .sin6_len = sizeof(sin6_linklocal_allnodes), 70224144Shrs .sin6_family = AF_INET6, 71224144Shrs .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, 72224144Shrs}; 7355505Sshin 74224144Shrsstruct sockaddr_in6 sin6_linklocal_allrouters = { 75224144Shrs .sin6_len = sizeof(sin6_linklocal_allrouters), 76224144Shrs .sin6_family = AF_INET6, 77224144Shrs .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, 78224144Shrs}; 7955505Sshin 80224144Shrsstruct sockaddr_in6 sin6_sitelocal_allrouters = { 81224144Shrs .sin6_len = sizeof(sin6_sitelocal_allrouters), 82224144Shrs .sin6_family = AF_INET6, 83224144Shrs .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT, 84224144Shrs}; 85224144Shrs 86224144Shrsstruct sockinfo sock = { .si_fd = -1, .si_name = NULL }; 87224144Shrsstruct sockinfo rtsock = { .si_fd = -1, .si_name = NULL }; 88224144Shrsstruct sockinfo ctrlsock = { .si_fd = -1, .si_name = _PATH_CTRL_SOCK }; 89224144Shrs 90224144Shrschar *mcastif; 91224144Shrs 92224144Shrsstatic void get_rtaddrs(int, struct sockaddr *, 93224144Shrs struct sockaddr **); 94224144Shrsstatic struct if_msghdr *get_next_msghdr(struct if_msghdr *, 95224144Shrs struct if_msghdr *); 96224144Shrs 9755505Sshinstatic void 9855505Sshinget_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 9955505Sshin{ 10055505Sshin int i; 101222732Shrs 10255505Sshin for (i = 0; i < RTAX_MAX; i++) { 10355505Sshin if (addrs & (1 << i)) { 10455505Sshin rti_info[i] = sa; 10555505Sshin NEXT_SA(sa); 10655505Sshin } 10755505Sshin else 10855505Sshin rti_info[i] = NULL; 10955505Sshin } 11055505Sshin} 11155505Sshin 11262656Skris#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 11355505Sshinint 11455505Sshinlladdropt_length(struct sockaddr_dl *sdl) 11555505Sshin{ 116118664Sume switch (sdl->sdl_type) { 117118664Sume case IFT_ETHER: 118308717Shrs case IFT_L2VLAN: 119308717Shrs case IFT_BRIDGE: 120222732Shrs return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 121118664Sume default: 122222732Shrs return (0); 12355505Sshin } 12455505Sshin} 12555505Sshin 12655505Sshinvoid 12755505Sshinlladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 12855505Sshin{ 12955505Sshin char *addr; 13055505Sshin 13155505Sshin ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 13255505Sshin 133118664Sume switch (sdl->sdl_type) { 134118664Sume case IFT_ETHER: 135308717Shrs case IFT_L2VLAN: 136308717Shrs case IFT_BRIDGE: 137118664Sume ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 138118664Sume addr = (char *)(ndopt + 1); 139118664Sume memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 140118664Sume break; 141118664Sume default: 142118664Sume syslog(LOG_ERR, "<%s> unsupported link type(%d)", 143118664Sume __func__, sdl->sdl_type); 144118664Sume exit(1); 14555505Sshin } 14655505Sshin 14755505Sshin return; 14855505Sshin} 14955505Sshin 15055505Sshinint 151222732Shrsrtbuf_len(void) 15255505Sshin{ 15355505Sshin size_t len; 15455505Sshin int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; 15555505Sshin 15655505Sshin if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 157222732Shrs return (-1); 15855505Sshin 159222732Shrs return (len); 16055505Sshin} 16155505Sshin 16262656Skris#define FILTER_MATCH(type, filter) ((0x1 << type) & filter) 16362656Skris#define SIN6(s) ((struct sockaddr_in6 *)(s)) 16462656Skris#define SDL(s) ((struct sockaddr_dl *)(s)) 16555505Sshinchar * 16655505Sshinget_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) 16755505Sshin{ 16855505Sshin struct rt_msghdr *rtm; 16955505Sshin struct ifa_msghdr *ifam; 17055505Sshin struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; 17155505Sshin 17255505Sshin *lenp = 0; 17355505Sshin for (rtm = (struct rt_msghdr *)buf; 17455505Sshin rtm < (struct rt_msghdr *)lim; 17555505Sshin rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { 17655505Sshin /* just for safety */ 17755505Sshin if (!rtm->rtm_msglen) { 17855505Sshin syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " 179222732Shrs "(buf=%p lim=%p rtm=%p)", __func__, 180222732Shrs buf, lim, rtm); 18155505Sshin break; 18255505Sshin } 183222732Shrs if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { 184222732Shrs syslog(LOG_WARNING, 185222732Shrs "<%s> routing message version mismatch " 186222732Shrs "(buf=%p lim=%p rtm=%p)", __func__, 187222732Shrs buf, lim, rtm); 18855505Sshin continue; 18955505Sshin } 19055505Sshin 191222732Shrs if (FILTER_MATCH(rtm->rtm_type, filter) == 0) 192222732Shrs continue; 193222732Shrs 19455505Sshin switch (rtm->rtm_type) { 19555505Sshin case RTM_GET: 19655505Sshin case RTM_ADD: 19755505Sshin case RTM_DELETE: 19855505Sshin /* address related checks */ 19955505Sshin sa = (struct sockaddr *)(rtm + 1); 20055505Sshin get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 20155505Sshin if ((dst = rti_info[RTAX_DST]) == NULL || 20255505Sshin dst->sa_family != AF_INET6) 20355505Sshin continue; 20455505Sshin 20555505Sshin if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || 20655505Sshin IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) 20755505Sshin continue; 20855505Sshin 20955505Sshin if ((gw = rti_info[RTAX_GATEWAY]) == NULL || 21055505Sshin gw->sa_family != AF_LINK) 21155505Sshin continue; 21255505Sshin if (ifindex && SDL(gw)->sdl_index != ifindex) 21355505Sshin continue; 21455505Sshin 21555505Sshin if (rti_info[RTAX_NETMASK] == NULL) 21655505Sshin continue; 21755505Sshin 21855505Sshin /* found */ 21955505Sshin *lenp = rtm->rtm_msglen; 22055505Sshin return (char *)rtm; 22155505Sshin /* NOTREACHED */ 22255505Sshin case RTM_NEWADDR: 22355505Sshin case RTM_DELADDR: 22455505Sshin ifam = (struct ifa_msghdr *)rtm; 22555505Sshin 22655505Sshin /* address related checks */ 22755505Sshin sa = (struct sockaddr *)(ifam + 1); 22855505Sshin get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 22955505Sshin if ((ifa = rti_info[RTAX_IFA]) == NULL || 23055505Sshin (ifa->sa_family != AF_INET && 23155505Sshin ifa->sa_family != AF_INET6)) 23255505Sshin continue; 23355505Sshin 23455505Sshin if (ifa->sa_family == AF_INET6 && 23555505Sshin (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || 23655505Sshin IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) 23755505Sshin continue; 23855505Sshin 23955505Sshin if (ifindex && ifam->ifam_index != ifindex) 24055505Sshin continue; 24155505Sshin 24255505Sshin /* found */ 24355505Sshin *lenp = ifam->ifam_msglen; 24455505Sshin return (char *)rtm; 24555505Sshin /* NOTREACHED */ 24655505Sshin case RTM_IFINFO: 247222732Shrs case RTM_IFANNOUNCE: 24855505Sshin /* found */ 24955505Sshin *lenp = rtm->rtm_msglen; 25055505Sshin return (char *)rtm; 25155505Sshin /* NOTREACHED */ 25255505Sshin } 25355505Sshin } 25455505Sshin 255222732Shrs return ((char *)rtm); 25655505Sshin} 25778064Sume#undef FILTER_MATCH 25855505Sshin 25955505Sshinstruct in6_addr * 26055505Sshinget_addr(char *buf) 26155505Sshin{ 26255505Sshin struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 26355505Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 26455505Sshin 26555505Sshin sa = (struct sockaddr *)(rtm + 1); 26655505Sshin get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 26755505Sshin 268222732Shrs return (&SIN6(rti_info[RTAX_DST])->sin6_addr); 26955505Sshin} 27055505Sshin 27155505Sshinint 27255505Sshinget_rtm_ifindex(char *buf) 27355505Sshin{ 27455505Sshin struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 27555505Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 27655505Sshin 27755505Sshin sa = (struct sockaddr *)(rtm + 1); 27855505Sshin get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 27955505Sshin 280222732Shrs return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); 28155505Sshin} 28255505Sshin 28355505Sshinint 28455505Sshinget_prefixlen(char *buf) 28555505Sshin{ 28655505Sshin struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 28755505Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 288224144Shrs char *p, *lim; 289222732Shrs 29055505Sshin sa = (struct sockaddr *)(rtm + 1); 29155505Sshin get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 29255505Sshin sa = rti_info[RTAX_NETMASK]; 29355505Sshin 294224144Shrs p = (char *)(&SIN6(sa)->sin6_addr); 295224144Shrs lim = (char *)sa + sa->sa_len; 29667801Sume return prefixlen(p, lim); 29767801Sume} 29867801Sume 29967801Sumeint 300224144Shrsprefixlen(unsigned char *p, unsigned char *lim) 30167801Sume{ 30267801Sume int masklen; 30367801Sume 30455505Sshin for (masklen = 0; p < lim; p++) { 30555505Sshin switch (*p) { 30655505Sshin case 0xff: 30755505Sshin masklen += 8; 30855505Sshin break; 30955505Sshin case 0xfe: 31055505Sshin masklen += 7; 31155505Sshin break; 31255505Sshin case 0xfc: 31355505Sshin masklen += 6; 31455505Sshin break; 31555505Sshin case 0xf8: 31655505Sshin masklen += 5; 31755505Sshin break; 31855505Sshin case 0xf0: 31955505Sshin masklen += 4; 32055505Sshin break; 32155505Sshin case 0xe0: 32255505Sshin masklen += 3; 32355505Sshin break; 32455505Sshin case 0xc0: 32555505Sshin masklen += 2; 32655505Sshin break; 32755505Sshin case 0x80: 32855505Sshin masklen += 1; 32955505Sshin break; 33055505Sshin case 0x00: 33155505Sshin break; 33255505Sshin default: 333222732Shrs return (-1); 33455505Sshin } 33555505Sshin } 33655505Sshin 337222732Shrs return (masklen); 33855505Sshin} 33955505Sshin 340224144Shrsstruct ifinfo * 341224144Shrsupdate_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname) 34255505Sshin{ 343224144Shrs struct ifinfo *ifi; 344224144Shrs int ifindex; 34555505Sshin 346224144Shrs ifi = NULL; 347224144Shrs ifindex = if_nametoindex(ifname); 348224144Shrs TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 349224144Shrs if (ifindex != 0) { 350224144Shrs if (ifindex == ifi->ifi_ifindex) 351224144Shrs break; 352224144Shrs } else { 353224144Shrs if (strncmp(ifname, ifi->ifi_ifname, 354224144Shrs sizeof(ifi->ifi_ifname)) == 0) 355224144Shrs break; 356224144Shrs } 357224144Shrs } 35855505Sshin 359224144Shrs if (ifi == NULL) { 360224144Shrs /* A new ifinfo element is needed. */ 361224144Shrs syslog(LOG_DEBUG, "<%s> new entry: %s", __func__, 362224144Shrs ifname); 36355505Sshin 364224144Shrs ELM_MALLOC(ifi, exit(1)); 365224144Shrs ifi->ifi_ifindex = 0; 366290853Sdelphij strlcpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)); 367224144Shrs ifi->ifi_rainfo = NULL; 368224144Shrs ifi->ifi_state = IFI_STATE_UNCONFIGURED; 369224144Shrs TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 370224144Shrs } 371224144Shrs 372224144Shrs ifi->ifi_persist = 1; 373224144Shrs 374224144Shrs syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__, 375224144Shrs ifi->ifi_ifname); 376224144Shrs syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__, 377224144Shrs ifi->ifi_ifname, ifi->ifi_state); 378224144Shrs return (ifi); 37955505Sshin} 38055505Sshin 38155505Sshinint 382224144Shrsupdate_ifinfo_nd_flags(struct ifinfo *ifi) 38355505Sshin{ 384224144Shrs struct in6_ndireq nd; 385224144Shrs int s; 386224144Shrs int error; 38755505Sshin 388224144Shrs if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 389224144Shrs syslog(LOG_ERR, 390224144Shrs "<%s> socket() failed.", __func__); 391224144Shrs return (1); 392224144Shrs } 393224144Shrs /* ND flags */ 394224144Shrs memset(&nd, 0, sizeof(nd)); 395300281Struckman strlcpy(nd.ifname, ifi->ifi_ifname, 396224144Shrs sizeof(nd.ifname)); 397224144Shrs error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd); 398224144Shrs if (error) { 399224144Shrs close(s); 400255156Shrs if (errno != EPFNOSUPPORT) 401255156Shrs syslog(LOG_ERR, "<%s> ioctl() failed.", __func__); 402224144Shrs return (1); 403224144Shrs } 404224144Shrs ifi->ifi_nd_flags = nd.ndi.flags; 405224144Shrs close(s); 406224144Shrs 407224144Shrs return (0); 40855505Sshin} 40955505Sshin 410224144Shrsstruct ifinfo * 411224144Shrsupdate_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) 41255505Sshin{ 413224144Shrs struct if_msghdr *ifm; 414224144Shrs struct ifinfo *ifi = NULL; 415224144Shrs struct sockaddr *sa; 416224144Shrs struct sockaddr *rti_info[RTAX_MAX]; 417224144Shrs char *msg; 418224144Shrs size_t len; 419224144Shrs char *lim; 420224144Shrs int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; 421224144Shrs int error; 42255505Sshin 423224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 42455505Sshin 425224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) < 426224144Shrs 0) { 427224144Shrs syslog(LOG_ERR, 428224144Shrs "<%s> sysctl: NET_RT_IFLIST size get failed", __func__); 42955505Sshin exit(1); 43055505Sshin } 431224144Shrs if ((msg = malloc(len)) == NULL) { 432118660Sume syslog(LOG_ERR, "<%s> malloc failed", __func__); 43355505Sshin exit(1); 43455505Sshin } 435224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) < 436224144Shrs 0) { 437224144Shrs syslog(LOG_ERR, 438224144Shrs "<%s> sysctl: NET_RT_IFLIST get failed", __func__); 43955505Sshin exit(1); 44055505Sshin } 44155505Sshin 442224144Shrs lim = msg + len; 443224144Shrs for (ifm = (struct if_msghdr *)msg; 444224144Shrs ifm != NULL && ifm < (struct if_msghdr *)lim; 445224144Shrs ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) { 446224144Shrs int ifi_new; 44755505Sshin 448224144Shrs syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu", 449224144Shrs __func__, ifm, lim, (char *)lim - (char *)ifm); 45055505Sshin 451224144Shrs if (ifm->ifm_version != RTM_VERSION) { 452224144Shrs syslog(LOG_ERR, 453224144Shrs "<%s> ifm_vesrion mismatch", __func__); 454224144Shrs exit(1); 455224144Shrs } 45655505Sshin if (ifm->ifm_msglen == 0) { 457224144Shrs syslog(LOG_WARNING, 458224144Shrs "<%s> ifm_msglen is 0", __func__); 459224144Shrs free(msg); 460224144Shrs return (NULL); 46155505Sshin } 46255505Sshin 463224144Shrs ifi_new = 0; 46455505Sshin if (ifm->ifm_type == RTM_IFINFO) { 465224144Shrs struct ifreq ifr; 466224144Shrs int s; 467224144Shrs char ifname[IFNAMSIZ]; 468224144Shrs 469224144Shrs syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. " 470224144Shrs "ifm_index = %d, ifindex = %d", 471224144Shrs __func__, ifm->ifm_index, ifindex); 472224144Shrs 473224144Shrs /* when ifindex is specified */ 474224144Shrs if (ifindex != UPDATE_IFINFO_ALL && 475224144Shrs ifindex != ifm->ifm_index) 476224144Shrs continue; 477224144Shrs 478224144Shrs /* lookup an entry with the same ifindex */ 479224144Shrs TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 480224144Shrs if (ifm->ifm_index == ifi->ifi_ifindex) 481224144Shrs break; 482224144Shrs if_indextoname(ifm->ifm_index, ifname); 483224144Shrs if (strncmp(ifname, ifi->ifi_ifname, 484224144Shrs sizeof(ifname)) == 0) 485224144Shrs break; 486224144Shrs } 487224144Shrs if (ifi == NULL) { 488224144Shrs syslog(LOG_DEBUG, 489224144Shrs "<%s> new entry for idx=%d", 490224144Shrs __func__, ifm->ifm_index); 491224144Shrs ELM_MALLOC(ifi, exit(1)); 492224144Shrs ifi->ifi_rainfo = NULL; 493224144Shrs ifi->ifi_state = IFI_STATE_UNCONFIGURED; 494224144Shrs ifi->ifi_persist = 0; 495224144Shrs ifi_new = 1; 496224144Shrs } 497224144Shrs /* ifindex */ 498224144Shrs ifi->ifi_ifindex = ifm->ifm_index; 499224144Shrs 500224144Shrs /* ifname */ 501224144Shrs if_indextoname(ifm->ifm_index, ifi->ifi_ifname); 502224144Shrs if (ifi->ifi_ifname == NULL) { 503224144Shrs syslog(LOG_WARNING, 504224144Shrs "<%s> ifname not found (idx=%d)", 505224144Shrs __func__, ifm->ifm_index); 506224144Shrs if (ifi_new) 507224144Shrs free(ifi); 508224144Shrs continue; 509224144Shrs } 510224144Shrs 511224144Shrs if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 512224144Shrs syslog(LOG_ERR, 513224144Shrs "<%s> socket() failed.", __func__); 514224144Shrs if (ifi_new) 515224144Shrs free(ifi); 516224144Shrs continue; 517224144Shrs } 518224144Shrs 519224144Shrs /* MTU */ 520224144Shrs ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu; 521224144Shrs if (ifi->ifi_phymtu == 0) { 522224144Shrs memset(&ifr, 0, sizeof(ifr)); 523224144Shrs ifr.ifr_addr.sa_family = AF_INET6; 524300281Struckman strlcpy(ifr.ifr_name, ifi->ifi_ifname, 525224144Shrs sizeof(ifr.ifr_name)); 526224144Shrs error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr); 527224144Shrs if (error) { 528224144Shrs close(s); 529224144Shrs syslog(LOG_ERR, 530224144Shrs "<%s> ioctl() failed.", 531224144Shrs __func__); 532224144Shrs if (ifi_new) 533224144Shrs free(ifi); 534224144Shrs continue; 535224144Shrs } 536224144Shrs ifi->ifi_phymtu = ifr.ifr_mtu; 537224144Shrs if (ifi->ifi_phymtu == 0) { 538224144Shrs syslog(LOG_WARNING, 539224144Shrs "<%s> no interface mtu info" 540224144Shrs " on %s. %d will be used.", 541224144Shrs __func__, ifi->ifi_ifname, 542224144Shrs IPV6_MMTU); 543224144Shrs ifi->ifi_phymtu = IPV6_MMTU; 544224144Shrs } 545224144Shrs } 546224144Shrs close(s); 547224144Shrs 548224144Shrs /* ND flags */ 549224144Shrs error = update_ifinfo_nd_flags(ifi); 550224144Shrs if (error) { 551224144Shrs if (ifi_new) 552224144Shrs free(ifi); 553224144Shrs continue; 554224144Shrs } 555224144Shrs 556224144Shrs /* SDL */ 557224144Shrs sa = (struct sockaddr *)(ifm + 1); 558224144Shrs get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 559224144Shrs if ((sa = rti_info[RTAX_IFP]) != NULL) { 560224144Shrs if (sa->sa_family == AF_LINK) { 561224144Shrs memcpy(&ifi->ifi_sdl, 562224144Shrs (struct sockaddr_dl *)sa, 563224144Shrs sizeof(ifi->ifi_sdl)); 564224144Shrs } 565224144Shrs } else 566224144Shrs memset(&ifi->ifi_sdl, 0, 567224144Shrs sizeof(ifi->ifi_sdl)); 568224144Shrs 569224144Shrs /* flags */ 570224144Shrs ifi->ifi_flags = ifm->ifm_flags; 571224144Shrs 572224144Shrs /* type */ 573224144Shrs ifi->ifi_type = ifm->ifm_type; 57455505Sshin } else { 575224144Shrs syslog(LOG_ERR, 576224144Shrs "out of sync parsing NET_RT_IFLIST\n" 577224144Shrs "expected %d, got %d\n msglen = %d\n", 578224144Shrs RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen); 579224144Shrs exit(1); 58055505Sshin } 581224144Shrs 582224144Shrs if (ifi_new) { 583224144Shrs syslog(LOG_DEBUG, 584224144Shrs "<%s> adding %s(idx=%d) to ifilist", 585224144Shrs __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 586224144Shrs TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 58755505Sshin } 58855505Sshin } 589224144Shrs free(msg); 590224144Shrs 591224144Shrs if (mcastif != NULL) { 592224144Shrs error = sock_mc_rr_update(&sock, mcastif); 593224144Shrs if (error) 594224144Shrs exit(1); 595224144Shrs } 596224144Shrs 597224144Shrs return (ifi); 59855505Sshin} 59955505Sshin 600224144Shrsstatic struct if_msghdr * 601224144Shrsget_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim) 60255505Sshin{ 603224144Shrs struct ifa_msghdr *ifam; 604224144Shrs 605224144Shrs for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen); 606224144Shrs ifam < (struct ifa_msghdr *)lim; 607224144Shrs ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) { 608224144Shrs if (!ifam->ifam_msglen) { 609224144Shrs syslog(LOG_WARNING, 610224144Shrs "<%s> ifa_msglen is 0", __func__); 611224144Shrs return (NULL); 612224144Shrs } 613224144Shrs if (ifam->ifam_type != RTM_NEWADDR) 614224144Shrs break; 615224144Shrs } 616224144Shrs 617224144Shrs return ((struct if_msghdr *)ifam); 618224144Shrs} 619224144Shrs 620224144Shrsint 621224144Shrsgetinet6sysctl(int code) 622224144Shrs{ 623224144Shrs int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 624224144Shrs int value; 625224144Shrs size_t size; 626224144Shrs 627224144Shrs mib[3] = code; 628224144Shrs size = sizeof(value); 629224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 630224144Shrs < 0) { 631224144Shrs syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 632224144Shrs __func__, code, 633224144Shrs strerror(errno)); 634224144Shrs return (-1); 635224144Shrs } 636224144Shrs else 637224144Shrs return (value); 638224144Shrs} 639224144Shrs 640224144Shrs 641224144Shrsint 642224144Shrssock_mc_join(struct sockinfo *s, int ifindex) 643224144Shrs{ 644224144Shrs struct ipv6_mreq mreq; 645224144Shrs char ifname[IFNAMSIZ]; 646224144Shrs 647224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 648224144Shrs 649224144Shrs if (ifindex == 0) 650224144Shrs return (1); 651224144Shrs 652224144Shrs /* 653224144Shrs * join all routers multicast address on each advertising 654224144Shrs * interface. 655224144Shrs */ 656224144Shrs memset(&mreq, 0, sizeof(mreq)); 657224144Shrs /* XXX */ 658224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 659224144Shrs &sin6_linklocal_allrouters.sin6_addr, 660224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 661224144Shrs 662224144Shrs mreq.ipv6mr_interface = ifindex; 663224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 664224144Shrs sizeof(mreq)) < 0) { 665224144Shrs syslog(LOG_ERR, 666224144Shrs "<%s> IPV6_JOIN_GROUP(link) on %s: %s", 667224144Shrs __func__, if_indextoname(ifindex, ifname), 668224144Shrs strerror(errno)); 669224144Shrs return (1); 670224144Shrs } 671222732Shrs syslog(LOG_DEBUG, 672224144Shrs "<%s> %s: join link-local all-routers MC group", 673224144Shrs __func__, if_indextoname(ifindex, ifname)); 674222732Shrs 675224144Shrs return (0); 676224144Shrs} 677224144Shrs 678224144Shrsint 679224144Shrssock_mc_leave(struct sockinfo *s, int ifindex) 680224144Shrs{ 681224144Shrs struct ipv6_mreq mreq; 682224144Shrs char ifname[IFNAMSIZ]; 683224144Shrs 684224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 685224144Shrs 686224144Shrs if (ifindex == 0) 687224144Shrs return (1); 688224144Shrs 689224144Shrs /* 690224144Shrs * join all routers multicast address on each advertising 691224144Shrs * interface. 692224144Shrs */ 693224144Shrs 694224144Shrs memset(&mreq, 0, sizeof(mreq)); 695224144Shrs /* XXX */ 696224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 697224144Shrs &sin6_linklocal_allrouters.sin6_addr, 698224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 699224144Shrs 700224144Shrs mreq.ipv6mr_interface = ifindex; 701224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, 702224144Shrs sizeof(mreq)) < 0) { 703224144Shrs syslog(LOG_ERR, 704224144Shrs "<%s> IPV6_JOIN_LEAVE(link) on %s: %s", 705224144Shrs __func__, if_indextoname(ifindex, ifname), 706224144Shrs strerror(errno)); 707224144Shrs return (1); 70855505Sshin } 709224144Shrs syslog(LOG_DEBUG, 710224144Shrs "<%s> %s: leave link-local all-routers MC group", 711224144Shrs __func__, if_indextoname(ifindex, ifname)); 71255505Sshin 713224144Shrs return (0); 71455505Sshin} 715224144Shrs 716224144Shrsint 717224144Shrssock_mc_rr_update(struct sockinfo *s, char *mif) 718224144Shrs{ 719224144Shrs struct ipv6_mreq mreq; 720224144Shrs 721224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 722224144Shrs 723224144Shrs if (mif == NULL) 724224144Shrs return (1); 725224144Shrs /* 726224144Shrs * When attending router renumbering, join all-routers site-local 727224144Shrs * multicast group. 728224144Shrs */ 729224144Shrs /* XXX */ 730224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 731224144Shrs &sin6_sitelocal_allrouters.sin6_addr, 732224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 733224144Shrs if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) { 734224144Shrs syslog(LOG_ERR, 735224144Shrs "<%s> invalid interface: %s", 736224144Shrs __func__, mif); 737224144Shrs return (1); 738224144Shrs } 739224144Shrs 740224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 741224144Shrs &mreq, sizeof(mreq)) < 0) { 742224144Shrs syslog(LOG_ERR, 743224144Shrs "<%s> IPV6_JOIN_GROUP(site) on %s: %s", 744224144Shrs __func__, mif, strerror(errno)); 745224144Shrs return (1); 746224144Shrs } 747224144Shrs 748224144Shrs syslog(LOG_DEBUG, 749224144Shrs "<%s> %s: join site-local all-routers MC group", 750224144Shrs __func__, mif); 751224144Shrs 752224144Shrs return (0); 753224144Shrs} 754