if.c revision 222732
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 222732 2011-06-06 03:06:43Z 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; 8555163Sshin 86197141Shrs memset(&ifr, 0, sizeof(ifr)); 87119027Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 88197141Shrs memset(&nd, 0, sizeof(nd)); 89197141Shrs strlcpy(nd.ifname, name, sizeof(nd.ifname)); 9055163Sshin 9155163Sshin if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 92118660Sume warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s", 93118664Sume strerror(errno)); 94222732Shrs return (-1); 9555163Sshin } 9655163Sshin if (!(ifr.ifr_flags & IFF_UP)) { 9755163Sshin ifr.ifr_flags |= IFF_UP; 98118664Sume if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) 99118660Sume warnmsg(LOG_ERR, __func__, 100118664Sume "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); 101222732Shrs return (-1); 10255163Sshin } 103197141Shrs if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 104197141Shrs warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s", 105197141Shrs strerror(errno)); 106222732Shrs return (-1); 107197141Shrs } 108197141Shrs if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 109197141Shrs warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s", 110197141Shrs strerror(errno)); 111197141Shrs close(s); 112222732Shrs return (-1); 113197141Shrs } 11455163Sshin 115118660Sume warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name); 11655163Sshin 117197141Shrs if (nd.ndi.flags & ND6_IFF_IFDISABLED) { 118197141Shrs if (Fflag) { 119197141Shrs nd.ndi.flags &= ~ND6_IFF_IFDISABLED; 120197141Shrs if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 121197141Shrs warnmsg(LOG_WARNING, __func__, 122197141Shrs "ioctl(SIOCSIFINFO_IN6): %s", 123197141Shrs strerror(errno)); 124197141Shrs close(s); 125222732Shrs return (-1); 126197141Shrs } 127197141Shrs } else { 128197141Shrs warnmsg(LOG_WARNING, __func__, 129197141Shrs "%s is disabled.", name); 130197141Shrs close(s); 131222732Shrs return (-1); 132197141Shrs } 133197141Shrs } 134197141Shrs if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) { 135197141Shrs if (Fflag) { 136197141Shrs nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV; 137197141Shrs if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 138197141Shrs warnmsg(LOG_WARNING, __func__, 139197141Shrs "ioctl(SIOCSIFINFO_IN6): %s", 140197141Shrs strerror(errno)); 141197141Shrs close(s); 142222732Shrs return (-1); 143197141Shrs } 144197141Shrs } else { 145197141Shrs warnmsg(LOG_WARNING, __func__, 146197141Shrs "%s does not accept Router Advertisement.", name); 147197141Shrs close(s); 148222732Shrs return (-1); 149197141Shrs } 150197141Shrs } 151197141Shrs close(s); 152197141Shrs 15362632Skris llflag = get_llflag(name); 15462632Skris if (llflag < 0) { 155118660Sume warnmsg(LOG_WARNING, __func__, 156118664Sume "get_llflag() failed, anyway I'll try"); 157222732Shrs return (0); 15855163Sshin } 15955163Sshin 16062632Skris if (!(llflag & IN6_IFF_NOTREADY)) { 161118664Sume warnmsg(LOG_DEBUG, __func__, "%s is ready", name); 162222732Shrs return (0); 16362632Skris } else { 16462632Skris if (llflag & IN6_IFF_TENTATIVE) { 165118660Sume warnmsg(LOG_DEBUG, __func__, "%s is tentative", 166118664Sume name); 167222732Shrs return (IFS_TENTATIVE); 16855163Sshin } 16962632Skris if (llflag & IN6_IFF_DUPLICATED) 170118660Sume warnmsg(LOG_DEBUG, __func__, "%s is duplicated", 171118664Sume name); 172222732Shrs return (-1); 17355163Sshin } 17455163Sshin} 17555163Sshin 17655163Sshinint 17755163Sshininterface_status(struct ifinfo *ifinfo) 17855163Sshin{ 17955163Sshin char *ifname = ifinfo->ifname; 18055163Sshin struct ifreq ifr; 18155163Sshin struct ifmediareq ifmr; 182118664Sume 18355163Sshin /* get interface flags */ 18455163Sshin memset(&ifr, 0, sizeof(ifr)); 185119027Sume strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 18655163Sshin if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 187118660Sume warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s", 188118664Sume ifname, strerror(errno)); 189222732Shrs return (-1); 19055163Sshin } 19155163Sshin /* 19255163Sshin * if one of UP and RUNNING flags is dropped, 19355163Sshin * the interface is not active. 19455163Sshin */ 195222732Shrs if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 19655163Sshin goto inactive; 19755163Sshin /* Next, check carrier on the interface, if possible */ 19855163Sshin if (!ifinfo->mediareqok) 19955163Sshin goto active; 20055163Sshin memset(&ifmr, 0, sizeof(ifmr)); 201119027Sume strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 20255163Sshin 20355163Sshin if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 20455163Sshin if (errno != EINVAL) { 205118660Sume warnmsg(LOG_DEBUG, __func__, 206118664Sume "ioctl(SIOCGIFMEDIA) on %s: %s", 207118664Sume ifname, strerror(errno)); 20855163Sshin return(-1); 20955163Sshin } 21055163Sshin /* 21155163Sshin * EINVAL simply means that the interface does not support 21255163Sshin * the SIOCGIFMEDIA ioctl. We regard it alive. 21355163Sshin */ 21455163Sshin ifinfo->mediareqok = 0; 21555163Sshin goto active; 21655163Sshin } 21755163Sshin 21855163Sshin if (ifmr.ifm_status & IFM_AVALID) { 219118664Sume switch (ifmr.ifm_active & IFM_NMASK) { 220118664Sume case IFM_ETHER: 221118998Sume case IFM_IEEE80211: 222118664Sume if (ifmr.ifm_status & IFM_ACTIVE) 223118664Sume goto active; 224118664Sume else 225118664Sume goto inactive; 226118664Sume break; 227118664Sume default: 228118664Sume goto inactive; 22955163Sshin } 23055163Sshin } 23155163Sshin 23255163Sshin inactive: 233222732Shrs return (0); 23455163Sshin 23555163Sshin active: 236222732Shrs return (1); 23755163Sshin} 23855163Sshin 23962632Skris#define ROUNDUP(a, size) \ 24055163Sshin (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 24155163Sshin 24262632Skris#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ 24355163Sshin ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ 244118664Sume sizeof(u_long)) : sizeof(u_long))) 24562632Skris#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 24655163Sshin 24755163Sshinint 24855163Sshinlladdropt_length(struct sockaddr_dl *sdl) 24955163Sshin{ 250118664Sume switch (sdl->sdl_type) { 251118664Sume case IFT_ETHER: 25278064Sume#ifdef IFT_IEEE80211 25378064Sume case IFT_IEEE80211: 25478064Sume#endif 255222732Shrs return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 256118664Sume default: 257222732Shrs return (0); 25855163Sshin } 25955163Sshin} 26055163Sshin 26155163Sshinvoid 26255163Sshinlladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 26355163Sshin{ 26455163Sshin char *addr; 26555163Sshin 26655163Sshin ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 26755163Sshin 268118664Sume switch (sdl->sdl_type) { 269118664Sume case IFT_ETHER: 27078064Sume#ifdef IFT_IEEE80211 27178064Sume case IFT_IEEE80211: 27278064Sume#endif 273118664Sume ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 274118664Sume addr = (char *)(ndopt + 1); 275118664Sume memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 276118664Sume break; 277118664Sume default: 278118664Sume warnmsg(LOG_ERR, __func__, 279118664Sume "unsupported link type(%d)", sdl->sdl_type); 280118664Sume exit(1); 28155163Sshin } 28255163Sshin 28355163Sshin return; 28455163Sshin} 28555163Sshin 28655163Sshinstruct sockaddr_dl * 28755163Sshinif_nametosdl(char *name) 28855163Sshin{ 28955163Sshin int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; 29055163Sshin char *buf, *next, *lim; 29155163Sshin size_t len; 29255163Sshin struct if_msghdr *ifm; 29355163Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 29455163Sshin struct sockaddr_dl *sdl = NULL, *ret_sdl; 29555163Sshin 29655163Sshin if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 29755163Sshin return(NULL); 29855163Sshin if ((buf = malloc(len)) == NULL) 29955163Sshin return(NULL); 30055163Sshin if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 30155163Sshin free(buf); 302222732Shrs return (NULL); 30355163Sshin } 30455163Sshin 30555163Sshin lim = buf + len; 30655163Sshin for (next = buf; next < lim; next += ifm->ifm_msglen) { 30755163Sshin ifm = (struct if_msghdr *)next; 30855163Sshin if (ifm->ifm_type == RTM_IFINFO) { 30955163Sshin sa = (struct sockaddr *)(ifm + 1); 31055163Sshin get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 31155163Sshin if ((sa = rti_info[RTAX_IFP]) != NULL) { 31255163Sshin if (sa->sa_family == AF_LINK) { 31355163Sshin sdl = (struct sockaddr_dl *)sa; 31462632Skris if (strlen(name) != sdl->sdl_nlen) 31562632Skris continue; /* not same len */ 31655163Sshin if (strncmp(&sdl->sdl_data[0], 31755163Sshin name, 31855163Sshin sdl->sdl_nlen) == 0) { 31955163Sshin break; 32055163Sshin } 32155163Sshin } 32255163Sshin } 32355163Sshin } 32455163Sshin } 32555163Sshin if (next == lim) { 32655163Sshin /* search failed */ 32755163Sshin free(buf); 328222732Shrs return (NULL); 32955163Sshin } 33055163Sshin 331157108Ssuz if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) { 332157108Ssuz free(buf); 333222732Shrs return (NULL); 334157108Ssuz } 33555163Sshin memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); 33655163Sshin 33778064Sume free(buf); 338222732Shrs return (ret_sdl); 33955163Sshin} 34055163Sshin 34155163Sshinint 34255163Sshingetinet6sysctl(int code) 34355163Sshin{ 34455163Sshin int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 34555163Sshin int value; 34655163Sshin size_t size; 34755163Sshin 34855163Sshin mib[3] = code; 34955163Sshin size = sizeof(value); 35055163Sshin if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0) 351222732Shrs return (-1); 35255163Sshin else 353222732Shrs return (value); 35455163Sshin} 35555163Sshin 356124525Sumeint 357124525Sumesetinet6sysctl(int code, int newval) 358124525Sume{ 359124525Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 360124525Sume int value; 361124525Sume size_t size; 362124525Sume 363124525Sume mib[3] = code; 364124525Sume size = sizeof(value); 365124525Sume if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, 366124525Sume &newval, sizeof(newval)) < 0) 367222732Shrs return (-1); 368124525Sume else 369222732Shrs return (value); 370124525Sume} 371124525Sume 37255163Sshin/*------------------------------------------------------------*/ 37355163Sshin 37462632Skris/* get ia6_flags for link-local addr on if. returns -1 on error. */ 37555163Sshinstatic int 37662632Skrisget_llflag(const char *name) 37755163Sshin{ 37862632Skris struct ifaddrs *ifap, *ifa; 37962632Skris struct in6_ifreq ifr6; 38062632Skris struct sockaddr_in6 *sin6; 38162632Skris int s; 38255163Sshin 38362632Skris if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { 384118660Sume warnmsg(LOG_ERR, __func__, "socket(SOCK_DGRAM): %s", 38562632Skris strerror(errno)); 38655163Sshin exit(1); 38755163Sshin } 38862632Skris if (getifaddrs(&ifap) != 0) { 389118664Sume warnmsg(LOG_ERR, __func__, "getifaddrs: %s", 39062632Skris strerror(errno)); 39162632Skris exit(1); 39255163Sshin } 39362632Skris 39462632Skris for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 395118664Sume if (strlen(ifa->ifa_name) != strlen(name) || 396118664Sume strncmp(ifa->ifa_name, name, strlen(name)) != 0) 39762632Skris continue; 39862632Skris if (ifa->ifa_addr->sa_family != AF_INET6) 39962632Skris continue; 40062632Skris sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 40162632Skris if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 40262632Skris continue; 40362632Skris 40462632Skris memset(&ifr6, 0, sizeof(ifr6)); 405119027Sume strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 40662632Skris memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); 40762632Skris if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 408118660Sume warnmsg(LOG_ERR, __func__, 40962632Skris "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); 41062632Skris exit(1); 41162632Skris } 41262632Skris 41362632Skris freeifaddrs(ifap); 41462632Skris close(s); 415222732Shrs return (ifr6.ifr_ifru.ifru_flags6); 41655163Sshin } 41762632Skris 41862632Skris freeifaddrs(ifap); 41962632Skris close(s); 420222732Shrs return (-1); 42155163Sshin} 42255163Sshin 423118664Sume 42455163Sshinstatic void 42555163Sshinget_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 42655163Sshin{ 42755163Sshin int i; 428118664Sume 42955163Sshin for (i = 0; i < RTAX_MAX; i++) { 43055163Sshin if (addrs & (1 << i)) { 43155163Sshin rti_info[i] = sa; 43255163Sshin NEXT_SA(sa); 433118664Sume } else 43455163Sshin rti_info[i] = NULL; 43555163Sshin } 43655163Sshin} 437