if.c revision 157108
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 157108 2006-03-24 23:59:51Z suz $ 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> 5155163Sshin 5255163Sshin#include <stdio.h> 5355163Sshin#include <unistd.h> 5455163Sshin#include <stdlib.h> 5555163Sshin#include <syslog.h> 5655163Sshin#include <string.h> 5755163Sshin#include <fcntl.h> 5855163Sshin#include <errno.h> 5955163Sshin#include <limits.h> 6062632Skris#include <ifaddrs.h> 6155163Sshin#include "rtsold.h" 6255163Sshin 6362632Skrisextern int rssock; 6455163Sshinstatic int ifsock; 6555163Sshin 66118998Sumestatic int get_llflag __P((const char *)); 67118998Sumestatic void get_rtaddrs __P((int, struct sockaddr *, struct sockaddr **)); 6855163Sshin 6955163Sshinint 70124524Sumeifinit(void) 7155163Sshin{ 7262632Skris ifsock = rssock; 7355163Sshin 7455163Sshin return(0); 7555163Sshin} 7655163Sshin 7755163Sshinint 7855163Sshininterface_up(char *name) 7955163Sshin{ 8055163Sshin struct ifreq ifr; 8162632Skris int llflag; 8255163Sshin 83119027Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 8455163Sshin 8555163Sshin if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 86118660Sume warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s", 87118664Sume strerror(errno)); 8855163Sshin return(-1); 8955163Sshin } 9055163Sshin if (!(ifr.ifr_flags & IFF_UP)) { 9155163Sshin ifr.ifr_flags |= IFF_UP; 92118664Sume if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) 93118660Sume warnmsg(LOG_ERR, __func__, 94118664Sume "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); 9555163Sshin return(-1); 9655163Sshin } 9755163Sshin 98118660Sume warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name); 9955163Sshin 10062632Skris llflag = get_llflag(name); 10162632Skris if (llflag < 0) { 102118660Sume warnmsg(LOG_WARNING, __func__, 103118664Sume "get_llflag() failed, anyway I'll try"); 10455163Sshin return 0; 10555163Sshin } 10655163Sshin 10762632Skris if (!(llflag & IN6_IFF_NOTREADY)) { 108118664Sume warnmsg(LOG_DEBUG, __func__, "%s is ready", name); 10955163Sshin return(0); 11062632Skris } else { 11162632Skris if (llflag & IN6_IFF_TENTATIVE) { 112118660Sume warnmsg(LOG_DEBUG, __func__, "%s is tentative", 113118664Sume name); 11455163Sshin return IFS_TENTATIVE; 11555163Sshin } 11662632Skris if (llflag & IN6_IFF_DUPLICATED) 117118660Sume warnmsg(LOG_DEBUG, __func__, "%s is duplicated", 118118664Sume name); 11955163Sshin return -1; 12055163Sshin } 12155163Sshin} 12255163Sshin 12355163Sshinint 12455163Sshininterface_status(struct ifinfo *ifinfo) 12555163Sshin{ 12655163Sshin char *ifname = ifinfo->ifname; 12755163Sshin struct ifreq ifr; 12855163Sshin struct ifmediareq ifmr; 129118664Sume 13055163Sshin /* get interface flags */ 13155163Sshin memset(&ifr, 0, sizeof(ifr)); 132119027Sume strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 13355163Sshin if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 134118660Sume warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s", 135118664Sume ifname, strerror(errno)); 13655163Sshin return(-1); 13755163Sshin } 13855163Sshin /* 13955163Sshin * if one of UP and RUNNING flags is dropped, 14055163Sshin * the interface is not active. 14155163Sshin */ 14255163Sshin if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 14355163Sshin goto inactive; 14455163Sshin } 14555163Sshin 14655163Sshin /* Next, check carrier on the interface, if possible */ 14755163Sshin if (!ifinfo->mediareqok) 14855163Sshin goto active; 14955163Sshin memset(&ifmr, 0, sizeof(ifmr)); 150119027Sume strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 15155163Sshin 15255163Sshin if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 15355163Sshin if (errno != EINVAL) { 154118660Sume warnmsg(LOG_DEBUG, __func__, 155118664Sume "ioctl(SIOCGIFMEDIA) on %s: %s", 156118664Sume ifname, strerror(errno)); 15755163Sshin return(-1); 15855163Sshin } 15955163Sshin /* 16055163Sshin * EINVAL simply means that the interface does not support 16155163Sshin * the SIOCGIFMEDIA ioctl. We regard it alive. 16255163Sshin */ 16355163Sshin ifinfo->mediareqok = 0; 16455163Sshin goto active; 16555163Sshin } 16655163Sshin 16755163Sshin if (ifmr.ifm_status & IFM_AVALID) { 168118664Sume switch (ifmr.ifm_active & IFM_NMASK) { 169118664Sume case IFM_ETHER: 170118998Sume case IFM_IEEE80211: 171118664Sume if (ifmr.ifm_status & IFM_ACTIVE) 172118664Sume goto active; 173118664Sume else 174118664Sume goto inactive; 175118664Sume break; 176118664Sume default: 177118664Sume goto inactive; 17855163Sshin } 17955163Sshin } 18055163Sshin 18155163Sshin inactive: 18255163Sshin return(0); 18355163Sshin 18455163Sshin active: 18555163Sshin return(1); 18655163Sshin} 18755163Sshin 18862632Skris#define ROUNDUP(a, size) \ 18955163Sshin (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 19055163Sshin 19162632Skris#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ 19255163Sshin ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ 193118664Sume sizeof(u_long)) : sizeof(u_long))) 19462632Skris#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 19555163Sshin 19655163Sshinint 19755163Sshinlladdropt_length(struct sockaddr_dl *sdl) 19855163Sshin{ 199118664Sume switch (sdl->sdl_type) { 200118664Sume case IFT_ETHER: 20178064Sume#ifdef IFT_IEEE80211 20278064Sume case IFT_IEEE80211: 20378064Sume#endif 204118664Sume return(ROUNDUP8(ETHER_ADDR_LEN + 2)); 205118664Sume default: 206118664Sume return(0); 20755163Sshin } 20855163Sshin} 20955163Sshin 21055163Sshinvoid 21155163Sshinlladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 21255163Sshin{ 21355163Sshin char *addr; 21455163Sshin 21555163Sshin ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 21655163Sshin 217118664Sume switch (sdl->sdl_type) { 218118664Sume case IFT_ETHER: 21978064Sume#ifdef IFT_IEEE80211 22078064Sume case IFT_IEEE80211: 22178064Sume#endif 222118664Sume ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 223118664Sume addr = (char *)(ndopt + 1); 224118664Sume memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 225118664Sume break; 226118664Sume default: 227118664Sume warnmsg(LOG_ERR, __func__, 228118664Sume "unsupported link type(%d)", sdl->sdl_type); 229118664Sume exit(1); 23055163Sshin } 23155163Sshin 23255163Sshin return; 23355163Sshin} 23455163Sshin 23555163Sshinstruct sockaddr_dl * 23655163Sshinif_nametosdl(char *name) 23755163Sshin{ 23855163Sshin int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; 23955163Sshin char *buf, *next, *lim; 24055163Sshin size_t len; 24155163Sshin struct if_msghdr *ifm; 24255163Sshin struct sockaddr *sa, *rti_info[RTAX_MAX]; 24355163Sshin struct sockaddr_dl *sdl = NULL, *ret_sdl; 24455163Sshin 24555163Sshin if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 24655163Sshin return(NULL); 24755163Sshin if ((buf = malloc(len)) == NULL) 24855163Sshin return(NULL); 24955163Sshin if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 25055163Sshin free(buf); 25155163Sshin return(NULL); 25255163Sshin } 25355163Sshin 25455163Sshin lim = buf + len; 25555163Sshin for (next = buf; next < lim; next += ifm->ifm_msglen) { 25655163Sshin ifm = (struct if_msghdr *)next; 25755163Sshin if (ifm->ifm_type == RTM_IFINFO) { 25855163Sshin sa = (struct sockaddr *)(ifm + 1); 25955163Sshin get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 26055163Sshin if ((sa = rti_info[RTAX_IFP]) != NULL) { 26155163Sshin if (sa->sa_family == AF_LINK) { 26255163Sshin sdl = (struct sockaddr_dl *)sa; 26362632Skris if (strlen(name) != sdl->sdl_nlen) 26462632Skris continue; /* not same len */ 26555163Sshin if (strncmp(&sdl->sdl_data[0], 26655163Sshin name, 26755163Sshin sdl->sdl_nlen) == 0) { 26855163Sshin break; 26955163Sshin } 27055163Sshin } 27155163Sshin } 27255163Sshin } 27355163Sshin } 27455163Sshin if (next == lim) { 27555163Sshin /* search failed */ 27655163Sshin free(buf); 27755163Sshin return(NULL); 27855163Sshin } 27955163Sshin 280157108Ssuz if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) { 281157108Ssuz free(buf); 28255163Sshin return(NULL); 283157108Ssuz } 28455163Sshin memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); 28555163Sshin 28678064Sume free(buf); 28755163Sshin return(ret_sdl); 28855163Sshin} 28955163Sshin 29055163Sshinint 29155163Sshingetinet6sysctl(int code) 29255163Sshin{ 29355163Sshin int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 29455163Sshin int value; 29555163Sshin size_t size; 29655163Sshin 29755163Sshin mib[3] = code; 29855163Sshin size = sizeof(value); 29955163Sshin if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0) 30055163Sshin return -1; 30155163Sshin else 30255163Sshin return value; 30355163Sshin} 30455163Sshin 305124525Sumeint 306124525Sumesetinet6sysctl(int code, int newval) 307124525Sume{ 308124525Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 309124525Sume int value; 310124525Sume size_t size; 311124525Sume 312124525Sume mib[3] = code; 313124525Sume size = sizeof(value); 314124525Sume if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, 315124525Sume &newval, sizeof(newval)) < 0) 316124525Sume return -1; 317124525Sume else 318124525Sume return value; 319124525Sume} 320124525Sume 32155163Sshin/*------------------------------------------------------------*/ 32255163Sshin 32362632Skris/* get ia6_flags for link-local addr on if. returns -1 on error. */ 32455163Sshinstatic int 32562632Skrisget_llflag(const char *name) 32655163Sshin{ 32762632Skris struct ifaddrs *ifap, *ifa; 32862632Skris struct in6_ifreq ifr6; 32962632Skris struct sockaddr_in6 *sin6; 33062632Skris int s; 33155163Sshin 33262632Skris if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { 333118660Sume warnmsg(LOG_ERR, __func__, "socket(SOCK_DGRAM): %s", 33462632Skris strerror(errno)); 33555163Sshin exit(1); 33655163Sshin } 33762632Skris if (getifaddrs(&ifap) != 0) { 338118664Sume warnmsg(LOG_ERR, __func__, "getifaddrs: %s", 33962632Skris strerror(errno)); 34062632Skris exit(1); 34155163Sshin } 34262632Skris 34362632Skris for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 344118664Sume if (strlen(ifa->ifa_name) != strlen(name) || 345118664Sume strncmp(ifa->ifa_name, name, strlen(name)) != 0) 34662632Skris continue; 34762632Skris if (ifa->ifa_addr->sa_family != AF_INET6) 34862632Skris continue; 34962632Skris sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 35062632Skris if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 35162632Skris continue; 35262632Skris 35362632Skris memset(&ifr6, 0, sizeof(ifr6)); 354119027Sume strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 35562632Skris memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); 35662632Skris if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 357118660Sume warnmsg(LOG_ERR, __func__, 35862632Skris "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); 35962632Skris exit(1); 36062632Skris } 36162632Skris 36262632Skris freeifaddrs(ifap); 36362632Skris close(s); 36462632Skris return ifr6.ifr_ifru.ifru_flags6; 36555163Sshin } 36662632Skris 36762632Skris freeifaddrs(ifap); 36862632Skris close(s); 36962632Skris return -1; 37055163Sshin} 37155163Sshin 372118664Sume 37355163Sshinstatic void 37455163Sshinget_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 37555163Sshin{ 37655163Sshin int i; 377118664Sume 37855163Sshin for (i = 0; i < RTAX_MAX; i++) { 37955163Sshin if (addrs & (1 << i)) { 38055163Sshin rti_info[i] = sa; 38155163Sshin NEXT_SA(sa); 382118664Sume } else 38355163Sshin rti_info[i] = NULL; 38455163Sshin } 38555163Sshin} 386