171333Sitojun/* $FreeBSD$ */ 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: 118222732Shrs return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 119118664Sume default: 120222732Shrs return (0); 12155505Sshin } 12255505Sshin} 12355505Sshin 12455505Sshinvoid 12555505Sshinlladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 12655505Sshin{ 12755505Sshin char *addr; 12855505Sshin 12955505Sshin ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 13055505Sshin 131118664Sume switch (sdl->sdl_type) { 132118664Sume case IFT_ETHER: 133118664Sume ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 134118664Sume addr = (char *)(ndopt + 1); 135118664Sume memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 136118664Sume break; 137118664Sume default: 138118664Sume syslog(LOG_ERR, "<%s> unsupported link type(%d)", 139118664Sume __func__, sdl->sdl_type); 140118664Sume exit(1); 14155505Sshin } 14255505Sshin 14355505Sshin return; 14455505Sshin} 14555505Sshin 14655505Sshinint 147222732Shrsrtbuf_len(void) 14855505Sshin{ 14955505Sshin size_t len; 15055505Sshin int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; 15155505Sshin 15255505Sshin if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 153222732Shrs return (-1); 15455505Sshin 155222732Shrs return (len); 15655505Sshin} 15755505Sshin 15862656Skris#define FILTER_MATCH(type, filter) ((0x1 << type) & filter) 15962656Skris#define SIN6(s) ((struct sockaddr_in6 *)(s)) 16062656Skris#define SDL(s) ((struct sockaddr_dl *)(s)) 16155505Sshinchar * 16255505Sshinget_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) 16355505Sshin{ 16455505Sshin struct rt_msghdr *rtm; 16555505Sshin struct ifa_msghdr *ifam; 16655505Sshin struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; 16755505Sshin 16855505Sshin *lenp = 0; 16955505Sshin for (rtm = (struct rt_msghdr *)buf; 17055505Sshin rtm < (struct rt_msghdr *)lim; 17155505Sshin rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { 17255505Sshin /* just for safety */ 17355505Sshin if (!rtm->rtm_msglen) { 17455505Sshin syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " 175222732Shrs "(buf=%p lim=%p rtm=%p)", __func__, 176222732Shrs buf, lim, rtm); 17755505Sshin break; 17855505Sshin } 179222732Shrs if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { 180222732Shrs syslog(LOG_WARNING, 181222732Shrs "<%s> routing message version mismatch " 182222732Shrs "(buf=%p lim=%p rtm=%p)", __func__, 183222732Shrs buf, lim, rtm); 18455505Sshin continue; 18555505Sshin } 18655505Sshin 187222732Shrs if (FILTER_MATCH(rtm->rtm_type, filter) == 0) 188222732Shrs continue; 189222732Shrs 19055505Sshin switch (rtm->rtm_type) { 19155505Sshin case RTM_GET: 19255505Sshin case RTM_ADD: 19355505Sshin case RTM_DELETE: 19455505Sshin /* address related checks */ 19555505Sshin sa = (struct sockaddr *)(rtm + 1); 19655505Sshin get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 19755505Sshin if ((dst = rti_info[RTAX_DST]) == NULL || 19855505Sshin dst->sa_family != AF_INET6) 19955505Sshin continue; 20055505Sshin 20155505Sshin if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || 20255505Sshin IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) 20355505Sshin continue; 20455505Sshin 20555505Sshin if ((gw = rti_info[RTAX_GATEWAY]) == NULL || 20655505Sshin gw->sa_family != AF_LINK) 20755505Sshin continue; 20855505Sshin if (ifindex && SDL(gw)->sdl_index != ifindex) 20955505Sshin continue; 21055505Sshin 21155505Sshin if (rti_info[RTAX_NETMASK] == NULL) 21255505Sshin continue; 21355505Sshin 21455505Sshin /* found */ 21555505Sshin *lenp = rtm->rtm_msglen; 21655505Sshin return (char *)rtm; 21755505Sshin /* NOTREACHED */ 21855505Sshin case RTM_NEWADDR: 21955505Sshin case RTM_DELADDR: 22055505Sshin ifam = (struct ifa_msghdr *)rtm; 22155505Sshin 22255505Sshin /* address related checks */ 22355505Sshin sa = (struct sockaddr *)(ifam + 1); 22455505Sshin get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 22555505Sshin if ((ifa = rti_info[RTAX_IFA]) == NULL || 22655505Sshin (ifa->sa_family != AF_INET && 22755505Sshin ifa->sa_family != AF_INET6)) 22855505Sshin continue; 22955505Sshin 23055505Sshin if (ifa->sa_family == AF_INET6 && 23155505Sshin (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || 23255505Sshin IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) 23355505Sshin continue; 23455505Sshin 23555505Sshin if (ifindex && ifam->ifam_index != ifindex) 23655505Sshin continue; 23755505Sshin 23855505Sshin /* found */ 23955505Sshin *lenp = ifam->ifam_msglen; 24055505Sshin return (char *)rtm; 24155505Sshin /* NOTREACHED */ 24255505Sshin case RTM_IFINFO: 243222732Shrs case RTM_IFANNOUNCE: 24455505Sshin /* found */ 24555505Sshin *lenp = rtm->rtm_msglen; 24655505Sshin return (char *)rtm; 24755505Sshin /* NOTREACHED */ 24855505Sshin } 24955505Sshin } 25055505Sshin 251222732Shrs return ((char *)rtm); 25255505Sshin} 25378064Sume#undef FILTER_MATCH 25455505Sshin 25555505Sshinstruct in6_addr * 25655505Sshinget_addr(char *buf) 25755505Sshin{ 25855505Sshin struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 25955505Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 26055505Sshin 26155505Sshin sa = (struct sockaddr *)(rtm + 1); 26255505Sshin get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 26355505Sshin 264222732Shrs return (&SIN6(rti_info[RTAX_DST])->sin6_addr); 26555505Sshin} 26655505Sshin 26755505Sshinint 26855505Sshinget_rtm_ifindex(char *buf) 26955505Sshin{ 27055505Sshin struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 27155505Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 27255505Sshin 27355505Sshin sa = (struct sockaddr *)(rtm + 1); 27455505Sshin get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 27555505Sshin 276222732Shrs return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); 27755505Sshin} 27855505Sshin 27955505Sshinint 28055505Sshinget_prefixlen(char *buf) 28155505Sshin{ 28255505Sshin struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 28355505Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 284224144Shrs char *p, *lim; 285222732Shrs 28655505Sshin sa = (struct sockaddr *)(rtm + 1); 28755505Sshin get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 28855505Sshin sa = rti_info[RTAX_NETMASK]; 28955505Sshin 290224144Shrs p = (char *)(&SIN6(sa)->sin6_addr); 291224144Shrs lim = (char *)sa + sa->sa_len; 29267801Sume return prefixlen(p, lim); 29367801Sume} 29467801Sume 29567801Sumeint 296224144Shrsprefixlen(unsigned char *p, unsigned char *lim) 29767801Sume{ 29867801Sume int masklen; 29967801Sume 30055505Sshin for (masklen = 0; p < lim; p++) { 30155505Sshin switch (*p) { 30255505Sshin case 0xff: 30355505Sshin masklen += 8; 30455505Sshin break; 30555505Sshin case 0xfe: 30655505Sshin masklen += 7; 30755505Sshin break; 30855505Sshin case 0xfc: 30955505Sshin masklen += 6; 31055505Sshin break; 31155505Sshin case 0xf8: 31255505Sshin masklen += 5; 31355505Sshin break; 31455505Sshin case 0xf0: 31555505Sshin masklen += 4; 31655505Sshin break; 31755505Sshin case 0xe0: 31855505Sshin masklen += 3; 31955505Sshin break; 32055505Sshin case 0xc0: 32155505Sshin masklen += 2; 32255505Sshin break; 32355505Sshin case 0x80: 32455505Sshin masklen += 1; 32555505Sshin break; 32655505Sshin case 0x00: 32755505Sshin break; 32855505Sshin default: 329222732Shrs return (-1); 33055505Sshin } 33155505Sshin } 33255505Sshin 333222732Shrs return (masklen); 33455505Sshin} 33555505Sshin 336224144Shrsstruct ifinfo * 337224144Shrsupdate_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname) 33855505Sshin{ 339224144Shrs struct ifinfo *ifi; 340224144Shrs int ifindex; 34155505Sshin 342224144Shrs ifi = NULL; 343224144Shrs ifindex = if_nametoindex(ifname); 344224144Shrs TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 345224144Shrs if (ifindex != 0) { 346224144Shrs if (ifindex == ifi->ifi_ifindex) 347224144Shrs break; 348224144Shrs } else { 349224144Shrs if (strncmp(ifname, ifi->ifi_ifname, 350224144Shrs sizeof(ifi->ifi_ifname)) == 0) 351224144Shrs break; 352224144Shrs } 353224144Shrs } 35455505Sshin 355224144Shrs if (ifi == NULL) { 356224144Shrs /* A new ifinfo element is needed. */ 357224144Shrs syslog(LOG_DEBUG, "<%s> new entry: %s", __func__, 358224144Shrs ifname); 35955505Sshin 360224144Shrs ELM_MALLOC(ifi, exit(1)); 361224144Shrs ifi->ifi_ifindex = 0; 362224144Shrs strncpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)-1); 363224144Shrs ifi->ifi_ifname[sizeof(ifi->ifi_ifname)-1] = '\0'; 364224144Shrs ifi->ifi_rainfo = NULL; 365224144Shrs ifi->ifi_state = IFI_STATE_UNCONFIGURED; 366224144Shrs TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 367224144Shrs } 368224144Shrs 369224144Shrs ifi->ifi_persist = 1; 370224144Shrs 371224144Shrs syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__, 372224144Shrs ifi->ifi_ifname); 373224144Shrs syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__, 374224144Shrs ifi->ifi_ifname, ifi->ifi_state); 375224144Shrs return (ifi); 37655505Sshin} 37755505Sshin 37855505Sshinint 379224144Shrsupdate_ifinfo_nd_flags(struct ifinfo *ifi) 38055505Sshin{ 381224144Shrs struct in6_ndireq nd; 382224144Shrs int s; 383224144Shrs int error; 38455505Sshin 385224144Shrs if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 386224144Shrs syslog(LOG_ERR, 387224144Shrs "<%s> socket() failed.", __func__); 388224144Shrs return (1); 389224144Shrs } 390224144Shrs /* ND flags */ 391224144Shrs memset(&nd, 0, sizeof(nd)); 392224144Shrs strncpy(nd.ifname, ifi->ifi_ifname, 393224144Shrs sizeof(nd.ifname)); 394224144Shrs error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd); 395224144Shrs if (error) { 396224144Shrs close(s); 397255156Shrs if (errno != EPFNOSUPPORT) 398255156Shrs syslog(LOG_ERR, "<%s> ioctl() failed.", __func__); 399224144Shrs return (1); 400224144Shrs } 401224144Shrs ifi->ifi_nd_flags = nd.ndi.flags; 402224144Shrs close(s); 403224144Shrs 404224144Shrs return (0); 40555505Sshin} 40655505Sshin 407224144Shrsstruct ifinfo * 408224144Shrsupdate_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) 40955505Sshin{ 410224144Shrs struct if_msghdr *ifm; 411224144Shrs struct ifinfo *ifi = NULL; 412224144Shrs struct sockaddr *sa; 413224144Shrs struct sockaddr *rti_info[RTAX_MAX]; 414224144Shrs char *msg; 415224144Shrs size_t len; 416224144Shrs char *lim; 417224144Shrs int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; 418224144Shrs int error; 41955505Sshin 420224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 42155505Sshin 422224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) < 423224144Shrs 0) { 424224144Shrs syslog(LOG_ERR, 425224144Shrs "<%s> sysctl: NET_RT_IFLIST size get failed", __func__); 42655505Sshin exit(1); 42755505Sshin } 428224144Shrs if ((msg = malloc(len)) == NULL) { 429118660Sume syslog(LOG_ERR, "<%s> malloc failed", __func__); 43055505Sshin exit(1); 43155505Sshin } 432224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) < 433224144Shrs 0) { 434224144Shrs syslog(LOG_ERR, 435224144Shrs "<%s> sysctl: NET_RT_IFLIST get failed", __func__); 43655505Sshin exit(1); 43755505Sshin } 43855505Sshin 439224144Shrs lim = msg + len; 440224144Shrs for (ifm = (struct if_msghdr *)msg; 441224144Shrs ifm != NULL && ifm < (struct if_msghdr *)lim; 442224144Shrs ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) { 443224144Shrs int ifi_new; 44455505Sshin 445224144Shrs syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu", 446224144Shrs __func__, ifm, lim, (char *)lim - (char *)ifm); 44755505Sshin 448224144Shrs if (ifm->ifm_version != RTM_VERSION) { 449224144Shrs syslog(LOG_ERR, 450224144Shrs "<%s> ifm_vesrion mismatch", __func__); 451224144Shrs exit(1); 452224144Shrs } 45355505Sshin if (ifm->ifm_msglen == 0) { 454224144Shrs syslog(LOG_WARNING, 455224144Shrs "<%s> ifm_msglen is 0", __func__); 456224144Shrs free(msg); 457224144Shrs return (NULL); 45855505Sshin } 45955505Sshin 460224144Shrs ifi_new = 0; 46155505Sshin if (ifm->ifm_type == RTM_IFINFO) { 462224144Shrs struct ifreq ifr; 463224144Shrs int s; 464224144Shrs char ifname[IFNAMSIZ]; 465224144Shrs 466224144Shrs syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. " 467224144Shrs "ifm_index = %d, ifindex = %d", 468224144Shrs __func__, ifm->ifm_index, ifindex); 469224144Shrs 470224144Shrs /* when ifindex is specified */ 471224144Shrs if (ifindex != UPDATE_IFINFO_ALL && 472224144Shrs ifindex != ifm->ifm_index) 473224144Shrs continue; 474224144Shrs 475224144Shrs /* lookup an entry with the same ifindex */ 476224144Shrs TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 477224144Shrs if (ifm->ifm_index == ifi->ifi_ifindex) 478224144Shrs break; 479224144Shrs if_indextoname(ifm->ifm_index, ifname); 480224144Shrs if (strncmp(ifname, ifi->ifi_ifname, 481224144Shrs sizeof(ifname)) == 0) 482224144Shrs break; 483224144Shrs } 484224144Shrs if (ifi == NULL) { 485224144Shrs syslog(LOG_DEBUG, 486224144Shrs "<%s> new entry for idx=%d", 487224144Shrs __func__, ifm->ifm_index); 488224144Shrs ELM_MALLOC(ifi, exit(1)); 489224144Shrs ifi->ifi_rainfo = NULL; 490224144Shrs ifi->ifi_state = IFI_STATE_UNCONFIGURED; 491224144Shrs ifi->ifi_persist = 0; 492224144Shrs ifi_new = 1; 493224144Shrs } 494224144Shrs /* ifindex */ 495224144Shrs ifi->ifi_ifindex = ifm->ifm_index; 496224144Shrs 497224144Shrs /* ifname */ 498224144Shrs if_indextoname(ifm->ifm_index, ifi->ifi_ifname); 499224144Shrs if (ifi->ifi_ifname == NULL) { 500224144Shrs syslog(LOG_WARNING, 501224144Shrs "<%s> ifname not found (idx=%d)", 502224144Shrs __func__, ifm->ifm_index); 503224144Shrs if (ifi_new) 504224144Shrs free(ifi); 505224144Shrs continue; 506224144Shrs } 507224144Shrs 508224144Shrs if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 509224144Shrs syslog(LOG_ERR, 510224144Shrs "<%s> socket() failed.", __func__); 511224144Shrs if (ifi_new) 512224144Shrs free(ifi); 513224144Shrs continue; 514224144Shrs } 515224144Shrs 516224144Shrs /* MTU */ 517224144Shrs ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu; 518224144Shrs if (ifi->ifi_phymtu == 0) { 519224144Shrs memset(&ifr, 0, sizeof(ifr)); 520224144Shrs ifr.ifr_addr.sa_family = AF_INET6; 521224144Shrs strncpy(ifr.ifr_name, ifi->ifi_ifname, 522224144Shrs sizeof(ifr.ifr_name)); 523224144Shrs error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr); 524224144Shrs if (error) { 525224144Shrs close(s); 526224144Shrs syslog(LOG_ERR, 527224144Shrs "<%s> ioctl() failed.", 528224144Shrs __func__); 529224144Shrs if (ifi_new) 530224144Shrs free(ifi); 531224144Shrs continue; 532224144Shrs } 533224144Shrs ifi->ifi_phymtu = ifr.ifr_mtu; 534224144Shrs if (ifi->ifi_phymtu == 0) { 535224144Shrs syslog(LOG_WARNING, 536224144Shrs "<%s> no interface mtu info" 537224144Shrs " on %s. %d will be used.", 538224144Shrs __func__, ifi->ifi_ifname, 539224144Shrs IPV6_MMTU); 540224144Shrs ifi->ifi_phymtu = IPV6_MMTU; 541224144Shrs } 542224144Shrs } 543224144Shrs close(s); 544224144Shrs 545224144Shrs /* ND flags */ 546224144Shrs error = update_ifinfo_nd_flags(ifi); 547224144Shrs if (error) { 548224144Shrs if (ifi_new) 549224144Shrs free(ifi); 550224144Shrs continue; 551224144Shrs } 552224144Shrs 553224144Shrs /* SDL */ 554224144Shrs sa = (struct sockaddr *)(ifm + 1); 555224144Shrs get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 556224144Shrs if ((sa = rti_info[RTAX_IFP]) != NULL) { 557224144Shrs if (sa->sa_family == AF_LINK) { 558224144Shrs memcpy(&ifi->ifi_sdl, 559224144Shrs (struct sockaddr_dl *)sa, 560224144Shrs sizeof(ifi->ifi_sdl)); 561224144Shrs } 562224144Shrs } else 563224144Shrs memset(&ifi->ifi_sdl, 0, 564224144Shrs sizeof(ifi->ifi_sdl)); 565224144Shrs 566224144Shrs /* flags */ 567224144Shrs ifi->ifi_flags = ifm->ifm_flags; 568224144Shrs 569224144Shrs /* type */ 570224144Shrs ifi->ifi_type = ifm->ifm_type; 57155505Sshin } else { 572224144Shrs syslog(LOG_ERR, 573224144Shrs "out of sync parsing NET_RT_IFLIST\n" 574224144Shrs "expected %d, got %d\n msglen = %d\n", 575224144Shrs RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen); 576224144Shrs exit(1); 57755505Sshin } 578224144Shrs 579224144Shrs if (ifi_new) { 580224144Shrs syslog(LOG_DEBUG, 581224144Shrs "<%s> adding %s(idx=%d) to ifilist", 582224144Shrs __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 583224144Shrs TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 58455505Sshin } 58555505Sshin } 586224144Shrs free(msg); 587224144Shrs 588224144Shrs if (mcastif != NULL) { 589224144Shrs error = sock_mc_rr_update(&sock, mcastif); 590224144Shrs if (error) 591224144Shrs exit(1); 592224144Shrs } 593224144Shrs 594224144Shrs return (ifi); 59555505Sshin} 59655505Sshin 597224144Shrsstatic struct if_msghdr * 598224144Shrsget_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim) 59955505Sshin{ 600224144Shrs struct ifa_msghdr *ifam; 601224144Shrs 602224144Shrs for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen); 603224144Shrs ifam < (struct ifa_msghdr *)lim; 604224144Shrs ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) { 605224144Shrs if (!ifam->ifam_msglen) { 606224144Shrs syslog(LOG_WARNING, 607224144Shrs "<%s> ifa_msglen is 0", __func__); 608224144Shrs return (NULL); 609224144Shrs } 610224144Shrs if (ifam->ifam_type != RTM_NEWADDR) 611224144Shrs break; 612224144Shrs } 613224144Shrs 614224144Shrs return ((struct if_msghdr *)ifam); 615224144Shrs} 616224144Shrs 617224144Shrsint 618224144Shrsgetinet6sysctl(int code) 619224144Shrs{ 620224144Shrs int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 621224144Shrs int value; 622224144Shrs size_t size; 623224144Shrs 624224144Shrs mib[3] = code; 625224144Shrs size = sizeof(value); 626224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 627224144Shrs < 0) { 628224144Shrs syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 629224144Shrs __func__, code, 630224144Shrs strerror(errno)); 631224144Shrs return (-1); 632224144Shrs } 633224144Shrs else 634224144Shrs return (value); 635224144Shrs} 636224144Shrs 637224144Shrs 638224144Shrsint 639224144Shrssock_mc_join(struct sockinfo *s, int ifindex) 640224144Shrs{ 641224144Shrs struct ipv6_mreq mreq; 642224144Shrs char ifname[IFNAMSIZ]; 643224144Shrs 644224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 645224144Shrs 646224144Shrs if (ifindex == 0) 647224144Shrs return (1); 648224144Shrs 649224144Shrs /* 650224144Shrs * join all routers multicast address on each advertising 651224144Shrs * interface. 652224144Shrs */ 653224144Shrs memset(&mreq, 0, sizeof(mreq)); 654224144Shrs /* XXX */ 655224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 656224144Shrs &sin6_linklocal_allrouters.sin6_addr, 657224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 658224144Shrs 659224144Shrs mreq.ipv6mr_interface = ifindex; 660224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 661224144Shrs sizeof(mreq)) < 0) { 662224144Shrs syslog(LOG_ERR, 663224144Shrs "<%s> IPV6_JOIN_GROUP(link) on %s: %s", 664224144Shrs __func__, if_indextoname(ifindex, ifname), 665224144Shrs strerror(errno)); 666224144Shrs return (1); 667224144Shrs } 668222732Shrs syslog(LOG_DEBUG, 669224144Shrs "<%s> %s: join link-local all-routers MC group", 670224144Shrs __func__, if_indextoname(ifindex, ifname)); 671222732Shrs 672224144Shrs return (0); 673224144Shrs} 674224144Shrs 675224144Shrsint 676224144Shrssock_mc_leave(struct sockinfo *s, int ifindex) 677224144Shrs{ 678224144Shrs struct ipv6_mreq mreq; 679224144Shrs char ifname[IFNAMSIZ]; 680224144Shrs 681224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 682224144Shrs 683224144Shrs if (ifindex == 0) 684224144Shrs return (1); 685224144Shrs 686224144Shrs /* 687224144Shrs * join all routers multicast address on each advertising 688224144Shrs * interface. 689224144Shrs */ 690224144Shrs 691224144Shrs memset(&mreq, 0, sizeof(mreq)); 692224144Shrs /* XXX */ 693224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 694224144Shrs &sin6_linklocal_allrouters.sin6_addr, 695224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 696224144Shrs 697224144Shrs mreq.ipv6mr_interface = ifindex; 698224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, 699224144Shrs sizeof(mreq)) < 0) { 700224144Shrs syslog(LOG_ERR, 701224144Shrs "<%s> IPV6_JOIN_LEAVE(link) on %s: %s", 702224144Shrs __func__, if_indextoname(ifindex, ifname), 703224144Shrs strerror(errno)); 704224144Shrs return (1); 70555505Sshin } 706224144Shrs syslog(LOG_DEBUG, 707224144Shrs "<%s> %s: leave link-local all-routers MC group", 708224144Shrs __func__, if_indextoname(ifindex, ifname)); 70955505Sshin 710224144Shrs return (0); 71155505Sshin} 712224144Shrs 713224144Shrsint 714224144Shrssock_mc_rr_update(struct sockinfo *s, char *mif) 715224144Shrs{ 716224144Shrs struct ipv6_mreq mreq; 717224144Shrs 718224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 719224144Shrs 720224144Shrs if (mif == NULL) 721224144Shrs return (1); 722224144Shrs /* 723224144Shrs * When attending router renumbering, join all-routers site-local 724224144Shrs * multicast group. 725224144Shrs */ 726224144Shrs /* XXX */ 727224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 728224144Shrs &sin6_sitelocal_allrouters.sin6_addr, 729224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 730224144Shrs if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) { 731224144Shrs syslog(LOG_ERR, 732224144Shrs "<%s> invalid interface: %s", 733224144Shrs __func__, mif); 734224144Shrs return (1); 735224144Shrs } 736224144Shrs 737224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 738224144Shrs &mreq, sizeof(mreq)) < 0) { 739224144Shrs syslog(LOG_ERR, 740224144Shrs "<%s> IPV6_JOIN_GROUP(site) on %s: %s", 741224144Shrs __func__, mif, strerror(errno)); 742224144Shrs return (1); 743224144Shrs } 744224144Shrs 745224144Shrs syslog(LOG_DEBUG, 746224144Shrs "<%s> %s: join site-local all-routers MC group", 747224144Shrs __func__, mif); 748224144Shrs 749224144Shrs return (0); 750224144Shrs} 751