171333Sitojun/* $FreeBSD: releng/10.3/usr.sbin/rtadvd/if.c 290853 2015-11-15 07:10:02Z delphij $ */ 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; 362290853Sdelphij strlcpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)); 363224144Shrs ifi->ifi_rainfo = NULL; 364224144Shrs ifi->ifi_state = IFI_STATE_UNCONFIGURED; 365224144Shrs TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 366224144Shrs } 367224144Shrs 368224144Shrs ifi->ifi_persist = 1; 369224144Shrs 370224144Shrs syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__, 371224144Shrs ifi->ifi_ifname); 372224144Shrs syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__, 373224144Shrs ifi->ifi_ifname, ifi->ifi_state); 374224144Shrs return (ifi); 37555505Sshin} 37655505Sshin 37755505Sshinint 378224144Shrsupdate_ifinfo_nd_flags(struct ifinfo *ifi) 37955505Sshin{ 380224144Shrs struct in6_ndireq nd; 381224144Shrs int s; 382224144Shrs int error; 38355505Sshin 384224144Shrs if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 385224144Shrs syslog(LOG_ERR, 386224144Shrs "<%s> socket() failed.", __func__); 387224144Shrs return (1); 388224144Shrs } 389224144Shrs /* ND flags */ 390224144Shrs memset(&nd, 0, sizeof(nd)); 391224144Shrs strncpy(nd.ifname, ifi->ifi_ifname, 392224144Shrs sizeof(nd.ifname)); 393224144Shrs error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd); 394224144Shrs if (error) { 395224144Shrs close(s); 396255156Shrs if (errno != EPFNOSUPPORT) 397255156Shrs syslog(LOG_ERR, "<%s> ioctl() failed.", __func__); 398224144Shrs return (1); 399224144Shrs } 400224144Shrs ifi->ifi_nd_flags = nd.ndi.flags; 401224144Shrs close(s); 402224144Shrs 403224144Shrs return (0); 40455505Sshin} 40555505Sshin 406224144Shrsstruct ifinfo * 407224144Shrsupdate_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) 40855505Sshin{ 409224144Shrs struct if_msghdr *ifm; 410224144Shrs struct ifinfo *ifi = NULL; 411224144Shrs struct sockaddr *sa; 412224144Shrs struct sockaddr *rti_info[RTAX_MAX]; 413224144Shrs char *msg; 414224144Shrs size_t len; 415224144Shrs char *lim; 416224144Shrs int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; 417224144Shrs int error; 41855505Sshin 419224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 42055505Sshin 421224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) < 422224144Shrs 0) { 423224144Shrs syslog(LOG_ERR, 424224144Shrs "<%s> sysctl: NET_RT_IFLIST size get failed", __func__); 42555505Sshin exit(1); 42655505Sshin } 427224144Shrs if ((msg = malloc(len)) == NULL) { 428118660Sume syslog(LOG_ERR, "<%s> malloc failed", __func__); 42955505Sshin exit(1); 43055505Sshin } 431224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) < 432224144Shrs 0) { 433224144Shrs syslog(LOG_ERR, 434224144Shrs "<%s> sysctl: NET_RT_IFLIST get failed", __func__); 43555505Sshin exit(1); 43655505Sshin } 43755505Sshin 438224144Shrs lim = msg + len; 439224144Shrs for (ifm = (struct if_msghdr *)msg; 440224144Shrs ifm != NULL && ifm < (struct if_msghdr *)lim; 441224144Shrs ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) { 442224144Shrs int ifi_new; 44355505Sshin 444224144Shrs syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu", 445224144Shrs __func__, ifm, lim, (char *)lim - (char *)ifm); 44655505Sshin 447224144Shrs if (ifm->ifm_version != RTM_VERSION) { 448224144Shrs syslog(LOG_ERR, 449224144Shrs "<%s> ifm_vesrion mismatch", __func__); 450224144Shrs exit(1); 451224144Shrs } 45255505Sshin if (ifm->ifm_msglen == 0) { 453224144Shrs syslog(LOG_WARNING, 454224144Shrs "<%s> ifm_msglen is 0", __func__); 455224144Shrs free(msg); 456224144Shrs return (NULL); 45755505Sshin } 45855505Sshin 459224144Shrs ifi_new = 0; 46055505Sshin if (ifm->ifm_type == RTM_IFINFO) { 461224144Shrs struct ifreq ifr; 462224144Shrs int s; 463224144Shrs char ifname[IFNAMSIZ]; 464224144Shrs 465224144Shrs syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. " 466224144Shrs "ifm_index = %d, ifindex = %d", 467224144Shrs __func__, ifm->ifm_index, ifindex); 468224144Shrs 469224144Shrs /* when ifindex is specified */ 470224144Shrs if (ifindex != UPDATE_IFINFO_ALL && 471224144Shrs ifindex != ifm->ifm_index) 472224144Shrs continue; 473224144Shrs 474224144Shrs /* lookup an entry with the same ifindex */ 475224144Shrs TAILQ_FOREACH(ifi, ifi_head, ifi_next) { 476224144Shrs if (ifm->ifm_index == ifi->ifi_ifindex) 477224144Shrs break; 478224144Shrs if_indextoname(ifm->ifm_index, ifname); 479224144Shrs if (strncmp(ifname, ifi->ifi_ifname, 480224144Shrs sizeof(ifname)) == 0) 481224144Shrs break; 482224144Shrs } 483224144Shrs if (ifi == NULL) { 484224144Shrs syslog(LOG_DEBUG, 485224144Shrs "<%s> new entry for idx=%d", 486224144Shrs __func__, ifm->ifm_index); 487224144Shrs ELM_MALLOC(ifi, exit(1)); 488224144Shrs ifi->ifi_rainfo = NULL; 489224144Shrs ifi->ifi_state = IFI_STATE_UNCONFIGURED; 490224144Shrs ifi->ifi_persist = 0; 491224144Shrs ifi_new = 1; 492224144Shrs } 493224144Shrs /* ifindex */ 494224144Shrs ifi->ifi_ifindex = ifm->ifm_index; 495224144Shrs 496224144Shrs /* ifname */ 497224144Shrs if_indextoname(ifm->ifm_index, ifi->ifi_ifname); 498224144Shrs if (ifi->ifi_ifname == NULL) { 499224144Shrs syslog(LOG_WARNING, 500224144Shrs "<%s> ifname not found (idx=%d)", 501224144Shrs __func__, ifm->ifm_index); 502224144Shrs if (ifi_new) 503224144Shrs free(ifi); 504224144Shrs continue; 505224144Shrs } 506224144Shrs 507224144Shrs if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 508224144Shrs syslog(LOG_ERR, 509224144Shrs "<%s> socket() failed.", __func__); 510224144Shrs if (ifi_new) 511224144Shrs free(ifi); 512224144Shrs continue; 513224144Shrs } 514224144Shrs 515224144Shrs /* MTU */ 516224144Shrs ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu; 517224144Shrs if (ifi->ifi_phymtu == 0) { 518224144Shrs memset(&ifr, 0, sizeof(ifr)); 519224144Shrs ifr.ifr_addr.sa_family = AF_INET6; 520224144Shrs strncpy(ifr.ifr_name, ifi->ifi_ifname, 521224144Shrs sizeof(ifr.ifr_name)); 522224144Shrs error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr); 523224144Shrs if (error) { 524224144Shrs close(s); 525224144Shrs syslog(LOG_ERR, 526224144Shrs "<%s> ioctl() failed.", 527224144Shrs __func__); 528224144Shrs if (ifi_new) 529224144Shrs free(ifi); 530224144Shrs continue; 531224144Shrs } 532224144Shrs ifi->ifi_phymtu = ifr.ifr_mtu; 533224144Shrs if (ifi->ifi_phymtu == 0) { 534224144Shrs syslog(LOG_WARNING, 535224144Shrs "<%s> no interface mtu info" 536224144Shrs " on %s. %d will be used.", 537224144Shrs __func__, ifi->ifi_ifname, 538224144Shrs IPV6_MMTU); 539224144Shrs ifi->ifi_phymtu = IPV6_MMTU; 540224144Shrs } 541224144Shrs } 542224144Shrs close(s); 543224144Shrs 544224144Shrs /* ND flags */ 545224144Shrs error = update_ifinfo_nd_flags(ifi); 546224144Shrs if (error) { 547224144Shrs if (ifi_new) 548224144Shrs free(ifi); 549224144Shrs continue; 550224144Shrs } 551224144Shrs 552224144Shrs /* SDL */ 553224144Shrs sa = (struct sockaddr *)(ifm + 1); 554224144Shrs get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 555224144Shrs if ((sa = rti_info[RTAX_IFP]) != NULL) { 556224144Shrs if (sa->sa_family == AF_LINK) { 557224144Shrs memcpy(&ifi->ifi_sdl, 558224144Shrs (struct sockaddr_dl *)sa, 559224144Shrs sizeof(ifi->ifi_sdl)); 560224144Shrs } 561224144Shrs } else 562224144Shrs memset(&ifi->ifi_sdl, 0, 563224144Shrs sizeof(ifi->ifi_sdl)); 564224144Shrs 565224144Shrs /* flags */ 566224144Shrs ifi->ifi_flags = ifm->ifm_flags; 567224144Shrs 568224144Shrs /* type */ 569224144Shrs ifi->ifi_type = ifm->ifm_type; 57055505Sshin } else { 571224144Shrs syslog(LOG_ERR, 572224144Shrs "out of sync parsing NET_RT_IFLIST\n" 573224144Shrs "expected %d, got %d\n msglen = %d\n", 574224144Shrs RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen); 575224144Shrs exit(1); 57655505Sshin } 577224144Shrs 578224144Shrs if (ifi_new) { 579224144Shrs syslog(LOG_DEBUG, 580224144Shrs "<%s> adding %s(idx=%d) to ifilist", 581224144Shrs __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 582224144Shrs TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next); 58355505Sshin } 58455505Sshin } 585224144Shrs free(msg); 586224144Shrs 587224144Shrs if (mcastif != NULL) { 588224144Shrs error = sock_mc_rr_update(&sock, mcastif); 589224144Shrs if (error) 590224144Shrs exit(1); 591224144Shrs } 592224144Shrs 593224144Shrs return (ifi); 59455505Sshin} 59555505Sshin 596224144Shrsstatic struct if_msghdr * 597224144Shrsget_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim) 59855505Sshin{ 599224144Shrs struct ifa_msghdr *ifam; 600224144Shrs 601224144Shrs for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen); 602224144Shrs ifam < (struct ifa_msghdr *)lim; 603224144Shrs ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) { 604224144Shrs if (!ifam->ifam_msglen) { 605224144Shrs syslog(LOG_WARNING, 606224144Shrs "<%s> ifa_msglen is 0", __func__); 607224144Shrs return (NULL); 608224144Shrs } 609224144Shrs if (ifam->ifam_type != RTM_NEWADDR) 610224144Shrs break; 611224144Shrs } 612224144Shrs 613224144Shrs return ((struct if_msghdr *)ifam); 614224144Shrs} 615224144Shrs 616224144Shrsint 617224144Shrsgetinet6sysctl(int code) 618224144Shrs{ 619224144Shrs int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 620224144Shrs int value; 621224144Shrs size_t size; 622224144Shrs 623224144Shrs mib[3] = code; 624224144Shrs size = sizeof(value); 625224144Shrs if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) 626224144Shrs < 0) { 627224144Shrs syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", 628224144Shrs __func__, code, 629224144Shrs strerror(errno)); 630224144Shrs return (-1); 631224144Shrs } 632224144Shrs else 633224144Shrs return (value); 634224144Shrs} 635224144Shrs 636224144Shrs 637224144Shrsint 638224144Shrssock_mc_join(struct sockinfo *s, int ifindex) 639224144Shrs{ 640224144Shrs struct ipv6_mreq mreq; 641224144Shrs char ifname[IFNAMSIZ]; 642224144Shrs 643224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 644224144Shrs 645224144Shrs if (ifindex == 0) 646224144Shrs return (1); 647224144Shrs 648224144Shrs /* 649224144Shrs * join all routers multicast address on each advertising 650224144Shrs * interface. 651224144Shrs */ 652224144Shrs memset(&mreq, 0, sizeof(mreq)); 653224144Shrs /* XXX */ 654224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 655224144Shrs &sin6_linklocal_allrouters.sin6_addr, 656224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 657224144Shrs 658224144Shrs mreq.ipv6mr_interface = ifindex; 659224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, 660224144Shrs sizeof(mreq)) < 0) { 661224144Shrs syslog(LOG_ERR, 662224144Shrs "<%s> IPV6_JOIN_GROUP(link) on %s: %s", 663224144Shrs __func__, if_indextoname(ifindex, ifname), 664224144Shrs strerror(errno)); 665224144Shrs return (1); 666224144Shrs } 667222732Shrs syslog(LOG_DEBUG, 668224144Shrs "<%s> %s: join link-local all-routers MC group", 669224144Shrs __func__, if_indextoname(ifindex, ifname)); 670222732Shrs 671224144Shrs return (0); 672224144Shrs} 673224144Shrs 674224144Shrsint 675224144Shrssock_mc_leave(struct sockinfo *s, int ifindex) 676224144Shrs{ 677224144Shrs struct ipv6_mreq mreq; 678224144Shrs char ifname[IFNAMSIZ]; 679224144Shrs 680224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 681224144Shrs 682224144Shrs if (ifindex == 0) 683224144Shrs return (1); 684224144Shrs 685224144Shrs /* 686224144Shrs * join all routers multicast address on each advertising 687224144Shrs * interface. 688224144Shrs */ 689224144Shrs 690224144Shrs memset(&mreq, 0, sizeof(mreq)); 691224144Shrs /* XXX */ 692224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 693224144Shrs &sin6_linklocal_allrouters.sin6_addr, 694224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 695224144Shrs 696224144Shrs mreq.ipv6mr_interface = ifindex; 697224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, 698224144Shrs sizeof(mreq)) < 0) { 699224144Shrs syslog(LOG_ERR, 700224144Shrs "<%s> IPV6_JOIN_LEAVE(link) on %s: %s", 701224144Shrs __func__, if_indextoname(ifindex, ifname), 702224144Shrs strerror(errno)); 703224144Shrs return (1); 70455505Sshin } 705224144Shrs syslog(LOG_DEBUG, 706224144Shrs "<%s> %s: leave link-local all-routers MC group", 707224144Shrs __func__, if_indextoname(ifindex, ifname)); 70855505Sshin 709224144Shrs return (0); 71055505Sshin} 711224144Shrs 712224144Shrsint 713224144Shrssock_mc_rr_update(struct sockinfo *s, char *mif) 714224144Shrs{ 715224144Shrs struct ipv6_mreq mreq; 716224144Shrs 717224144Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 718224144Shrs 719224144Shrs if (mif == NULL) 720224144Shrs return (1); 721224144Shrs /* 722224144Shrs * When attending router renumbering, join all-routers site-local 723224144Shrs * multicast group. 724224144Shrs */ 725224144Shrs /* XXX */ 726224144Shrs memcpy(&mreq.ipv6mr_multiaddr.s6_addr, 727224144Shrs &sin6_sitelocal_allrouters.sin6_addr, 728224144Shrs sizeof(mreq.ipv6mr_multiaddr.s6_addr)); 729224144Shrs if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) { 730224144Shrs syslog(LOG_ERR, 731224144Shrs "<%s> invalid interface: %s", 732224144Shrs __func__, mif); 733224144Shrs return (1); 734224144Shrs } 735224144Shrs 736224144Shrs if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 737224144Shrs &mreq, sizeof(mreq)) < 0) { 738224144Shrs syslog(LOG_ERR, 739224144Shrs "<%s> IPV6_JOIN_GROUP(site) on %s: %s", 740224144Shrs __func__, mif, strerror(errno)); 741224144Shrs return (1); 742224144Shrs } 743224144Shrs 744224144Shrs syslog(LOG_DEBUG, 745224144Shrs "<%s> %s: join site-local all-routers MC group", 746224144Shrs __func__, mif); 747224144Shrs 748224144Shrs return (0); 749224144Shrs} 750