if.c revision 197141
1124524Sume/* $KAME: if.c,v 1.27 2003/10/05 00:09:36 itojun Exp $ */ 266776Skris 355163Sshin/* 455163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 555163Sshin * All rights reserved. 662632Skris * 755163Sshin * Redistribution and use in source and binary forms, with or without 855163Sshin * modification, are permitted provided that the following conditions 955163Sshin * are met: 1055163Sshin * 1. Redistributions of source code must retain the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer. 1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer in the 1455163Sshin * documentation and/or other materials provided with the distribution. 1555163Sshin * 3. Neither the name of the project nor the names of its contributors 1655163Sshin * may be used to endorse or promote products derived from this software 1755163Sshin * without specific prior written permission. 1862632Skris * 1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955163Sshin * SUCH DAMAGE. 3055163Sshin * 3155163Sshin * $FreeBSD: head/usr.sbin/rtsold/if.c 197141 2009-09-12 22:14:58Z hrs $ 3255163Sshin */ 3355163Sshin 3455163Sshin#include <sys/param.h> 3555163Sshin#include <sys/socket.h> 3655163Sshin#include <sys/sysctl.h> 3755163Sshin#include <sys/ioctl.h> 3866776Skris#include <sys/queue.h> 3955163Sshin 4055163Sshin#include <net/if.h> 4155163Sshin#include <net/if_var.h> 4255163Sshin#include <net/if_types.h> 4355163Sshin#include <net/route.h> 4455163Sshin#include <net/if_dl.h> 4555163Sshin#include <net/if_media.h> 46118787Sume#include <net/ethernet.h> 4755163Sshin#include <netinet/in.h> 4855163Sshin#include <netinet/icmp6.h> 4955163Sshin 5055163Sshin#include <netinet6/in6_var.h> 51197141Shrs#include <netinet6/nd6.h> 5255163Sshin 5355163Sshin#include <stdio.h> 5455163Sshin#include <unistd.h> 5555163Sshin#include <stdlib.h> 5655163Sshin#include <syslog.h> 5755163Sshin#include <string.h> 5855163Sshin#include <fcntl.h> 5955163Sshin#include <errno.h> 6055163Sshin#include <limits.h> 6162632Skris#include <ifaddrs.h> 6255163Sshin#include "rtsold.h" 6355163Sshin 6462632Skrisextern int rssock; 6555163Sshinstatic int ifsock; 6655163Sshin 67173412Skevlostatic int get_llflag(const char *); 68173412Skevlostatic void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 6955163Sshin 7055163Sshinint 71124524Sumeifinit(void) 7255163Sshin{ 7362632Skris ifsock = rssock; 7455163Sshin 7555163Sshin return(0); 7655163Sshin} 7755163Sshin 7855163Sshinint 7955163Sshininterface_up(char *name) 8055163Sshin{ 8155163Sshin struct ifreq ifr; 82197141Shrs struct in6_ndireq nd; 8362632Skris int llflag; 84197141Shrs int s; 85197141Shrs int error; 8655163Sshin 87197141Shrs memset(&ifr, 0, sizeof(ifr)); 88119027Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 89197141Shrs memset(&nd, 0, sizeof(nd)); 90197141Shrs strlcpy(nd.ifname, name, sizeof(nd.ifname)); 9155163Sshin 9255163Sshin if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 93118660Sume warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s", 94118664Sume strerror(errno)); 9555163Sshin return(-1); 9655163Sshin } 9755163Sshin if (!(ifr.ifr_flags & IFF_UP)) { 9855163Sshin ifr.ifr_flags |= IFF_UP; 99118664Sume if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) 100118660Sume warnmsg(LOG_ERR, __func__, 101118664Sume "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); 10255163Sshin return(-1); 10355163Sshin } 104197141Shrs if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 105197141Shrs warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s", 106197141Shrs strerror(errno)); 107197141Shrs return(-1); 108197141Shrs } 109197141Shrs if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 110197141Shrs warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s", 111197141Shrs strerror(errno)); 112197141Shrs close(s); 113197141Shrs return(-1); 114197141Shrs } 11555163Sshin 116118660Sume warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name); 11755163Sshin 118197141Shrs if (nd.ndi.flags & ND6_IFF_IFDISABLED) { 119197141Shrs if (Fflag) { 120197141Shrs nd.ndi.flags &= ~ND6_IFF_IFDISABLED; 121197141Shrs if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 122197141Shrs warnmsg(LOG_WARNING, __func__, 123197141Shrs "ioctl(SIOCSIFINFO_IN6): %s", 124197141Shrs strerror(errno)); 125197141Shrs close(s); 126197141Shrs return(-1); 127197141Shrs } 128197141Shrs } else { 129197141Shrs warnmsg(LOG_WARNING, __func__, 130197141Shrs "%s is disabled.", name); 131197141Shrs close(s); 132197141Shrs return(-1); 133197141Shrs } 134197141Shrs } 135197141Shrs if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) { 136197141Shrs if (Fflag) { 137197141Shrs nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV; 138197141Shrs if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 139197141Shrs warnmsg(LOG_WARNING, __func__, 140197141Shrs "ioctl(SIOCSIFINFO_IN6): %s", 141197141Shrs strerror(errno)); 142197141Shrs close(s); 143197141Shrs return(-1); 144197141Shrs } 145197141Shrs } else { 146197141Shrs warnmsg(LOG_WARNING, __func__, 147197141Shrs "%s does not accept Router Advertisement.", name); 148197141Shrs close(s); 149197141Shrs return(-1); 150197141Shrs } 151197141Shrs } 152197141Shrs close(s); 153197141Shrs 15462632Skris llflag = get_llflag(name); 15562632Skris if (llflag < 0) { 156118660Sume warnmsg(LOG_WARNING, __func__, 157118664Sume "get_llflag() failed, anyway I'll try"); 15855163Sshin return 0; 15955163Sshin } 16055163Sshin 16162632Skris if (!(llflag & IN6_IFF_NOTREADY)) { 162118664Sume warnmsg(LOG_DEBUG, __func__, "%s is ready", name); 16355163Sshin return(0); 16462632Skris } else { 16562632Skris if (llflag & IN6_IFF_TENTATIVE) { 166118660Sume warnmsg(LOG_DEBUG, __func__, "%s is tentative", 167118664Sume name); 16855163Sshin return IFS_TENTATIVE; 16955163Sshin } 17062632Skris if (llflag & IN6_IFF_DUPLICATED) 171118660Sume warnmsg(LOG_DEBUG, __func__, "%s is duplicated", 172118664Sume name); 17355163Sshin return -1; 17455163Sshin } 17555163Sshin} 17655163Sshin 17755163Sshinint 17855163Sshininterface_status(struct ifinfo *ifinfo) 17955163Sshin{ 18055163Sshin char *ifname = ifinfo->ifname; 18155163Sshin struct ifreq ifr; 18255163Sshin struct ifmediareq ifmr; 183118664Sume 18455163Sshin /* get interface flags */ 18555163Sshin memset(&ifr, 0, sizeof(ifr)); 186119027Sume strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 18755163Sshin if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 188118660Sume warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s", 189118664Sume ifname, strerror(errno)); 19055163Sshin return(-1); 19155163Sshin } 19255163Sshin /* 19355163Sshin * if one of UP and RUNNING flags is dropped, 19455163Sshin * the interface is not active. 19555163Sshin */ 19655163Sshin if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 19755163Sshin goto inactive; 19855163Sshin } 19955163Sshin 20055163Sshin /* Next, check carrier on the interface, if possible */ 20155163Sshin if (!ifinfo->mediareqok) 20255163Sshin goto active; 20355163Sshin memset(&ifmr, 0, sizeof(ifmr)); 204119027Sume strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 20555163Sshin 20655163Sshin if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 20755163Sshin if (errno != EINVAL) { 208118660Sume warnmsg(LOG_DEBUG, __func__, 209118664Sume "ioctl(SIOCGIFMEDIA) on %s: %s", 210118664Sume ifname, strerror(errno)); 21155163Sshin return(-1); 21255163Sshin } 21355163Sshin /* 21455163Sshin * EINVAL simply means that the interface does not support 21555163Sshin * the SIOCGIFMEDIA ioctl. We regard it alive. 21655163Sshin */ 21755163Sshin ifinfo->mediareqok = 0; 21855163Sshin goto active; 21955163Sshin } 22055163Sshin 22155163Sshin if (ifmr.ifm_status & IFM_AVALID) { 222118664Sume switch (ifmr.ifm_active & IFM_NMASK) { 223118664Sume case IFM_ETHER: 224118998Sume case IFM_IEEE80211: 225118664Sume if (ifmr.ifm_status & IFM_ACTIVE) 226118664Sume goto active; 227118664Sume else 228118664Sume goto inactive; 229118664Sume break; 230118664Sume default: 231118664Sume goto inactive; 23255163Sshin } 23355163Sshin } 23455163Sshin 23555163Sshin inactive: 23655163Sshin return(0); 23755163Sshin 23855163Sshin active: 23955163Sshin return(1); 24055163Sshin} 24155163Sshin 24262632Skris#define ROUNDUP(a, size) \ 24355163Sshin (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 24455163Sshin 24562632Skris#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ 24655163Sshin ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ 247118664Sume sizeof(u_long)) : sizeof(u_long))) 24862632Skris#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 24955163Sshin 25055163Sshinint 25155163Sshinlladdropt_length(struct sockaddr_dl *sdl) 25255163Sshin{ 253118664Sume switch (sdl->sdl_type) { 254118664Sume case IFT_ETHER: 25578064Sume#ifdef IFT_IEEE80211 25678064Sume case IFT_IEEE80211: 25778064Sume#endif 258118664Sume return(ROUNDUP8(ETHER_ADDR_LEN + 2)); 259118664Sume default: 260118664Sume return(0); 26155163Sshin } 26255163Sshin} 26355163Sshin 26455163Sshinvoid 26555163Sshinlladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 26655163Sshin{ 26755163Sshin char *addr; 26855163Sshin 26955163Sshin ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 27055163Sshin 271118664Sume switch (sdl->sdl_type) { 272118664Sume case IFT_ETHER: 27378064Sume#ifdef IFT_IEEE80211 27478064Sume case IFT_IEEE80211: 27578064Sume#endif 276118664Sume ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 277118664Sume addr = (char *)(ndopt + 1); 278118664Sume memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 279118664Sume break; 280118664Sume default: 281118664Sume warnmsg(LOG_ERR, __func__, 282118664Sume "unsupported link type(%d)", sdl->sdl_type); 283118664Sume exit(1); 28455163Sshin } 28555163Sshin 28655163Sshin return; 28755163Sshin} 28855163Sshin 28955163Sshinstruct sockaddr_dl * 29055163Sshinif_nametosdl(char *name) 29155163Sshin{ 29255163Sshin int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; 29355163Sshin char *buf, *next, *lim; 29455163Sshin size_t len; 29555163Sshin struct if_msghdr *ifm; 29655163Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 29755163Sshin struct sockaddr_dl *sdl = NULL, *ret_sdl; 29855163Sshin 29955163Sshin if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 30055163Sshin return(NULL); 30155163Sshin if ((buf = malloc(len)) == NULL) 30255163Sshin return(NULL); 30355163Sshin if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 30455163Sshin free(buf); 30555163Sshin return(NULL); 30655163Sshin } 30755163Sshin 30855163Sshin lim = buf + len; 30955163Sshin for (next = buf; next < lim; next += ifm->ifm_msglen) { 31055163Sshin ifm = (struct if_msghdr *)next; 31155163Sshin if (ifm->ifm_type == RTM_IFINFO) { 31255163Sshin sa = (struct sockaddr *)(ifm + 1); 31355163Sshin get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 31455163Sshin if ((sa = rti_info[RTAX_IFP]) != NULL) { 31555163Sshin if (sa->sa_family == AF_LINK) { 31655163Sshin sdl = (struct sockaddr_dl *)sa; 31762632Skris if (strlen(name) != sdl->sdl_nlen) 31862632Skris continue; /* not same len */ 31955163Sshin if (strncmp(&sdl->sdl_data[0], 32055163Sshin name, 32155163Sshin sdl->sdl_nlen) == 0) { 32255163Sshin break; 32355163Sshin } 32455163Sshin } 32555163Sshin } 32655163Sshin } 32755163Sshin } 32855163Sshin if (next == lim) { 32955163Sshin /* search failed */ 33055163Sshin free(buf); 33155163Sshin return(NULL); 33255163Sshin } 33355163Sshin 334157108Ssuz if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) { 335157108Ssuz free(buf); 33655163Sshin return(NULL); 337157108Ssuz } 33855163Sshin memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); 33955163Sshin 34078064Sume free(buf); 34155163Sshin return(ret_sdl); 34255163Sshin} 34355163Sshin 34455163Sshinint 34555163Sshingetinet6sysctl(int code) 34655163Sshin{ 34755163Sshin int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 34855163Sshin int value; 34955163Sshin size_t size; 35055163Sshin 35155163Sshin mib[3] = code; 35255163Sshin size = sizeof(value); 35355163Sshin if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0) 35455163Sshin return -1; 35555163Sshin else 35655163Sshin return value; 35755163Sshin} 35855163Sshin 359124525Sumeint 360124525Sumesetinet6sysctl(int code, int newval) 361124525Sume{ 362124525Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 363124525Sume int value; 364124525Sume size_t size; 365124525Sume 366124525Sume mib[3] = code; 367124525Sume size = sizeof(value); 368124525Sume if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, 369124525Sume &newval, sizeof(newval)) < 0) 370124525Sume return -1; 371124525Sume else 372124525Sume return value; 373124525Sume} 374124525Sume 37555163Sshin/*------------------------------------------------------------*/ 37655163Sshin 37762632Skris/* get ia6_flags for link-local addr on if. returns -1 on error. */ 37855163Sshinstatic int 37962632Skrisget_llflag(const char *name) 38055163Sshin{ 38162632Skris struct ifaddrs *ifap, *ifa; 38262632Skris struct in6_ifreq ifr6; 38362632Skris struct sockaddr_in6 *sin6; 38462632Skris int s; 38555163Sshin 38662632Skris if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { 387118660Sume warnmsg(LOG_ERR, __func__, "socket(SOCK_DGRAM): %s", 38862632Skris strerror(errno)); 38955163Sshin exit(1); 39055163Sshin } 39162632Skris if (getifaddrs(&ifap) != 0) { 392118664Sume warnmsg(LOG_ERR, __func__, "getifaddrs: %s", 39362632Skris strerror(errno)); 39462632Skris exit(1); 39555163Sshin } 39662632Skris 39762632Skris for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 398118664Sume if (strlen(ifa->ifa_name) != strlen(name) || 399118664Sume strncmp(ifa->ifa_name, name, strlen(name)) != 0) 40062632Skris continue; 40162632Skris if (ifa->ifa_addr->sa_family != AF_INET6) 40262632Skris continue; 40362632Skris sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 40462632Skris if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 40562632Skris continue; 40662632Skris 40762632Skris memset(&ifr6, 0, sizeof(ifr6)); 408119027Sume strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 40962632Skris memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); 41062632Skris if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 411118660Sume warnmsg(LOG_ERR, __func__, 41262632Skris "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); 41362632Skris exit(1); 41462632Skris } 41562632Skris 41662632Skris freeifaddrs(ifap); 41762632Skris close(s); 41862632Skris return ifr6.ifr_ifru.ifru_flags6; 41955163Sshin } 42062632Skris 42162632Skris freeifaddrs(ifap); 42262632Skris close(s); 42362632Skris return -1; 42455163Sshin} 42555163Sshin 426118664Sume 42755163Sshinstatic void 42855163Sshinget_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 42955163Sshin{ 43055163Sshin int i; 431118664Sume 43255163Sshin for (i = 0; i < RTAX_MAX; i++) { 43355163Sshin if (addrs & (1 << i)) { 43455163Sshin rti_info[i] = sa; 43555163Sshin NEXT_SA(sa); 436118664Sume } else 43755163Sshin rti_info[i] = NULL; 43855163Sshin } 43955163Sshin} 440