route6d.c revision 119040
162607Sitojun/* $FreeBSD: head/usr.sbin/route6d/route6d.c 119040 2003-08-17 17:47:22Z ume $ */ 278064Sume/* $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $ */ 355163Sshin 455163Sshin/* 555163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 655163Sshin * All rights reserved. 762607Sitojun * 855163Sshin * Redistribution and use in source and binary forms, with or without 955163Sshin * modification, are permitted provided that the following conditions 1055163Sshin * are met: 1155163Sshin * 1. Redistributions of source code must retain the above copyright 1255163Sshin * notice, this list of conditions and the following disclaimer. 1355163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1455163Sshin * notice, this list of conditions and the following disclaimer in the 1555163Sshin * documentation and/or other materials provided with the distribution. 1655163Sshin * 3. Neither the name of the project nor the names of its contributors 1755163Sshin * may be used to endorse or promote products derived from this software 1855163Sshin * without specific prior written permission. 1962607Sitojun * 2055163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2155163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2455163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2555163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2655163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2755163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2855163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2955163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3055163Sshin * SUCH DAMAGE. 3155163Sshin */ 3255163Sshin 3355163Sshin#ifndef lint 3478064Sumestatic char _rcsid[] = "$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $"; 3555163Sshin#endif 3655163Sshin 3755163Sshin#include <stdio.h> 3855163Sshin 3955163Sshin#include <time.h> 4055163Sshin#include <unistd.h> 4155163Sshin#include <stdlib.h> 4255163Sshin#include <string.h> 4355163Sshin#include <signal.h> 4455163Sshin#ifdef __STDC__ 4555163Sshin#include <stdarg.h> 4655163Sshin#else 4755163Sshin#include <varargs.h> 4855163Sshin#endif 4955163Sshin#include <syslog.h> 5055163Sshin#include <stddef.h> 5162607Sitojun#include <errno.h> 5255163Sshin#include <err.h> 5355163Sshin 5455163Sshin#include <sys/types.h> 5555163Sshin#include <sys/param.h> 5655163Sshin#include <sys/file.h> 5755163Sshin#include <sys/socket.h> 5855163Sshin#include <sys/ioctl.h> 5955163Sshin#include <sys/sysctl.h> 6055163Sshin#include <sys/uio.h> 6155163Sshin#include <net/if.h> 6262607Sitojun#if defined(__FreeBSD__) && __FreeBSD__ >= 3 6355163Sshin#include <net/if_var.h> 6462607Sitojun#endif /* __FreeBSD__ >= 3 */ 6562607Sitojun#define KERNEL 1 6662607Sitojun#define _KERNEL 1 6755163Sshin#include <net/route.h> 6862607Sitojun#undef KERNEL 6962607Sitojun#undef _KERNEL 7055163Sshin#include <netinet/in.h> 7155163Sshin#include <netinet/in_var.h> 7255163Sshin#include <netinet/ip6.h> 7355163Sshin#include <netinet/udp.h> 7455163Sshin#include <netdb.h> 7562607Sitojun#include <ifaddrs.h> 7655163Sshin 7755163Sshin#include <arpa/inet.h> 7855163Sshin 7955163Sshin#include "route6d.h" 8055163Sshin 8155163Sshin#define MAXFILTER 40 8255163Sshin 8355163Sshin#ifdef DEBUG 8455163Sshin#define INIT_INTERVAL6 6 8555163Sshin#else 86119039Sume#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest */ 8755163Sshin#endif 8855163Sshin 8955163Sshin/* alignment constraint for routing socket */ 9062607Sitojun#define ROUNDUP(a) \ 9155163Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 9262607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 9355163Sshin 9455163Sshin/* 9555163Sshin * Following two macros are highly depending on KAME Release 9655163Sshin */ 9755163Sshin#define IN6_LINKLOCAL_IFINDEX(addr) \ 9855163Sshin ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 9955163Sshin 10055163Sshin#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 10155163Sshin do { \ 10255163Sshin (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 10355163Sshin (addr).s6_addr[3] = (index) & 0xff; \ 10455163Sshin } while (0) 10555163Sshin 10655163Sshinstruct ifc { /* Configuration of an interface */ 10755163Sshin char *ifc_name; /* if name */ 10855163Sshin struct ifc *ifc_next; 10955163Sshin int ifc_index; /* if index */ 11055163Sshin int ifc_mtu; /* if mtu */ 11155163Sshin int ifc_metric; /* if metric */ 11278064Sume u_int ifc_flags; /* flags */ 11378064Sume short ifc_cflags; /* IFC_XXX */ 11455163Sshin struct in6_addr ifc_mylladdr; /* my link-local address */ 11555163Sshin struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 11655163Sshin struct iff *ifc_filter; /* filter structure */ 11755163Sshin struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 11855163Sshin int ifc_joined; /* joined to ff02::9 */ 11955163Sshin}; 12055163Sshin 12162607Sitojunstruct ifac { /* Adddress associated to an interface */ 12255163Sshin struct ifc *ifa_conf; /* back pointer */ 12355163Sshin struct ifac *ifa_next; 12455163Sshin struct in6_addr ifa_addr; /* address */ 12555163Sshin struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 12655163Sshin int ifa_plen; /* prefix length */ 12755163Sshin}; 12855163Sshin 12955163Sshinstruct iff { 13055163Sshin int iff_type; 13155163Sshin struct in6_addr iff_addr; 13255163Sshin int iff_plen; 13355163Sshin struct iff *iff_next; 13455163Sshin}; 13555163Sshin 13655163Sshinstruct ifc *ifc; 13755163Sshinint nifc; /* number of valid ifc's */ 13855163Sshinstruct ifc **index2ifc; 13955163Sshinint nindex2ifc; 14055163Sshinstruct ifc *loopifcp = NULL; /* pointing to loopback */ 14155163Sshinfd_set sockvec; /* vector to select() for receiving */ 14255163Sshinint rtsock; /* the routing socket */ 14355163Sshinint ripsock; /* socket to send/receive RIP datagram */ 14455163Sshin 14555163Sshinstruct rip6 *ripbuf; /* packet buffer for sending */ 14655163Sshin 14755163Sshin/* 14878064Sume * Maintain the routes in a linked list. When the number of the routes 14955163Sshin * grows, somebody would like to introduce a hash based or a radix tree 15078064Sume * based structure. I believe the number of routes handled by RIP is 15155163Sshin * limited and I don't have to manage a complex data structure, however. 15255163Sshin * 15355163Sshin * One of the major drawbacks of the linear linked list is the difficulty 15478064Sume * of representing the relationship between a couple of routes. This may 15555163Sshin * be a significant problem when we have to support route aggregation with 15655163Sshin * supressing the specifices covered by the aggregate. 15755163Sshin */ 15855163Sshin 15955163Sshinstruct riprt { 16055163Sshin struct riprt *rrt_next; /* next destination */ 16155163Sshin struct riprt *rrt_same; /* same destination - future use */ 16255163Sshin struct netinfo6 rrt_info; /* network info */ 16355163Sshin struct in6_addr rrt_gw; /* gateway */ 16462607Sitojun u_long rrt_flags; /* kernel routing table flags */ 16562607Sitojun u_long rrt_rflags; /* route6d routing table flags */ 16655163Sshin time_t rrt_t; /* when the route validated */ 16755163Sshin int rrt_index; /* ifindex from which this route got */ 16855163Sshin}; 16955163Sshin 17055163Sshinstruct riprt *riprt = 0; 17155163Sshin 17255163Sshinint dflag = 0; /* debug flag */ 17355163Sshinint qflag = 0; /* quiet flag */ 17455163Sshinint nflag = 0; /* don't update kernel routing table */ 17555163Sshinint aflag = 0; /* age out even the statically defined routes */ 17655163Sshinint hflag = 0; /* don't split horizon */ 17755163Sshinint lflag = 0; /* exchange site local routes */ 17855163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 17955163Sshinint Sflag = 0; /* announce static routes to every interface */ 18062607Sitojununsigned long routetag = 0; /* route tag attached on originating case */ 18155163Sshin 18255163Sshinchar *filter[MAXFILTER]; 18355163Sshinint filtertype[MAXFILTER]; 18455163Sshinint nfilter = 0; 18555163Sshin 18655163Sshinpid_t pid; 18755163Sshin 18855163Sshinstruct sockaddr_storage ripsin; 18955163Sshin 19055163Sshinstruct rtentry rtentry; 19155163Sshin 19255163Sshinint interval = 1; 19355163Sshintime_t nextalarm = 0; 19455163Sshintime_t sup_trig_update = 0; 19555163Sshin 19655163SshinFILE *rtlog = NULL; 19755163Sshin 19855163Sshinint logopened = 0; 19955163Sshin 20055163Sshinstatic u_long seq = 0; 20155163Sshin 20278064Sumevolatile int signo; 20378064Sumevolatile sig_atomic_t seenalrm; 20478064Sumevolatile sig_atomic_t seenquit; 20578064Sumevolatile sig_atomic_t seenusr1; 20678064Sume 20762607Sitojun#define RRTF_AGGREGATE 0x08000000 20862607Sitojun#define RRTF_NOADVERTISE 0x10000000 20962607Sitojun#define RRTF_NH_NOT_LLADDR 0x20000000 21062607Sitojun#define RRTF_SENDANYWAY 0x40000000 21162607Sitojun#define RRTF_CHANGED 0x80000000 21255163Sshin 21355163Sshinint main __P((int, char **)); 21478064Sumevoid sighandler __P((int)); 21578064Sumevoid ripalarm __P((void)); 21655163Sshinvoid riprecv __P((void)); 21755163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); 21878064Sumeint out_filter __P((struct riprt *, struct ifc *)); 21955163Sshinvoid init __P((void)); 22055163Sshinvoid sockopt __P((struct ifc *)); 22155163Sshinvoid ifconfig __P((void)); 22262607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int)); 22355163Sshinvoid rtrecv __P((void)); 22455163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *, 22555163Sshin const struct sockaddr_in6 *)); 22655163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, 22755163Sshin const struct sockaddr_in6 *)); 22855163Sshinvoid filterconfig __P((void)); 22955163Sshinint getifmtu __P((int)); 23078064Sumeconst char *rttypes __P((struct rt_msghdr *)); 23178064Sumeconst char *rtflags __P((struct rt_msghdr *)); 23278064Sumeconst char *ifflags __P((int)); 23378064Sumeint ifrt __P((struct ifc *, int)); 23462607Sitojunvoid ifrt_p2p __P((struct ifc *, int)); 23555163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *)); 23655163Sshinvoid applyplen __P((struct in6_addr *, int)); 23755163Sshinvoid ifrtdump __P((int)); 23855163Sshinvoid ifdump __P((int)); 23955163Sshinvoid ifdump0 __P((FILE *, const struct ifc *)); 24055163Sshinvoid rtdump __P((int)); 24155163Sshinvoid rt_entry __P((struct rt_msghdr *, int)); 24278064Sumevoid rtdexit __P((void)); 24378064Sumevoid riprequest __P((struct ifc *, struct netinfo6 *, int, 24478064Sume struct sockaddr_in6 *)); 24555163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *)); 24655163Sshinvoid sendrequest __P((struct ifc *)); 24778064Sumeint sin6mask2len __P((const struct sockaddr_in6 *)); 24855163Sshinint mask2len __P((const struct in6_addr *, int)); 24955163Sshinint sendpacket __P((struct sockaddr_in6 *, int)); 25055163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); 25155163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *)); 25255163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *)); 25355163Sshinvoid krtread __P((int)); 25455163Sshinint tobeadv __P((struct riprt *, struct ifc *)); 25555163Sshinchar *allocopy __P((char *)); 25655163Sshinchar *hms __P((void)); 25755163Sshinconst char *inet6_n2p __P((const struct in6_addr *)); 25855163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); 25955163Sshinstruct in6_addr *plen2mask __P((int)); 26078064Sumestruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **)); 26155163Sshinint ripinterval __P((int)); 26255163Sshintime_t ripsuptrig __P((void)); 26366807Skrisvoid fatal __P((const char *, ...)) 26466807Skris __attribute__((__format__(__printf__, 1, 2))); 26566807Skrisvoid trace __P((int, const char *, ...)) 26666807Skris __attribute__((__format__(__printf__, 2, 3))); 26766807Skrisvoid tracet __P((int, const char *, ...)) 26866807Skris __attribute__((__format__(__printf__, 2, 3))); 26955163Sshinunsigned int if_maxindex __P((void)); 27055163Sshinstruct ifc *ifc_find __P((char *)); 27155163Sshinstruct iff *iff_find __P((struct ifc *, int)); 27255163Sshinvoid setindex2ifc __P((int, struct ifc *)); 27355163Sshin 27455163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 27555163Sshin 27655163Sshinint 27755163Sshinmain(argc, argv) 27855163Sshin int argc; 27955163Sshin char **argv; 28055163Sshin{ 28155163Sshin int ch; 28255163Sshin int error = 0; 28355163Sshin struct ifc *ifcp; 28455163Sshin sigset_t mask, omask; 28555163Sshin FILE *pidfile; 28655163Sshin char *progname; 28762607Sitojun char *ep; 28855163Sshin 28955163Sshin progname = strrchr(*argv, '/'); 29055163Sshin if (progname) 29155163Sshin progname++; 29255163Sshin else 29355163Sshin progname = *argv; 29455163Sshin 29555163Sshin pid = getpid(); 29678064Sume while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { 29755163Sshin switch (ch) { 29855163Sshin case 'A': 29955163Sshin case 'N': 30055163Sshin case 'O': 30155163Sshin case 'T': 30255163Sshin case 'L': 30362607Sitojun if (nfilter >= MAXFILTER) { 30455163Sshin fatal("Exceeds MAXFILTER"); 30562607Sitojun /*NOTREACHED*/ 30662607Sitojun } 30755163Sshin filtertype[nfilter] = ch; 30855163Sshin filter[nfilter++] = allocopy(optarg); 30955163Sshin break; 31055163Sshin case 't': 31162607Sitojun ep = NULL; 31262607Sitojun routetag = strtoul(optarg, &ep, 0); 31362607Sitojun if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 31455163Sshin fatal("invalid route tag"); 31555163Sshin /*NOTREACHED*/ 31655163Sshin } 31755163Sshin break; 31855163Sshin case 'R': 31962607Sitojun if ((rtlog = fopen(optarg, "w")) == NULL) { 32055163Sshin fatal("Can not write to routelog"); 32162607Sitojun /*NOTREACHED*/ 32262607Sitojun } 32355163Sshin break; 32462607Sitojun#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 32562607Sitojun FLAG('a', aflag, 1); break; 32662607Sitojun FLAG('d', dflag, 1); break; 32762607Sitojun FLAG('D', dflag, 2); break; 32862607Sitojun FLAG('h', hflag, 1); break; 32962607Sitojun FLAG('l', lflag, 1); break; 33062607Sitojun FLAG('n', nflag, 1); break; 33162607Sitojun FLAG('q', qflag, 1); break; 33262607Sitojun FLAG('s', sflag, 1); break; 33362607Sitojun FLAG('S', Sflag, 1); break; 33455163Sshin#undef FLAG 33555163Sshin default: 33655163Sshin fatal("Invalid option specified, terminating"); 33762607Sitojun /*NOTREACHED*/ 33855163Sshin } 33955163Sshin } 34055163Sshin argc -= optind; 34155163Sshin argv += optind; 34278064Sume if (argc > 0) { 34355163Sshin fatal("bogus extra arguments"); 34478064Sume /*NOTREACHED*/ 34578064Sume } 34655163Sshin 34755163Sshin if (geteuid()) { 34855163Sshin nflag = 1; 34955163Sshin fprintf(stderr, "No kernel update is allowed\n"); 35055163Sshin } 351119037Sume 352119037Sume if (dflag == 0) { 353119037Sume if (daemon(0, 0) < 0) { 354119037Sume fatal("daemon"); 355119037Sume /*NOTREACHED*/ 356119037Sume } 357119037Sume } 358119037Sume 35955163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 36055163Sshin logopened++; 36178064Sume 36278064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 36378064Sume fatal("malloc"); 36478064Sume memset(ripbuf, 0, RIP6_MAXMTU); 36578064Sume ripbuf->rip6_cmd = RIP6_RESPONSE; 36678064Sume ripbuf->rip6_vers = RIP6_VERSION; 36778064Sume ripbuf->rip6_res1[0] = 0; 36878064Sume ripbuf->rip6_res1[1] = 0; 36978064Sume 37055163Sshin init(); 37155163Sshin ifconfig(); 37255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 37355163Sshin if (ifcp->ifc_index < 0) { 37455163Sshin fprintf(stderr, 37555163Sshin"No ifindex found at %s (no link-local address?)\n", 37655163Sshin ifcp->ifc_name); 37755163Sshin error++; 37855163Sshin } 37955163Sshin } 38055163Sshin if (error) 38155163Sshin exit(1); 38278064Sume if (loopifcp == NULL) { 38355163Sshin fatal("No loopback found"); 38478064Sume /*NOTREACHED*/ 38578064Sume } 386110666Sache#ifdef __FreeBSD__ 387110666Sache sranddev(); 388110666Sache#else 389110666Sache srand((unsigned)(time(NULL)^(pid<<16))); 390110666Sache#endif 39155163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 39255163Sshin ifrt(ifcp, 0); 39355163Sshin filterconfig(); 39455163Sshin krtread(0); 39555163Sshin if (dflag) 39655163Sshin ifrtdump(0); 39755163Sshin 39855163Sshin pid = getpid(); 39955163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 40055163Sshin fprintf(pidfile, "%d\n", pid); 40155163Sshin fclose(pidfile); 40255163Sshin } 40355163Sshin 40478064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 40555163Sshin fatal("malloc"); 40678064Sume /*NOTREACHED*/ 40778064Sume } 40862607Sitojun memset(ripbuf, 0, RIP6_MAXMTU); 40955163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 41055163Sshin ripbuf->rip6_vers = RIP6_VERSION; 41155163Sshin ripbuf->rip6_res1[0] = 0; 41255163Sshin ripbuf->rip6_res1[1] = 0; 41355163Sshin 41478064Sume if (signal(SIGALRM, sighandler) == SIG_ERR || 41578064Sume signal(SIGQUIT, sighandler) == SIG_ERR || 41678064Sume signal(SIGTERM, sighandler) == SIG_ERR || 41778064Sume signal(SIGUSR1, sighandler) == SIG_ERR || 41878064Sume signal(SIGHUP, sighandler) == SIG_ERR || 41978064Sume signal(SIGINT, sighandler) == SIG_ERR) { 42078064Sume fatal("signal"); 42178064Sume /*NOTREACHED*/ 42278064Sume } 42355163Sshin /* 42455163Sshin * To avoid rip packet congestion (not on a cable but in this 42555163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 42655163Sshin * packets. 42755163Sshin */ 42855163Sshin alarm(ripinterval(INIT_INTERVAL6)); 42955163Sshin 43055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 43155163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 43255163Sshin sendrequest(ifcp); 43355163Sshin } 43455163Sshin 43555163Sshin syslog(LOG_INFO, "**** Started ****"); 43655163Sshin sigemptyset(&mask); 43755163Sshin sigaddset(&mask, SIGALRM); 43855163Sshin while (1) { 43955163Sshin fd_set recvec; 44055163Sshin 44178064Sume if (seenalrm) { 44278064Sume ripalarm(); 44378064Sume seenalrm = 0; 44478064Sume continue; 44578064Sume } 44678064Sume if (seenquit) { 44778064Sume rtdexit(); 44878064Sume seenquit = 0; 44978064Sume continue; 45078064Sume } 45178064Sume if (seenusr1) { 45278064Sume ifrtdump(SIGUSR1); 45378064Sume seenusr1 = 0; 45478064Sume continue; 45578064Sume } 45678064Sume 45755163Sshin FD_COPY(&sockvec, &recvec); 45878064Sume signo = 0; 45955163Sshin switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) { 46055163Sshin case -1: 46178064Sume if (errno != EINTR) { 46278064Sume fatal("select"); 46378064Sume /*NOTREACHED*/ 46478064Sume } 46578064Sume continue; 46655163Sshin case 0: 46755163Sshin continue; 46855163Sshin default: 46955163Sshin if (FD_ISSET(ripsock, &recvec)) { 47055163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 47155163Sshin riprecv(); 47255163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 47355163Sshin } 47455163Sshin if (FD_ISSET(rtsock, &recvec)) { 47555163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 47655163Sshin rtrecv(); 47755163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 47855163Sshin } 47955163Sshin } 48055163Sshin } 48155163Sshin} 48255163Sshin 48378064Sumevoid 48478064Sumesighandler(sig) 48578064Sume int sig; 48678064Sume{ 48778064Sume 48878064Sume signo = sig; 48978064Sume switch (signo) { 49078064Sume case SIGALRM: 49178064Sume seenalrm++; 49278064Sume break; 49378064Sume case SIGQUIT: 49478064Sume case SIGTERM: 49578064Sume seenquit++; 49678064Sume break; 49778064Sume case SIGUSR1: 49878064Sume case SIGHUP: 49978064Sume case SIGINT: 50078064Sume seenusr1++; 50178064Sume break; 50278064Sume } 50378064Sume} 50478064Sume 50555163Sshin/* 50655163Sshin * gracefully exits after resetting sockopts. 50755163Sshin */ 50855163Sshin/* ARGSUSED */ 50955163Sshinvoid 51078064Sumertdexit() 51155163Sshin{ 51255163Sshin struct riprt *rrt; 51355163Sshin 51455163Sshin alarm(0); 51555163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 51662607Sitojun if (rrt->rrt_rflags & RRTF_AGGREGATE) { 51755163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 51855163Sshin } 51955163Sshin } 52055163Sshin close(ripsock); 52155163Sshin close(rtsock); 52255163Sshin syslog(LOG_INFO, "**** Terminated ****"); 52355163Sshin closelog(); 52455163Sshin exit(1); 52555163Sshin} 52655163Sshin 52755163Sshin/* 52855163Sshin * Called periodically: 52955163Sshin * 1. age out the learned route. remove it if necessary. 53055163Sshin * 2. submit RIP6_RESPONSE packets. 53178064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 53255163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the 53355163Sshin * routes more precisely. 53455163Sshin */ 53555163Sshin/* ARGSUSED */ 53655163Sshinvoid 53778064Sumeripalarm() 53855163Sshin{ 53955163Sshin struct ifc *ifcp; 54055163Sshin struct riprt *rrt, *rrt_prev, *rrt_next; 54155163Sshin time_t t_lifetime, t_holddown; 54255163Sshin 54355163Sshin /* age the RIP routes */ 54455163Sshin rrt_prev = 0; 54555163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 54655163Sshin t_holddown = t_lifetime - RIP_HOLDDOWN; 54755163Sshin for (rrt = riprt; rrt; rrt = rrt_next) { 54855163Sshin rrt_next = rrt->rrt_next; 54955163Sshin 55055163Sshin if (rrt->rrt_t == 0) { 55155163Sshin rrt_prev = rrt; 55255163Sshin continue; 55355163Sshin } 55455163Sshin if (rrt->rrt_t < t_holddown) { 55555163Sshin if (rrt_prev) { 55655163Sshin rrt_prev->rrt_next = rrt->rrt_next; 55755163Sshin } else { 55855163Sshin riprt = rrt->rrt_next; 55955163Sshin } 56055163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 56155163Sshin free(rrt); 56255163Sshin continue; 56355163Sshin } 56455163Sshin if (rrt->rrt_t < t_lifetime) 56555163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 56655163Sshin rrt_prev = rrt; 56755163Sshin } 56855163Sshin /* Supply updates */ 56955163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 57055163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 57155163Sshin ripsend(ifcp, &ifcp->ifc_ripsin, 0); 57255163Sshin } 57355163Sshin alarm(ripinterval(SUPPLY_INTERVAL6)); 57455163Sshin} 57555163Sshin 57655163Sshinvoid 57755163Sshininit() 57855163Sshin{ 579119034Sume int error; 580119034Sume const int int0 = 0, int1 = 1, int255 = 255; 58155163Sshin struct addrinfo hints, *res; 58255163Sshin char port[10]; 58355163Sshin 58455163Sshin ifc = (struct ifc *)NULL; 58555163Sshin nifc = 0; 58655163Sshin nindex2ifc = 0; /*initial guess*/ 58755163Sshin index2ifc = NULL; 58855163Sshin snprintf(port, sizeof(port), "%d", RIP6_PORT); 58955163Sshin 59055163Sshin memset(&hints, 0, sizeof(hints)); 59155163Sshin hints.ai_family = PF_INET6; 59255163Sshin hints.ai_socktype = SOCK_DGRAM; 59355163Sshin hints.ai_flags = AI_PASSIVE; 59455163Sshin error = getaddrinfo(NULL, port, &hints, &res); 59578064Sume if (error) { 59666807Skris fatal("%s", gai_strerror(error)); 59778064Sume /*NOTREACHED*/ 59878064Sume } 59978064Sume if (res->ai_next) { 60055163Sshin fatal(":: resolved to multiple address"); 60178064Sume /*NOTREACHED*/ 60278064Sume } 60355163Sshin 60455163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 60578064Sume if (ripsock < 0) { 60655163Sshin fatal("rip socket"); 60778064Sume /*NOTREACHED*/ 60878064Sume } 609119034Sume#ifdef IPV6_V6ONLY 610119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 611119034Sume &int1, sizeof(int1)) < 0) { 612119034Sume fatal("rip IPV6_V6ONLY"); 613119034Sume /*NOTREACHED*/ 614119034Sume } 615119034Sume#endif 61678064Sume if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 61755163Sshin fatal("rip bind"); 61878064Sume /*NOTREACHED*/ 61978064Sume } 62055163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 62178064Sume &int255, sizeof(int255)) < 0) { 62255163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 62378064Sume /*NOTREACHED*/ 62478064Sume } 62555163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 62678064Sume &int0, sizeof(int0)) < 0) { 62755163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 62878064Sume /*NOTREACHED*/ 62978064Sume } 63062921Sume 63162607Sitojun#ifdef IPV6_RECVPKTINFO 632119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 633119034Sume &int1, sizeof(int1)) < 0) { 63462607Sitojun fatal("rip IPV6_RECVPKTINFO"); 63578064Sume /*NOTREACHED*/ 63678064Sume } 63762607Sitojun#else /* old adv. API */ 638119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 639119034Sume &int1, sizeof(int1)) < 0) { 64055163Sshin fatal("rip IPV6_PKTINFO"); 64178064Sume /*NOTREACHED*/ 64278064Sume } 64362607Sitojun#endif 64455163Sshin 64555163Sshin memset(&hints, 0, sizeof(hints)); 64655163Sshin hints.ai_family = PF_INET6; 64755163Sshin hints.ai_socktype = SOCK_DGRAM; 64855163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 64978064Sume if (error) { 65066807Skris fatal("%s", gai_strerror(error)); 65178064Sume /*NOTREACHED*/ 65278064Sume } 65378064Sume if (res->ai_next) { 65455163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 65578064Sume /*NOTREACHED*/ 65678064Sume } 65755163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 65855163Sshin 65955163Sshin#ifdef FD_ZERO 66055163Sshin FD_ZERO(&sockvec); 66155163Sshin#else 66255163Sshin memset(&sockvec, 0, sizeof(sockvec)); 66355163Sshin#endif 66455163Sshin FD_SET(ripsock, &sockvec); 66555163Sshin 66655163Sshin if (nflag == 0) { 66778064Sume if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 66855163Sshin fatal("route socket"); 66978064Sume /*NOTREACHED*/ 67078064Sume } 67155163Sshin FD_SET(rtsock, &sockvec); 67255163Sshin } else 67355163Sshin rtsock = -1; /*just for safety */ 67455163Sshin} 67555163Sshin 67662607Sitojun#define RIPSIZE(n) \ 67762607Sitojun (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 67855163Sshin 67955163Sshin/* 68055163Sshin * ripflush flushes the rip datagram stored in the rip buffer 68155163Sshin */ 68255163Sshinstatic int nrt; 68355163Sshinstatic struct netinfo6 *np; 68455163Sshin 68555163Sshinvoid 686119031Sumeripflush(ifcp, sin6) 68755163Sshin struct ifc *ifcp; 688119031Sume struct sockaddr_in6 *sin6; 68955163Sshin{ 69055163Sshin int i; 69155163Sshin int error; 69255163Sshin 69355163Sshin if (ifcp) 69455163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 69555163Sshin ifcp->ifc_name, nrt, 696119031Sume inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 69755163Sshin else 69855163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 699119031Sume nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 70055163Sshin if (dflag >= 2) { 70155163Sshin np = ripbuf->rip6_nets; 70255163Sshin for (i = 0; i < nrt; i++, np++) { 70355163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 70455163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 70562607Sitojun trace(2, " NextHop reset"); 70655163Sshin else { 70755163Sshin trace(2, " NextHop %s", 70855163Sshin inet6_n2p(&np->rip6_dest)); 70955163Sshin } 71055163Sshin } else { 71155163Sshin trace(2, " %s/%d[%d]", 71255163Sshin inet6_n2p(&np->rip6_dest), 71355163Sshin np->rip6_plen, np->rip6_metric); 71455163Sshin } 71555163Sshin if (np->rip6_tag) { 71655163Sshin trace(2, " tag=0x%04x", 71755163Sshin ntohs(np->rip6_tag) & 0xffff); 71855163Sshin } 71955163Sshin trace(2, "\n"); 72055163Sshin } 72155163Sshin } 722119031Sume error = sendpacket(sin6, RIPSIZE(nrt)); 72355163Sshin if (error == EAFNOSUPPORT) { 72455163Sshin /* Protocol not supported */ 72555163Sshin tracet(1, "Could not send info to %s (%s): " 72655163Sshin "set IFF_UP to 0\n", 72755163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 72855163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 72955163Sshin } 73055163Sshin nrt = 0; np = ripbuf->rip6_nets; 73155163Sshin} 73255163Sshin 73355163Sshin/* 73455163Sshin * Generate RIP6_RESPONSE packets and send them. 73555163Sshin */ 73655163Sshinvoid 737119031Sumeripsend(ifcp, sin6, flag) 73855163Sshin struct ifc *ifcp; 739119031Sume struct sockaddr_in6 *sin6; 74055163Sshin int flag; 74155163Sshin{ 74255163Sshin struct riprt *rrt; 74355163Sshin struct in6_addr *nh; /* next hop */ 74478064Sume int maxrte; 74555163Sshin 74655163Sshin if (ifcp == NULL) { 74755163Sshin /* 74855163Sshin * Request from non-link local address is not 74955163Sshin * a regular route6d update. 75055163Sshin */ 75162607Sitojun maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 75262607Sitojun sizeof(struct udphdr) - 75355163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 75455163Sshin sizeof(struct netinfo6); 75555163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 75655163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 75762607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 75855163Sshin continue; 75955163Sshin /* Put the route to the buffer */ 76055163Sshin *np = rrt->rrt_info; 76155163Sshin np++; nrt++; 76255163Sshin if (nrt == maxrte) { 763119031Sume ripflush(NULL, sin6); 76455163Sshin nh = NULL; 76555163Sshin } 76655163Sshin } 76755163Sshin if (nrt) /* Send last packet */ 768119031Sume ripflush(NULL, sin6); 76955163Sshin return; 77055163Sshin } 77155163Sshin 77262607Sitojun if ((flag & RRTF_SENDANYWAY) == 0 && 77355163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 77455163Sshin return; 77578064Sume 77678064Sume /* -N: no use */ 77755163Sshin if (iff_find(ifcp, 'N') != NULL) 77855163Sshin return; 77978064Sume 78078064Sume /* -T: generate default route only */ 78155163Sshin if (iff_find(ifcp, 'T') != NULL) { 78255163Sshin struct netinfo6 rrt_info; 78355163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 78455163Sshin rrt_info.rip6_dest = in6addr_any; 78555163Sshin rrt_info.rip6_plen = 0; 78655163Sshin rrt_info.rip6_metric = 1; 78778064Sume rrt_info.rip6_metric += ifcp->ifc_metric; 78855163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 78955163Sshin np = ripbuf->rip6_nets; 79055163Sshin *np = rrt_info; 79155163Sshin nrt = 1; 792119031Sume ripflush(ifcp, sin6); 79355163Sshin return; 79455163Sshin } 79578064Sume 79662607Sitojun maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 79762607Sitojun sizeof(struct udphdr) - 79855163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 79955163Sshin sizeof(struct netinfo6); 80078064Sume 80155163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 80255163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 80362607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 80455163Sshin continue; 80578064Sume 80678064Sume /* Need to check filter here */ 80778064Sume if (out_filter(rrt, ifcp) == 0) 80855163Sshin continue; 80978064Sume 81055163Sshin /* Check split horizon and other conditions */ 81155163Sshin if (tobeadv(rrt, ifcp) == 0) 81255163Sshin continue; 81378064Sume 81455163Sshin /* Only considers the routes with flag if specified */ 81562607Sitojun if ((flag & RRTF_CHANGED) && 81662607Sitojun (rrt->rrt_rflags & RRTF_CHANGED) == 0) 81755163Sshin continue; 81878064Sume 81955163Sshin /* Check nexthop */ 82055163Sshin if (rrt->rrt_index == ifcp->ifc_index && 82155163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 82262607Sitojun (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 82355163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 82455163Sshin if (nrt == maxrte - 2) 825119031Sume ripflush(ifcp, sin6); 82655163Sshin np->rip6_dest = rrt->rrt_gw; 82755163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 82855163Sshin SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 82955163Sshin np->rip6_plen = 0; 83055163Sshin np->rip6_tag = 0; 83155163Sshin np->rip6_metric = NEXTHOP_METRIC; 83255163Sshin nh = &rrt->rrt_gw; 83355163Sshin np++; nrt++; 83455163Sshin } 83555163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 83655163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 83762607Sitojun rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 83855163Sshin /* Reset nexthop */ 83955163Sshin if (nrt == maxrte - 2) 840119031Sume ripflush(ifcp, sin6); 84155163Sshin memset(np, 0, sizeof(struct netinfo6)); 84255163Sshin np->rip6_metric = NEXTHOP_METRIC; 84355163Sshin nh = NULL; 84455163Sshin np++; nrt++; 84555163Sshin } 84678064Sume 84755163Sshin /* Put the route to the buffer */ 84855163Sshin *np = rrt->rrt_info; 84955163Sshin np++; nrt++; 85055163Sshin if (nrt == maxrte) { 851119031Sume ripflush(ifcp, sin6); 85255163Sshin nh = NULL; 85355163Sshin } 85455163Sshin } 85555163Sshin if (nrt) /* Send last packet */ 856119031Sume ripflush(ifcp, sin6); 85755163Sshin} 85855163Sshin 85955163Sshin/* 86078064Sume * outbound filter logic, per-route/interface. 86178064Sume */ 86278064Sumeint 86378064Sumeout_filter(rrt, ifcp) 86478064Sume struct riprt *rrt; 86578064Sume struct ifc *ifcp; 86678064Sume{ 86778064Sume struct iff *iffp; 86878064Sume struct in6_addr ia; 86978064Sume int ok; 87078064Sume 87178064Sume /* 87278064Sume * -A: filter out less specific routes, if we have aggregated 87378064Sume * route configured. 87478064Sume */ 87578064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 87678064Sume if (iffp->iff_type != 'A') 87778064Sume continue; 87878064Sume if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 87978064Sume continue; 88078064Sume ia = rrt->rrt_info.rip6_dest; 88178064Sume applyplen(&ia, iffp->iff_plen); 88278064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 88378064Sume return 0; 88478064Sume } 88578064Sume 88678064Sume /* 88778064Sume * if it is an aggregated route, advertise it only to the 88878064Sume * interfaces specified on -A. 88978064Sume */ 89078064Sume if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 89178064Sume ok = 0; 89278064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 89378064Sume if (iffp->iff_type != 'A') 89478064Sume continue; 89578064Sume if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 89678064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 89778064Sume &iffp->iff_addr)) { 89878064Sume ok = 1; 89978064Sume break; 90078064Sume } 90178064Sume } 90278064Sume if (!ok) 90378064Sume return 0; 90478064Sume } 90578064Sume 90678064Sume /* 90778064Sume * -O: advertise only if prefix matches the configured prefix. 90878064Sume */ 90978064Sume if (iff_find(ifcp, 'O')) { 91078064Sume ok = 0; 91178064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 91278064Sume if (iffp->iff_type != 'O') 91378064Sume continue; 91478064Sume if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 91578064Sume continue; 91678064Sume ia = rrt->rrt_info.rip6_dest; 91778064Sume applyplen(&ia, iffp->iff_plen); 91878064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 91978064Sume ok = 1; 92078064Sume break; 92178064Sume } 92278064Sume } 92378064Sume if (!ok) 92478064Sume return 0; 92578064Sume } 92678064Sume 92778064Sume /* the prefix should be advertised */ 92878064Sume return 1; 92978064Sume} 93078064Sume 93178064Sume/* 93255163Sshin * Determine if the route is to be advertised on the specified interface. 93355163Sshin * It checks options specified in the arguments and the split horizon rule. 93455163Sshin */ 93555163Sshinint 93655163Sshintobeadv(rrt, ifcp) 93755163Sshin struct riprt *rrt; 93855163Sshin struct ifc *ifcp; 93955163Sshin{ 94055163Sshin 94155163Sshin /* Special care for static routes */ 94255163Sshin if (rrt->rrt_flags & RTF_STATIC) { 94362607Sitojun /* XXX don't advertise reject/blackhole routes */ 94462607Sitojun if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 94562607Sitojun return 0; 94662607Sitojun 94755163Sshin if (Sflag) /* Yes, advertise it anyway */ 94855163Sshin return 1; 94955163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 95055163Sshin return 1; 95155163Sshin return 0; 95255163Sshin } 95355163Sshin /* Regular split horizon */ 95455163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 95555163Sshin return 0; 95655163Sshin return 1; 95755163Sshin} 95855163Sshin 95955163Sshin/* 96055163Sshin * Send a rip packet actually. 96155163Sshin */ 96255163Sshinint 963119031Sumesendpacket(sin6, len) 964119031Sume struct sockaddr_in6 *sin6; 96555163Sshin int len; 96655163Sshin{ 96755163Sshin /* 96855163Sshin * MSG_DONTROUTE should not be specified when it responds with a 96978064Sume * RIP6_REQUEST message. SO_DONTROUTE has been specified to 97055163Sshin * other sockets. 97155163Sshin */ 97255163Sshin struct msghdr m; 97355163Sshin struct cmsghdr *cm; 97455163Sshin struct iovec iov[2]; 97555163Sshin u_char cmsgbuf[256]; 97655163Sshin struct in6_pktinfo *pi; 97778064Sume int idx; 97855163Sshin struct sockaddr_in6 sincopy; 97955163Sshin 98055163Sshin /* do not overwrite the given sin */ 981119031Sume sincopy = *sin6; 982119031Sume sin6 = &sincopy; 98355163Sshin 984119035Sume if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 985119035Sume IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 986119031Sume idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); 987119031Sume SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); 98855163Sshin } else 98978064Sume idx = 0; 99055163Sshin 991119031Sume m.msg_name = (caddr_t)sin6; 992119031Sume m.msg_namelen = sizeof(*sin6); 99355163Sshin iov[0].iov_base = (caddr_t)ripbuf; 99455163Sshin iov[0].iov_len = len; 99555163Sshin m.msg_iov = iov; 99655163Sshin m.msg_iovlen = 1; 99778064Sume if (!idx) { 99855163Sshin m.msg_control = NULL; 99955163Sshin m.msg_controllen = 0; 100055163Sshin } else { 100155163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 100255163Sshin cm = (struct cmsghdr *)cmsgbuf; 100355163Sshin m.msg_control = (caddr_t)cm; 100455163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 100555163Sshin 100655163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 100755163Sshin cm->cmsg_level = IPPROTO_IPV6; 100855163Sshin cm->cmsg_type = IPV6_PKTINFO; 100955163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 101055163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 101178064Sume pi->ipi6_ifindex = idx; 101255163Sshin } 101355163Sshin 101455163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 101555163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 101655163Sshin return errno; 101755163Sshin } 101862921Sume 101955163Sshin return 0; 102055163Sshin} 102155163Sshin 102255163Sshin/* 102378064Sume * Receive and process RIP packets. Update the routes/kernel forwarding 102455163Sshin * table if necessary. 102555163Sshin */ 102655163Sshinvoid 102755163Sshinriprecv() 102855163Sshin{ 102955163Sshin struct ifc *ifcp, *ic; 103055163Sshin struct sockaddr_in6 fsock; 103155163Sshin struct in6_addr nh; /* next hop */ 103255163Sshin struct rip6 *rp; 103355163Sshin struct netinfo6 *np, *nq; 103455163Sshin struct riprt *rrt; 103578064Sume int len, nn, need_trigger, idx; 103655163Sshin char buf[4 * RIP6_MAXMTU]; 103755163Sshin time_t t; 103855163Sshin struct msghdr m; 103955163Sshin struct cmsghdr *cm; 104055163Sshin struct iovec iov[2]; 104155163Sshin u_char cmsgbuf[256]; 104255163Sshin struct in6_pktinfo *pi; 104355163Sshin struct iff *iffp; 104455163Sshin struct in6_addr ia; 104555163Sshin int ok; 104678064Sume time_t t_half_lifetime; 104755163Sshin 104855163Sshin need_trigger = 0; 104962921Sume 105055163Sshin m.msg_name = (caddr_t)&fsock; 105155163Sshin m.msg_namelen = sizeof(fsock); 105255163Sshin iov[0].iov_base = (caddr_t)buf; 105355163Sshin iov[0].iov_len = sizeof(buf); 105455163Sshin m.msg_iov = iov; 105555163Sshin m.msg_iovlen = 1; 105655163Sshin cm = (struct cmsghdr *)cmsgbuf; 105755163Sshin m.msg_control = (caddr_t)cm; 105855163Sshin m.msg_controllen = sizeof(cmsgbuf); 105978064Sume if ((len = recvmsg(ripsock, &m, 0)) < 0) { 106055163Sshin fatal("recvmsg"); 106178064Sume /*NOTREACHED*/ 106278064Sume } 106378064Sume idx = 0; 106455163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 106555163Sshin cm; 106655163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 106778064Sume if (cm->cmsg_level == IPPROTO_IPV6 && 106878064Sume cm->cmsg_type == IPV6_PKTINFO) { 106955163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 107078064Sume idx = pi->ipi6_ifindex; 107155163Sshin break; 107255163Sshin } 107355163Sshin } 107478064Sume if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 107578064Sume SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); 107655163Sshin 107755163Sshin nh = fsock.sin6_addr; 107855163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 107955163Sshin sizeof(struct netinfo6); 108055163Sshin rp = (struct rip6 *)buf; 108155163Sshin np = rp->rip6_nets; 108255163Sshin 1083119035Sume if (rp->rip6_vers != RIP6_VERSION) { 108455163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 108555163Sshin return; 108655163Sshin } 108755163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 108878064Sume if (idx && idx < nindex2ifc) { 108978064Sume ifcp = index2ifc[idx]; 109055163Sshin riprequest(ifcp, np, nn, &fsock); 109155163Sshin } else { 109255163Sshin riprequest(NULL, np, nn, &fsock); 109355163Sshin } 109462607Sitojun return; 109562607Sitojun } 109655163Sshin 109755163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 109855163Sshin trace(1, "Packets from non-ll addr: %s\n", 109978064Sume inet6_n2p(&fsock.sin6_addr)); 110055163Sshin return; /* Ignore packets from non-link-local addr */ 110155163Sshin } 110278064Sume idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 110378064Sume ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 110455163Sshin if (!ifcp) { 110578064Sume trace(1, "Packets to unknown interface index %d\n", idx); 110655163Sshin return; /* Ignore it */ 110755163Sshin } 110855163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 110955163Sshin return; /* The packet is from me; ignore */ 111055163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 111155163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 111262607Sitojun return; 111355163Sshin } 111478064Sume 111578064Sume /* -N: no use */ 111655163Sshin if (iff_find(ifcp, 'N') != NULL) 111755163Sshin return; 111878064Sume 111955163Sshin tracet(1, "Recv(%s): from %s.%d info(%d)\n", 112078064Sume ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 112155163Sshin 112255163Sshin t = time(NULL); 112378064Sume t_half_lifetime = t - (RIP_LIFETIME/2); 112455163Sshin for (; nn; nn--, np++) { 112555163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 112655163Sshin /* modify neighbor address */ 112755163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 112855163Sshin nh = np->rip6_dest; 112978064Sume SET_IN6_LINKLOCAL_IFINDEX(nh, idx); 113055163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 113155163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 113255163Sshin nh = fsock.sin6_addr; 113355163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 113455163Sshin } else { 113555163Sshin nh = fsock.sin6_addr; 113655163Sshin trace(1, "\tInvalid Nexthop: %s\n", 113778064Sume inet6_n2p(&np->rip6_dest)); 113855163Sshin } 113955163Sshin continue; 114055163Sshin } 114155163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 114255163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 114355163Sshin inet6_n2p(&np->rip6_dest), 114455163Sshin np->rip6_plen, np->rip6_metric); 114555163Sshin continue; 114655163Sshin } 114755163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 114855163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 114955163Sshin inet6_n2p(&np->rip6_dest), 115055163Sshin np->rip6_plen, np->rip6_metric); 115155163Sshin continue; 115255163Sshin } 115355163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 115455163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 115555163Sshin inet6_n2p(&np->rip6_dest), 115655163Sshin np->rip6_plen, np->rip6_metric); 115755163Sshin continue; 115855163Sshin } 115955163Sshin /* may need to pass sitelocal prefix in some case, however*/ 116055163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 116155163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 116255163Sshin inet6_n2p(&np->rip6_dest), 116355163Sshin np->rip6_plen, np->rip6_metric); 116455163Sshin continue; 116555163Sshin } 116655163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 116755163Sshin inet6_n2p(&np->rip6_dest), 116855163Sshin np->rip6_plen, np->rip6_metric); 116955163Sshin if (np->rip6_tag) 117055163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 117162607Sitojun if (dflag >= 2) { 117262607Sitojun ia = np->rip6_dest; 117362607Sitojun applyplen(&ia, np->rip6_plen); 117462607Sitojun if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 117562607Sitojun trace(2, " [junk outside prefix]"); 117662607Sitojun } 117755163Sshin 117878064Sume /* 117978064Sume * -L: listen only if the prefix matches the configuration 118078064Sume */ 118155163Sshin ok = 1; /* if there's no L filter, it is ok */ 118255163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 118355163Sshin if (iffp->iff_type != 'L') 118455163Sshin continue; 118555163Sshin ok = 0; 118655163Sshin if (np->rip6_plen < iffp->iff_plen) 118755163Sshin continue; 118855163Sshin /* special rule: ::/0 means default, not "in /0" */ 118955163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 119055163Sshin continue; 119162607Sitojun ia = np->rip6_dest; 119255163Sshin applyplen(&ia, iffp->iff_plen); 119355163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 119455163Sshin ok = 1; 119555163Sshin break; 119655163Sshin } 119755163Sshin } 119855163Sshin if (!ok) { 119955163Sshin trace(2, " (filtered)\n"); 120055163Sshin continue; 120155163Sshin } 120255163Sshin 120355163Sshin trace(2, "\n"); 120455163Sshin np->rip6_metric++; 120555163Sshin np->rip6_metric += ifcp->ifc_metric; 120655163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 120755163Sshin np->rip6_metric = HOPCNT_INFINITY6; 120855163Sshin 120955163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 121078064Sume if ((rrt = rtsearch(np, NULL)) != NULL) { 121155163Sshin if (rrt->rrt_t == 0) 121255163Sshin continue; /* Intf route has priority */ 121355163Sshin nq = &rrt->rrt_info; 121455163Sshin if (nq->rip6_metric > np->rip6_metric) { 121555163Sshin if (rrt->rrt_index == ifcp->ifc_index && 121655163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 121755163Sshin /* Small metric from the same gateway */ 121855163Sshin nq->rip6_metric = np->rip6_metric; 121955163Sshin } else { 122055163Sshin /* Better route found */ 122155163Sshin rrt->rrt_index = ifcp->ifc_index; 122255163Sshin /* Update routing table */ 122355163Sshin delroute(nq, &rrt->rrt_gw); 122455163Sshin rrt->rrt_gw = nh; 122555163Sshin *nq = *np; 122655163Sshin addroute(rrt, &nh, ifcp); 122755163Sshin } 122862607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 122955163Sshin rrt->rrt_t = t; 123055163Sshin need_trigger = 1; 123155163Sshin } else if (nq->rip6_metric < np->rip6_metric && 123255163Sshin rrt->rrt_index == ifcp->ifc_index && 123355163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 123455163Sshin /* Got worse route from same gw */ 123555163Sshin nq->rip6_metric = np->rip6_metric; 123655163Sshin rrt->rrt_t = t; 123762607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 123855163Sshin need_trigger = 1; 123955163Sshin } else if (nq->rip6_metric == np->rip6_metric && 124055163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 124178064Sume if (rrt->rrt_index == ifcp->ifc_index && 124278064Sume IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 124378064Sume /* same metric, same route from same gw */ 124478064Sume rrt->rrt_t = t; 124578064Sume } else if (rrt->rrt_t < t_half_lifetime) { 124678064Sume /* Better route found */ 124778064Sume rrt->rrt_index = ifcp->ifc_index; 124878064Sume /* Update routing table */ 124978064Sume delroute(nq, &rrt->rrt_gw); 125078064Sume rrt->rrt_gw = nh; 125178064Sume *nq = *np; 125278064Sume addroute(rrt, &nh, ifcp); 125378064Sume rrt->rrt_rflags |= RRTF_CHANGED; 125478064Sume rrt->rrt_t = t; 125578064Sume } 125655163Sshin } 125762607Sitojun /* 125855163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 125978064Sume * do not update age value. Do nothing. 126055163Sshin */ 126155163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 126255163Sshin /* Got a new valid route */ 126378064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 126455163Sshin fatal("malloc: struct riprt"); 126578064Sume /*NOTREACHED*/ 126678064Sume } 126762607Sitojun memset(rrt, 0, sizeof(*rrt)); 126855163Sshin nq = &rrt->rrt_info; 126955163Sshin 127055163Sshin rrt->rrt_same = NULL; 127155163Sshin rrt->rrt_index = ifcp->ifc_index; 127255163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 127355163Sshin rrt->rrt_gw = nh; 127455163Sshin *nq = *np; 127555163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 127655163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 127755163Sshin rrt->rrt_flags |= RTF_HOST; 127855163Sshin 127955163Sshin /* Put the route to the list */ 128055163Sshin rrt->rrt_next = riprt; 128155163Sshin riprt = rrt; 128255163Sshin /* Update routing table */ 128355163Sshin addroute(rrt, &nh, ifcp); 128462607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 128555163Sshin need_trigger = 1; 128655163Sshin rrt->rrt_t = t; 128755163Sshin } 128855163Sshin } 128955163Sshin /* XXX need to care the interval between triggered updates */ 129055163Sshin if (need_trigger) { 129155163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 129255163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 129355163Sshin if (ifcp->ifc_index == ic->ifc_index) 129455163Sshin continue; 129555163Sshin if (ic->ifc_flags & IFF_UP) 129655163Sshin ripsend(ic, &ic->ifc_ripsin, 129762607Sitojun RRTF_CHANGED); 129855163Sshin } 129955163Sshin } 130055163Sshin /* Reset the flag */ 130155163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 130262607Sitojun rrt->rrt_rflags &= ~RRTF_CHANGED; 130355163Sshin } 130455163Sshin} 130555163Sshin 130655163Sshin/* 130755163Sshin * Send all routes request packet to the specified interface. 130855163Sshin */ 130955163Sshinvoid 131055163Sshinsendrequest(ifcp) 131155163Sshin struct ifc *ifcp; 131255163Sshin{ 131355163Sshin struct netinfo6 *np; 131455163Sshin int error; 131555163Sshin 131655163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 131755163Sshin return; 131855163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 131955163Sshin np = ripbuf->rip6_nets; 132055163Sshin memset(np, 0, sizeof(struct netinfo6)); 132155163Sshin np->rip6_metric = HOPCNT_INFINITY6; 132255163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 132355163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 132455163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 132555163Sshin if (error == EAFNOSUPPORT) { 132655163Sshin /* Protocol not supported */ 132755163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 132855163Sshin "set IFF_UP to 0\n", 132955163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 133055163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 133155163Sshin } 133255163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 133355163Sshin} 133455163Sshin 133555163Sshin/* 133655163Sshin * Process a RIP6_REQUEST packet. 133755163Sshin */ 133855163Sshinvoid 1339119031Sumeriprequest(ifcp, np, nn, sin6) 134055163Sshin struct ifc *ifcp; 134155163Sshin struct netinfo6 *np; 134255163Sshin int nn; 1343119031Sume struct sockaddr_in6 *sin6; 134455163Sshin{ 134555163Sshin int i; 134655163Sshin struct riprt *rrt; 134755163Sshin 134855163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 134955163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 135055163Sshin /* Specific response, don't split-horizon */ 135155163Sshin trace(1, "\tRIP Request\n"); 135255163Sshin for (i = 0; i < nn; i++, np++) { 135378064Sume rrt = rtsearch(np, NULL); 135455163Sshin if (rrt) 135555163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 135655163Sshin else 135755163Sshin np->rip6_metric = HOPCNT_INFINITY6; 135855163Sshin } 1359119031Sume (void)sendpacket(sin6, RIPSIZE(nn)); 136055163Sshin return; 136155163Sshin } 136255163Sshin /* Whole routing table dump */ 136355163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 1364119031Sume ripsend(ifcp, sin6, RRTF_SENDANYWAY); 136555163Sshin} 136655163Sshin 136755163Sshin/* 136855163Sshin * Get information of each interface. 136955163Sshin */ 137055163Sshinvoid 137155163Sshinifconfig() 137255163Sshin{ 137362607Sitojun struct ifaddrs *ifap, *ifa; 137462607Sitojun struct ifc *ifcp; 137562607Sitojun struct ipv6_mreq mreq; 137662607Sitojun int s; 137762607Sitojun 137878064Sume if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 137962607Sitojun fatal("socket"); 138078064Sume /*NOTREACHED*/ 138178064Sume } 138262607Sitojun 138378064Sume if (getifaddrs(&ifap) != 0) { 138462607Sitojun fatal("getifaddrs"); 138578064Sume /*NOTREACHED*/ 138678064Sume } 138762607Sitojun 138862607Sitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 138962607Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 139062607Sitojun continue; 139162607Sitojun ifcp = ifc_find(ifa->ifa_name); 139262607Sitojun /* we are interested in multicast-capable interfaces */ 139362607Sitojun if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 139462607Sitojun continue; 139562607Sitojun if (!ifcp) { 139662607Sitojun /* new interface */ 139778064Sume if ((ifcp = MALLOC(struct ifc)) == NULL) { 139862607Sitojun fatal("malloc: struct ifc"); 139978064Sume /*NOTREACHED*/ 140078064Sume } 140162607Sitojun memset(ifcp, 0, sizeof(*ifcp)); 140262607Sitojun ifcp->ifc_index = -1; 140362607Sitojun ifcp->ifc_next = ifc; 140462607Sitojun ifc = ifcp; 140562607Sitojun nifc++; 140662607Sitojun ifcp->ifc_name = allocopy(ifa->ifa_name); 140762607Sitojun ifcp->ifc_addr = 0; 140862607Sitojun ifcp->ifc_filter = 0; 140962607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 141062607Sitojun trace(1, "newif %s <%s>\n", ifcp->ifc_name, 141162607Sitojun ifflags(ifcp->ifc_flags)); 141262607Sitojun if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 141362607Sitojun loopifcp = ifcp; 141462607Sitojun } else { 141562607Sitojun /* update flag, this may be up again */ 141662607Sitojun if (ifcp->ifc_flags != ifa->ifa_flags) { 141762607Sitojun trace(1, "%s: <%s> -> ", ifcp->ifc_name, 141862607Sitojun ifflags(ifcp->ifc_flags)); 141962607Sitojun trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 142078064Sume ifcp->ifc_cflags |= IFC_CHANGED; 142162607Sitojun } 142262607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 142362607Sitojun } 142462607Sitojun ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 142562607Sitojun if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 142662607Sitojun && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 142762607Sitojun mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 142862607Sitojun mreq.ipv6mr_interface = ifcp->ifc_index; 142978064Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 143078064Sume &mreq, sizeof(mreq)) < 0) { 143162607Sitojun fatal("IPV6_JOIN_GROUP"); 143278064Sume /*NOTREACHED*/ 143378064Sume } 143462607Sitojun trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 143562607Sitojun ifcp->ifc_joined++; 143662607Sitojun } 143762607Sitojun } 143862607Sitojun close(s); 143962607Sitojun freeifaddrs(ifap); 144055163Sshin} 144155163Sshin 144255163Sshinvoid 144362607Sitojunifconfig1(name, sa, ifcp, s) 144462607Sitojun const char *name; 144562607Sitojun const struct sockaddr *sa; 144655163Sshin struct ifc *ifcp; 144755163Sshin int s; 144855163Sshin{ 144955163Sshin struct in6_ifreq ifr; 1450119031Sume const struct sockaddr_in6 *sin6; 145155163Sshin struct ifac *ifa; 145255163Sshin int plen; 145355163Sshin char buf[BUFSIZ]; 145455163Sshin 1455119031Sume sin6 = (const struct sockaddr_in6 *)sa; 1456119031Sume ifr.ifr_addr = *sin6; 1457119032Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 145878064Sume if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 145955163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 146078064Sume /*NOTREACHED*/ 146178064Sume } 146278064Sume plen = sin6mask2len(&ifr.ifr_addr); 1463119031Sume if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 146455163Sshin /* same interface found */ 146555163Sshin /* need check if something changed */ 146655163Sshin /* XXX not yet implemented */ 146755163Sshin return; 146855163Sshin } 146955163Sshin /* 147055163Sshin * New address is found 147155163Sshin */ 147278064Sume if ((ifa = MALLOC(struct ifac)) == NULL) { 147355163Sshin fatal("malloc: struct ifac"); 147478064Sume /*NOTREACHED*/ 147578064Sume } 147662607Sitojun memset(ifa, 0, sizeof(*ifa)); 147755163Sshin ifa->ifa_conf = ifcp; 147855163Sshin ifa->ifa_next = ifcp->ifc_addr; 147955163Sshin ifcp->ifc_addr = ifa; 1480119031Sume ifa->ifa_addr = sin6->sin6_addr; 148155163Sshin ifa->ifa_plen = plen; 148255163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1483119031Sume ifr.ifr_addr = *sin6; 148478064Sume if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 148555163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 148678064Sume /*NOTREACHED*/ 148778064Sume } 148855163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 148955163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 149055163Sshin trace(1, "found address %s/%d -- %s\n", 149155163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 149255163Sshin } else { 149355163Sshin trace(1, "found address %s/%d\n", 149455163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 149555163Sshin } 149655163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 149755163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 149855163Sshin ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 149955163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 150055163Sshin SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 150155163Sshin ifcp->ifc_index); 150255163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 150355163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 150455163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 150555163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 150678064Sume if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 150755163Sshin fatal("ioctl: SIOCGIFMETRIC"); 150878064Sume /*NOTREACHED*/ 150978064Sume } 151055163Sshin ifcp->ifc_metric = ifr.ifr_metric; 151155163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 151255163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 151378064Sume } else 151478064Sume ifcp->ifc_cflags |= IFC_CHANGED; 151555163Sshin} 151655163Sshin 151755163Sshin/* 151855163Sshin * Receive and process routing messages. 151955163Sshin * Update interface information as necesssary. 152055163Sshin */ 152155163Sshinvoid 152255163Sshinrtrecv() 152355163Sshin{ 152455163Sshin char buf[BUFSIZ]; 152555163Sshin char *p, *q; 152655163Sshin struct rt_msghdr *rtm; 152755163Sshin struct ifa_msghdr *ifam; 152855163Sshin struct if_msghdr *ifm; 152955163Sshin int len; 153078064Sume struct ifc *ifcp, *ic; 153155163Sshin int iface = 0, rtable = 0; 153255163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 153378064Sume struct sockaddr_in6 mask; 153455163Sshin int i, addrs; 153578064Sume struct riprt *rrt; 153655163Sshin 153755163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 153855163Sshin perror("read from rtsock"); 153978064Sume exit(1); 154055163Sshin } 154155163Sshin if (len < sizeof(*rtm)) { 154269279Sume trace(1, "short read from rtsock: %d (should be > %lu)\n", 154369279Sume len, (u_long)sizeof(*rtm)); 154455163Sshin return; 154555163Sshin } 154655163Sshin 154755163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 154855163Sshin /* safety against bogus message */ 154955163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 155055163Sshin trace(1, "bogus rtmsg: length=%d\n", 155155163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 155255163Sshin break; 155355163Sshin } 155455163Sshin rtm = NULL; 155555163Sshin ifam = NULL; 155655163Sshin ifm = NULL; 155755163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 155855163Sshin case RTM_NEWADDR: 155955163Sshin case RTM_DELADDR: 156055163Sshin ifam = (struct ifa_msghdr *)p; 156155163Sshin addrs = ifam->ifam_addrs; 156255163Sshin q = (char *)(ifam + 1); 156355163Sshin break; 156455163Sshin case RTM_IFINFO: 156555163Sshin ifm = (struct if_msghdr *)p; 156655163Sshin addrs = ifm->ifm_addrs; 156755163Sshin q = (char *)(ifm + 1); 156855163Sshin break; 156955163Sshin default: 157055163Sshin rtm = (struct rt_msghdr *)p; 157155163Sshin addrs = rtm->rtm_addrs; 157255163Sshin q = (char *)(rtm + 1); 157355163Sshin if (rtm->rtm_version != RTM_VERSION) { 157455163Sshin trace(1, "unexpected rtmsg version %d " 157555163Sshin "(should be %d)\n", 157655163Sshin rtm->rtm_version, RTM_VERSION); 157755163Sshin continue; 157855163Sshin } 157955163Sshin if (rtm->rtm_pid == pid) { 158055163Sshin#if 0 158155163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 158255163Sshin#endif 158355163Sshin continue; 158455163Sshin } 158555163Sshin break; 158655163Sshin } 158755163Sshin memset(&rta, 0, sizeof(rta)); 158855163Sshin for (i = 0; i < RTAX_MAX; i++) { 158955163Sshin if (addrs & (1 << i)) { 159055163Sshin rta[i] = (struct sockaddr_in6 *)q; 159155163Sshin q += ROUNDUP(rta[i]->sin6_len); 159255163Sshin } 159355163Sshin } 159455163Sshin 159555163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 159655163Sshin rttypes((struct rt_msghdr *)p), addrs); 159755163Sshin if (dflag >= 2) { 159855163Sshin for (i = 0; 159955163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 160055163Sshin i++) { 160155163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 160255163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 160355163Sshin } 160455163Sshin fprintf(stderr, "\n"); 160555163Sshin } 160655163Sshin 160755163Sshin /* 160855163Sshin * Easy ones first. 160955163Sshin * 161055163Sshin * We may be able to optimize by using ifm->ifm_index or 161155163Sshin * ifam->ifam_index. For simplicity we don't do that here. 161255163Sshin */ 161355163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 161455163Sshin case RTM_NEWADDR: 161555163Sshin case RTM_IFINFO: 161655163Sshin iface++; 161755163Sshin continue; 161855163Sshin case RTM_ADD: 161955163Sshin rtable++; 162055163Sshin continue; 162155163Sshin case RTM_LOSING: 162255163Sshin case RTM_MISS: 162355163Sshin case RTM_RESOLVE: 162455163Sshin case RTM_GET: 162555163Sshin case RTM_LOCK: 162655163Sshin /* nothing to be done here */ 162755163Sshin trace(1, "\tnothing to be done, ignored\n"); 162855163Sshin continue; 162955163Sshin } 163055163Sshin 163155163Sshin#if 0 163255163Sshin if (rta[RTAX_DST] == NULL) { 163355163Sshin trace(1, "\tno destination, ignored\n"); 163462607Sitojun continue; 163555163Sshin } 163655163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 163755163Sshin trace(1, "\taf mismatch, ignored\n"); 163855163Sshin continue; 163955163Sshin } 164055163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 164155163Sshin trace(1, "\tlinklocal destination, ignored\n"); 164255163Sshin continue; 164355163Sshin } 164455163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 164555163Sshin trace(1, "\tloopback destination, ignored\n"); 164655163Sshin continue; /* Loopback */ 164755163Sshin } 164855163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 164955163Sshin trace(1, "\tmulticast destination, ignored\n"); 165055163Sshin continue; 165155163Sshin } 165255163Sshin#endif 165355163Sshin 165455163Sshin /* hard ones */ 165555163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 165655163Sshin case RTM_NEWADDR: 165755163Sshin case RTM_IFINFO: 165855163Sshin case RTM_ADD: 165955163Sshin case RTM_LOSING: 166055163Sshin case RTM_MISS: 166155163Sshin case RTM_RESOLVE: 166255163Sshin case RTM_GET: 166355163Sshin case RTM_LOCK: 166455163Sshin /* should already be handled */ 166555163Sshin fatal("rtrecv: never reach here"); 166678064Sume /*NOTREACHED*/ 166755163Sshin case RTM_DELETE: 166878064Sume if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 166978064Sume trace(1, "\tsome of dst/gw/netamsk are " 167078064Sume "unavailable, ignored\n"); 167155163Sshin break; 167255163Sshin } 167378064Sume if ((rtm->rtm_flags & RTF_HOST) != 0) { 167478064Sume mask.sin6_len = sizeof(mask); 167578064Sume memset(&mask.sin6_addr, 0xff, 167678064Sume sizeof(mask.sin6_addr)); 167778064Sume rta[RTAX_NETMASK] = &mask; 167878064Sume } else if (!rta[RTAX_NETMASK]) { 167978064Sume trace(1, "\tsome of dst/gw/netamsk are " 168078064Sume "unavailable, ignored\n"); 168178064Sume break; 168278064Sume } 168378064Sume if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 168478064Sume rta[RTAX_NETMASK]) == 0) { 168555163Sshin rtable++; /*just to be sure*/ 168655163Sshin } 168755163Sshin break; 168855163Sshin case RTM_CHANGE: 168955163Sshin case RTM_REDIRECT: 169055163Sshin trace(1, "\tnot supported yet, ignored\n"); 169155163Sshin break; 169255163Sshin case RTM_DELADDR: 169355163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 169455163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 169555163Sshin break; 169655163Sshin } 169755163Sshin if (ifam->ifam_index < nindex2ifc) 169855163Sshin ifcp = index2ifc[ifam->ifam_index]; 169955163Sshin else 170055163Sshin ifcp = NULL; 170155163Sshin if (!ifcp) { 170255163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 170355163Sshin ifam->ifam_index); 170455163Sshin break; 170555163Sshin } 170678064Sume if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 170778064Sume iface++; 170855163Sshin break; 170955163Sshin case RTM_OLDADD: 171055163Sshin case RTM_OLDDEL: 171155163Sshin trace(1, "\tnot supported yet, ignored\n"); 171255163Sshin break; 171355163Sshin } 171455163Sshin 171555163Sshin } 171655163Sshin 171755163Sshin if (iface) { 171855163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 171955163Sshin ifconfig(); 172055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 172178064Sume if (ifcp->ifc_cflags & IFC_CHANGED) { 172278064Sume if (ifrt(ifcp, 1)) { 172378064Sume for (ic = ifc; ic; ic = ic->ifc_next) { 172478064Sume if (ifcp->ifc_index == ic->ifc_index) 172578064Sume continue; 172678064Sume if (ic->ifc_flags & IFF_UP) 172778064Sume ripsend(ic, &ic->ifc_ripsin, 172878064Sume RRTF_CHANGED); 172978064Sume } 173078064Sume /* Reset the flag */ 173178064Sume for (rrt = riprt; rrt; rrt = rrt->rrt_next) 173278064Sume rrt->rrt_rflags &= ~RRTF_CHANGED; 173378064Sume } 173478064Sume ifcp->ifc_cflags &= ~IFC_CHANGED; 173578064Sume } 173655163Sshin } 173755163Sshin if (rtable) { 173855163Sshin trace(1, "rtsock: read routing table again\n"); 173955163Sshin krtread(1); 174055163Sshin } 174155163Sshin} 174255163Sshin 174355163Sshin/* 174455163Sshin * remove specified route from the internal routing table. 174555163Sshin */ 174655163Sshinint 174755163Sshinrt_del(sdst, sgw, smask) 174855163Sshin const struct sockaddr_in6 *sdst; 174955163Sshin const struct sockaddr_in6 *sgw; 175055163Sshin const struct sockaddr_in6 *smask; 175155163Sshin{ 175255163Sshin const struct in6_addr *dst = NULL; 175355163Sshin const struct in6_addr *gw = NULL; 175455163Sshin int prefix; 175555163Sshin struct netinfo6 ni6; 175655163Sshin struct riprt *rrt = NULL; 175755163Sshin time_t t_lifetime; 175855163Sshin 175955163Sshin if (sdst->sin6_family != AF_INET6) { 176055163Sshin trace(1, "\tother AF, ignored\n"); 176155163Sshin return -1; 176255163Sshin } 176355163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 176455163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 176555163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 176655163Sshin trace(1, "\taddress %s not interesting, ignored\n", 176755163Sshin inet6_n2p(&sdst->sin6_addr)); 176855163Sshin return -1; 176955163Sshin } 177055163Sshin dst = &sdst->sin6_addr; 177178064Sume if (sgw->sin6_family == AF_INET6) { 177255163Sshin /* easy case */ 177355163Sshin gw = &sgw->sin6_addr; 177478064Sume prefix = sin6mask2len(smask); 177555163Sshin } else if (sgw->sin6_family == AF_LINK) { 177655163Sshin /* 177755163Sshin * Interface route... a hard case. We need to get the prefix 177855163Sshin * length from the kernel, but we now are parsing rtmsg. 177955163Sshin * We'll purge matching routes from my list, then get the 178055163Sshin * fresh list. 178155163Sshin */ 178255163Sshin struct riprt *longest; 1783108533Sschweikh trace(1, "\t%s is an interface route, guessing prefixlen\n", 178455163Sshin inet6_n2p(dst)); 178555163Sshin longest = NULL; 178655163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 178755163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 178855163Sshin &sdst->sin6_addr) 178955163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 179055163Sshin if (!longest 179155163Sshin || longest->rrt_info.rip6_plen < 179255163Sshin rrt->rrt_info.rip6_plen) { 179355163Sshin longest = rrt; 179455163Sshin } 179555163Sshin } 179655163Sshin } 179755163Sshin rrt = longest; 179855163Sshin if (!rrt) { 179955163Sshin trace(1, "\tno matching interface route found\n"); 180055163Sshin return -1; 180155163Sshin } 180255163Sshin gw = &in6addr_loopback; 180355163Sshin prefix = rrt->rrt_info.rip6_plen; 180455163Sshin } else { 180578064Sume trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 180655163Sshin return -1; 180755163Sshin } 180855163Sshin 180955163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 181055163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 181155163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 181255163Sshin /* age route for interface address */ 181355163Sshin memset(&ni6, 0, sizeof(ni6)); 181455163Sshin ni6.rip6_dest = *dst; 181555163Sshin ni6.rip6_plen = prefix; 181655163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 181755163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 181855163Sshin ni6.rip6_plen); 181978064Sume if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 182055163Sshin trace(1, "\tno route found\n"); 182155163Sshin return -1; 182255163Sshin } 182378064Sume#if 0 182455163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 182555163Sshin trace(1, "\tyou can delete static routes only\n"); 182678064Sume } else 182778064Sume#endif 182878064Sume if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 182955163Sshin trace(1, "\tgw mismatch: %s <-> ", 183055163Sshin inet6_n2p(&rrt->rrt_gw)); 183155163Sshin trace(1, "%s\n", inet6_n2p(gw)); 183255163Sshin } else { 183355163Sshin trace(1, "\troute found, age it\n"); 183455163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 183555163Sshin rrt->rrt_t = t_lifetime; 183655163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 183755163Sshin } 183855163Sshin } 183955163Sshin return 0; 184055163Sshin} 184155163Sshin 184255163Sshin/* 184355163Sshin * remove specified address from internal interface/routing table. 184455163Sshin */ 184555163Sshinint 184655163Sshinrt_deladdr(ifcp, sifa, smask) 184755163Sshin struct ifc *ifcp; 184855163Sshin const struct sockaddr_in6 *sifa; 184955163Sshin const struct sockaddr_in6 *smask; 185055163Sshin{ 185155163Sshin const struct in6_addr *addr = NULL; 185255163Sshin int prefix; 185355163Sshin struct ifac *ifa = NULL; 185455163Sshin struct netinfo6 ni6; 185555163Sshin struct riprt *rrt = NULL; 185655163Sshin time_t t_lifetime; 185755163Sshin int updated = 0; 185855163Sshin 185978064Sume if (sifa->sin6_family != AF_INET6) { 186055163Sshin trace(1, "\tother AF, ignored\n"); 186155163Sshin return -1; 186255163Sshin } 186355163Sshin addr = &sifa->sin6_addr; 186478064Sume prefix = sin6mask2len(smask); 186555163Sshin 186655163Sshin trace(1, "\tdeleting %s/%d from %s\n", 186755163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 186855163Sshin ifa = ifa_match(ifcp, addr, prefix); 186955163Sshin if (!ifa) { 187055163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 187155163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 187255163Sshin return -1; 187355163Sshin } 187455163Sshin if (ifa->ifa_conf != ifcp) { 187555163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 187655163Sshin "(%s != %s)\n", 187755163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 187855163Sshin return -1; 187955163Sshin } 188055163Sshin /* remove ifa from interface */ 188155163Sshin if (ifcp->ifc_addr == ifa) 188255163Sshin ifcp->ifc_addr = ifa->ifa_next; 188355163Sshin else { 188455163Sshin struct ifac *p; 188555163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 188655163Sshin if (p->ifa_next == ifa) { 188755163Sshin p->ifa_next = ifa->ifa_next; 188855163Sshin break; 188955163Sshin } 189055163Sshin } 189155163Sshin } 189255163Sshin ifa->ifa_next = NULL; 189355163Sshin ifa->ifa_conf = NULL; 189455163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 189555163Sshin /* age route for interface address */ 189655163Sshin memset(&ni6, 0, sizeof(ni6)); 189755163Sshin ni6.rip6_dest = ifa->ifa_addr; 189855163Sshin ni6.rip6_plen = ifa->ifa_plen; 189955163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 190055163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 190155163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 190278064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 190355163Sshin struct in6_addr none; 190455163Sshin memset(&none, 0, sizeof(none)); 190578064Sume if (rrt->rrt_index == ifcp->ifc_index && 190678064Sume (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 190778064Sume IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 190855163Sshin trace(1, "\troute found, age it\n"); 190955163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 191055163Sshin rrt->rrt_t = t_lifetime; 191155163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 191255163Sshin } 191355163Sshin updated++; 191455163Sshin } else { 191555163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 191655163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 191755163Sshin rrt->rrt_info.rip6_plen, 191855163Sshin rrt->rrt_index); 191955163Sshin } 192055163Sshin } else 192155163Sshin trace(1, "\tno interface route found\n"); 192255163Sshin /* age route for p2p destination */ 192355163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 192455163Sshin memset(&ni6, 0, sizeof(ni6)); 192555163Sshin ni6.rip6_dest = ifa->ifa_raddr; 192655163Sshin ni6.rip6_plen = 128; 192755163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 192855163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 192955163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 193055163Sshin ifcp->ifc_index); 193178064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 193278064Sume if (rrt->rrt_index == ifcp->ifc_index && 193378064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 193455163Sshin trace(1, "\troute found, age it\n"); 193555163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 193655163Sshin rrt->rrt_t = t_lifetime; 193755163Sshin rrt->rrt_info.rip6_metric = 193878064Sume HOPCNT_INFINITY6; 193955163Sshin updated++; 194055163Sshin } 194155163Sshin } else { 194255163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 194355163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 194455163Sshin rrt->rrt_info.rip6_plen, 194555163Sshin rrt->rrt_index); 194655163Sshin } 194755163Sshin } else 194855163Sshin trace(1, "\tno p2p route found\n"); 194955163Sshin } 195055163Sshin return updated ? 0 : -1; 195155163Sshin} 195255163Sshin 195355163Sshin/* 195455163Sshin * Get each interface address and put those interface routes to the route 195555163Sshin * list. 195655163Sshin */ 195778064Sumeint 195855163Sshinifrt(ifcp, again) 195962607Sitojun struct ifc *ifcp; 196055163Sshin int again; 196155163Sshin{ 196262607Sitojun struct ifac *ifa; 196378064Sume struct riprt *rrt, *search_rrt, *prev_rrt, *loop_rrt; 196462607Sitojun struct netinfo6 *np; 196578064Sume time_t t_lifetime; 196678064Sume int need_trigger = 0; 196755163Sshin 196855163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 196978064Sume return 0; /* ignore loopback */ 197062607Sitojun if (ifcp->ifc_flags & IFF_POINTOPOINT) { 197162607Sitojun ifrt_p2p(ifcp, again); 197278064Sume return 0; 197362607Sitojun } 197462607Sitojun 197555163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 197662607Sitojun if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 197762607Sitojun#if 0 197862607Sitojun trace(1, "route: %s on %s: " 197962607Sitojun "skip linklocal interface address\n", 198062607Sitojun inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 198162607Sitojun#endif 198262607Sitojun continue; 198362607Sitojun } 198462607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 198562607Sitojun#if 0 198662607Sitojun trace(1, "route: %s: skip unspec interface address\n", 198762607Sitojun ifcp->ifc_name); 198862607Sitojun#endif 198962607Sitojun continue; 199062607Sitojun } 199178064Sume if (ifcp->ifc_flags & IFF_UP) { 199278064Sume if ((rrt = MALLOC(struct riprt)) == NULL) 199378064Sume fatal("malloc: struct riprt"); 199478064Sume memset(rrt, 0, sizeof(*rrt)); 199578064Sume rrt->rrt_same = NULL; 199678064Sume rrt->rrt_index = ifcp->ifc_index; 199778064Sume rrt->rrt_t = 0; /* don't age */ 199878064Sume rrt->rrt_info.rip6_dest = ifa->ifa_addr; 199978064Sume rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 200078064Sume rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 200178064Sume rrt->rrt_info.rip6_plen = ifa->ifa_plen; 200278064Sume rrt->rrt_flags = RTF_CLONING; 200378064Sume rrt->rrt_rflags |= RRTF_CHANGED; 200478064Sume applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 200578064Sume memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 200678064Sume#if 0 200778064Sume /* XXX why gateway address == network adddress? */ 200878064Sume rrt->rrt_gw = ifa->ifa_addr; 200978064Sume#endif 201078064Sume np = &rrt->rrt_info; 201178064Sume search_rrt = rtsearch(np, &prev_rrt); 201278064Sume if (search_rrt != NULL) { 201378064Sume if (search_rrt->rrt_info.rip6_metric > 201478064Sume rrt->rrt_info.rip6_metric) { 201578064Sume if (prev_rrt) 201678064Sume prev_rrt->rrt_next = rrt->rrt_next; 201778064Sume else 201878064Sume riprt = rrt->rrt_next; 201978064Sume delroute(&rrt->rrt_info, &rrt->rrt_gw); 202078064Sume free(rrt); 202178064Sume } else { 202278064Sume /* Already have better route */ 202378064Sume if (!again) { 202478064Sume trace(1, "route: %s/%d: " 202578064Sume "already registered (%s)\n", 202678064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 202778064Sume ifcp->ifc_name); 202878064Sume } 202978064Sume free(rrt); 203078064Sume continue; 203178064Sume } 203278064Sume } 203355163Sshin /* Attach the route to the list */ 203462607Sitojun trace(1, "route: %s/%d: register route (%s)\n", 203562607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 203662607Sitojun ifcp->ifc_name); 203755163Sshin rrt->rrt_next = riprt; 203855163Sshin riprt = rrt; 203978064Sume addroute(rrt, &rrt->rrt_gw, ifcp); 204078064Sume sendrequest(ifcp); 204178064Sume ripsend(ifcp, &ifcp->ifc_ripsin, 0); 204278064Sume need_trigger = 1; 204355163Sshin } else { 204478064Sume for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 204578064Sume if (loop_rrt->rrt_index == ifcp->ifc_index) { 204678064Sume t_lifetime = time(NULL) - RIP_LIFETIME; 204778064Sume if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 204878064Sume loop_rrt->rrt_t = t_lifetime; 204978064Sume loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 205078064Sume loop_rrt->rrt_rflags |= RRTF_CHANGED; 205178064Sume need_trigger = 1; 205278064Sume } 205378064Sume } 205455163Sshin } 205578064Sume } 205662607Sitojun } 205778064Sume return need_trigger; 205862607Sitojun} 205955163Sshin 206062607Sitojun/* 206162607Sitojun * there are couple of p2p interface routing models. "behavior" lets 206262607Sitojun * you pick one. it looks that gated behavior fits best with BSDs, 2063119035Sume * since BSD kernels do not look at prefix length on p2p interfaces. 206462607Sitojun */ 206562607Sitojunvoid 206662607Sitojunifrt_p2p(ifcp, again) 206762607Sitojun struct ifc *ifcp; 206862607Sitojun int again; 206962607Sitojun{ 207062607Sitojun struct ifac *ifa; 207178064Sume struct riprt *rrt, *orrt, *prevrrt; 207262607Sitojun struct netinfo6 *np; 207362607Sitojun struct in6_addr addr, dest; 207462607Sitojun int advert, ignore, i; 207562607Sitojun#define P2PADVERT_NETWORK 1 207662607Sitojun#define P2PADVERT_ADDR 2 207762607Sitojun#define P2PADVERT_DEST 4 207862607Sitojun#define P2PADVERT_MAX 4 207962607Sitojun const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 208078064Sume const char *category = ""; 208162607Sitojun const char *noadv; 208262607Sitojun 208362607Sitojun for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 208462607Sitojun addr = ifa->ifa_addr; 208562607Sitojun dest = ifa->ifa_raddr; 208662607Sitojun applyplen(&addr, ifa->ifa_plen); 208762607Sitojun applyplen(&dest, ifa->ifa_plen); 208862607Sitojun advert = ignore = 0; 208962607Sitojun switch (behavior) { 209062607Sitojun case CISCO: 209162607Sitojun /* 209262607Sitojun * honor addr/plen, just like normal shared medium 209362607Sitojun * interface. this may cause trouble if you reuse 209462607Sitojun * addr/plen on other interfaces. 209562607Sitojun * 209662607Sitojun * advertise addr/plen. 209762607Sitojun */ 209862607Sitojun advert |= P2PADVERT_NETWORK; 209962607Sitojun break; 210062607Sitojun case GATED: 210162607Sitojun /* 210262607Sitojun * prefixlen on p2p interface is meaningless. 210362607Sitojun * advertise addr/128 and dest/128. 210462607Sitojun * 210562607Sitojun * do not install network route to route6d routing 210662607Sitojun * table (if we do, it would prevent route installation 210762607Sitojun * for other p2p interface that shares addr/plen). 210878064Sume * 210978064Sume * XXX what should we do if dest is ::? it will not 211078064Sume * get announced anyways (see following filter), 211178064Sume * but we need to think. 211262607Sitojun */ 211362607Sitojun advert |= P2PADVERT_ADDR; 211462607Sitojun advert |= P2PADVERT_DEST; 211562607Sitojun ignore |= P2PADVERT_NETWORK; 211662607Sitojun break; 211762607Sitojun case ROUTE6D: 211862607Sitojun /* 211978064Sume * just for testing. actually the code is redundant 212078064Sume * given the current p2p interface address assignment 212178064Sume * rule for kame kernel. 212278064Sume * 212378064Sume * intent: 212478064Sume * A/n -> announce A/n 212578064Sume * A B/n, A and B share prefix -> A/n (= B/n) 212678064Sume * A B/n, do not share prefix -> A/128 and B/128 212778064Sume * actually, A/64 and A B/128 are the only cases 212878064Sume * permitted by the kernel: 212978064Sume * A/64 -> A/64 213078064Sume * A B/128 -> A/128 and B/128 213162607Sitojun */ 213278064Sume if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 213378064Sume if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 213478064Sume advert |= P2PADVERT_NETWORK; 213578064Sume else { 213678064Sume advert |= P2PADVERT_ADDR; 213778064Sume advert |= P2PADVERT_DEST; 213878064Sume ignore |= P2PADVERT_NETWORK; 213978064Sume } 214078064Sume } else 214162607Sitojun advert |= P2PADVERT_NETWORK; 214262607Sitojun break; 214362607Sitojun } 214462607Sitojun 214562607Sitojun for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 214662607Sitojun if ((ignore & i) != 0) 214762607Sitojun continue; 214878064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 214955163Sshin fatal("malloc: struct riprt"); 215078064Sume /*NOTREACHED*/ 215178064Sume } 215262607Sitojun memset(rrt, 0, sizeof(*rrt)); 215355163Sshin rrt->rrt_same = NULL; 215455163Sshin rrt->rrt_index = ifcp->ifc_index; 215562607Sitojun rrt->rrt_t = 0; /* don't age */ 215662607Sitojun switch (i) { 215762607Sitojun case P2PADVERT_NETWORK: 215862607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 215962607Sitojun rrt->rrt_info.rip6_plen = ifa->ifa_plen; 216062607Sitojun applyplen(&rrt->rrt_info.rip6_dest, 216162607Sitojun ifa->ifa_plen); 216262607Sitojun category = "network"; 216362607Sitojun break; 216462607Sitojun case P2PADVERT_ADDR: 216562607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 216662607Sitojun rrt->rrt_info.rip6_plen = 128; 216778064Sume rrt->rrt_gw = in6addr_loopback; 216862607Sitojun category = "addr"; 216962607Sitojun break; 217062607Sitojun case P2PADVERT_DEST: 217162607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 217262607Sitojun rrt->rrt_info.rip6_plen = 128; 217378064Sume rrt->rrt_gw = ifa->ifa_addr; 217462607Sitojun category = "dest"; 217562607Sitojun break; 217662607Sitojun } 217762607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 217862607Sitojun IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 217962607Sitojun#if 0 218062607Sitojun trace(1, "route: %s: skip unspec/linklocal " 218162607Sitojun "(%s on %s)\n", category, ifcp->ifc_name); 218262607Sitojun#endif 218362607Sitojun free(rrt); 218462607Sitojun continue; 218562607Sitojun } 218662607Sitojun if ((advert & i) == 0) { 218762607Sitojun rrt->rrt_rflags |= RRTF_NOADVERTISE; 218862607Sitojun noadv = ", NO-ADV"; 218962607Sitojun } else 219062607Sitojun noadv = ""; 219155163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 219262607Sitojun rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 219355163Sshin np = &rrt->rrt_info; 219478064Sume orrt = rtsearch(np, &prevrrt); 219578064Sume if (!orrt) { 219655163Sshin /* Attach the route to the list */ 219762607Sitojun trace(1, "route: %s/%d: register route " 219862607Sitojun "(%s on %s%s)\n", 219962607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 220062607Sitojun category, ifcp->ifc_name, noadv); 220155163Sshin rrt->rrt_next = riprt; 220255163Sshin riprt = rrt; 220378064Sume } else if (rrt->rrt_index != orrt->rrt_index || 220478064Sume rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 220578064Sume /* swap route */ 220678064Sume rrt->rrt_next = orrt->rrt_next; 220778064Sume if (prevrrt) 220878064Sume prevrrt->rrt_next = rrt; 220978064Sume else 221078064Sume riprt = rrt; 221178064Sume free(orrt); 221278064Sume 221378064Sume trace(1, "route: %s/%d: update (%s on %s%s)\n", 221478064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 221578064Sume category, ifcp->ifc_name, noadv); 221655163Sshin } else { 221755163Sshin /* Already found */ 221855163Sshin if (!again) { 221962607Sitojun trace(1, "route: %s/%d: " 222062607Sitojun "already registered (%s on %s%s)\n", 222162607Sitojun inet6_n2p(&np->rip6_dest), 222262607Sitojun np->rip6_plen, category, 222362607Sitojun ifcp->ifc_name, noadv); 222455163Sshin } 222555163Sshin free(rrt); 222655163Sshin } 222755163Sshin } 222855163Sshin } 222962607Sitojun#undef P2PADVERT_NETWORK 223062607Sitojun#undef P2PADVERT_ADDR 223162607Sitojun#undef P2PADVERT_DEST 223262607Sitojun#undef P2PADVERT_MAX 223355163Sshin} 223455163Sshin 223555163Sshinint 223655163Sshingetifmtu(ifindex) 223755163Sshin int ifindex; 223855163Sshin{ 223955163Sshin int mib[6]; 224055163Sshin char *buf; 224155163Sshin size_t msize; 224255163Sshin struct if_msghdr *ifm; 224355163Sshin int mtu; 224455163Sshin 224555163Sshin mib[0] = CTL_NET; 224655163Sshin mib[1] = PF_ROUTE; 224755163Sshin mib[2] = 0; 224855163Sshin mib[3] = AF_INET6; 224955163Sshin mib[4] = NET_RT_IFLIST; 225055163Sshin mib[5] = ifindex; 225178064Sume if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 225255163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 225378064Sume /*NOTREACHED*/ 225478064Sume } 225578064Sume if ((buf = malloc(msize)) == NULL) { 225655163Sshin fatal("malloc"); 225778064Sume /*NOTREACHED*/ 225878064Sume } 225978064Sume if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 226055163Sshin fatal("sysctl NET_RT_IFLIST"); 226178064Sume /*NOTREACHED*/ 226278064Sume } 226355163Sshin ifm = (struct if_msghdr *)buf; 226455163Sshin mtu = ifm->ifm_data.ifi_mtu; 226578064Sume#ifdef __FreeBSD__ 226678064Sume if (ifindex != ifm->ifm_index) { 226755163Sshin fatal("ifindex does not match with ifm_index"); 226878064Sume /*NOTREACHED*/ 226978064Sume } 227078064Sume#endif 227155163Sshin free(buf); 227255163Sshin return mtu; 227355163Sshin} 227455163Sshin 227555163Sshinconst char * 227655163Sshinrttypes(rtm) 227755163Sshin struct rt_msghdr *rtm; 227855163Sshin{ 227962607Sitojun#define RTTYPE(s, f) \ 228062607Sitojundo { \ 228162607Sitojun if (rtm->rtm_type == (f)) \ 228262607Sitojun return (s); \ 228362607Sitojun} while (0) 228455163Sshin RTTYPE("ADD", RTM_ADD); 228555163Sshin RTTYPE("DELETE", RTM_DELETE); 228655163Sshin RTTYPE("CHANGE", RTM_CHANGE); 228755163Sshin RTTYPE("GET", RTM_GET); 228855163Sshin RTTYPE("LOSING", RTM_LOSING); 228955163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 229055163Sshin RTTYPE("MISS", RTM_MISS); 229155163Sshin RTTYPE("LOCK", RTM_LOCK); 229255163Sshin RTTYPE("OLDADD", RTM_OLDADD); 229355163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 229455163Sshin RTTYPE("RESOLVE", RTM_RESOLVE); 229555163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 229655163Sshin RTTYPE("DELADDR", RTM_DELADDR); 229755163Sshin RTTYPE("IFINFO", RTM_IFINFO); 229878064Sume#ifdef RTM_OLDADD 229978064Sume RTTYPE("OLDADD", RTM_OLDADD); 230078064Sume#endif 230178064Sume#ifdef RTM_OLDDEL 230278064Sume RTTYPE("OLDDEL", RTM_OLDDEL); 230378064Sume#endif 230478064Sume#ifdef RTM_OIFINFO 230578064Sume RTTYPE("OIFINFO", RTM_OIFINFO); 230678064Sume#endif 230778064Sume#ifdef RTM_IFANNOUNCE 230878064Sume RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 230978064Sume#endif 231078064Sume#ifdef RTM_NEWMADDR 231178064Sume RTTYPE("NEWMADDR", RTM_NEWMADDR); 231278064Sume#endif 231378064Sume#ifdef RTM_DELMADDR 231478064Sume RTTYPE("DELMADDR", RTM_DELMADDR); 231578064Sume#endif 231655163Sshin#undef RTTYPE 231755163Sshin return NULL; 231855163Sshin} 231955163Sshin 232055163Sshinconst char * 232155163Sshinrtflags(rtm) 232255163Sshin struct rt_msghdr *rtm; 232355163Sshin{ 232455163Sshin static char buf[BUFSIZ]; 232555163Sshin 232678064Sume /* 232778064Sume * letter conflict should be okay. painful when *BSD diverges... 232878064Sume */ 232978064Sume strlcpy(buf, "", sizeof(buf)); 233062607Sitojun#define RTFLAG(s, f) \ 233162607Sitojundo { \ 233262607Sitojun if (rtm->rtm_flags & (f)) \ 233378064Sume strlcat(buf, (s), sizeof(buf)); \ 233462607Sitojun} while (0) 233555163Sshin RTFLAG("U", RTF_UP); 233655163Sshin RTFLAG("G", RTF_GATEWAY); 233755163Sshin RTFLAG("H", RTF_HOST); 233855163Sshin RTFLAG("R", RTF_REJECT); 233955163Sshin RTFLAG("D", RTF_DYNAMIC); 234055163Sshin RTFLAG("M", RTF_MODIFIED); 234155163Sshin RTFLAG("d", RTF_DONE); 234255163Sshin#ifdef RTF_MASK 234355163Sshin RTFLAG("m", RTF_MASK); 234455163Sshin#endif 234555163Sshin RTFLAG("C", RTF_CLONING); 234678064Sume#ifdef RTF_CLONED 234778064Sume RTFLAG("c", RTF_CLONED); 234878064Sume#endif 234978064Sume#ifdef RTF_PRCLONING 235078064Sume RTFLAG("c", RTF_PRCLONING); 235178064Sume#endif 235278064Sume#ifdef RTF_WASCLONED 235378064Sume RTFLAG("W", RTF_WASCLONED); 235478064Sume#endif 235555163Sshin RTFLAG("X", RTF_XRESOLVE); 235655163Sshin RTFLAG("L", RTF_LLINFO); 235755163Sshin RTFLAG("S", RTF_STATIC); 235855163Sshin RTFLAG("B", RTF_BLACKHOLE); 235978064Sume#ifdef RTF_PROTO3 236078064Sume RTFLAG("3", RTF_PROTO3); 236178064Sume#endif 236255163Sshin RTFLAG("2", RTF_PROTO2); 236355163Sshin RTFLAG("1", RTF_PROTO1); 236478064Sume#ifdef RTF_BROADCAST 236578064Sume RTFLAG("b", RTF_BROADCAST); 236678064Sume#endif 236778064Sume#ifdef RTF_DEFAULT 236878064Sume RTFLAG("d", RTF_DEFAULT); 236978064Sume#endif 237078064Sume#ifdef RTF_ISAROUTER 237178064Sume RTFLAG("r", RTF_ISAROUTER); 237278064Sume#endif 237378064Sume#ifdef RTF_TUNNEL 237478064Sume RTFLAG("T", RTF_TUNNEL); 237578064Sume#endif 237678064Sume#ifdef RTF_AUTH 237778064Sume RTFLAG("A", RTF_AUTH); 237878064Sume#endif 237978064Sume#ifdef RTF_CRYPT 238078064Sume RTFLAG("E", RTF_CRYPT); 238178064Sume#endif 238255163Sshin#undef RTFLAG 238355163Sshin return buf; 238455163Sshin} 238555163Sshin 238655163Sshinconst char * 238755163Sshinifflags(flags) 238855163Sshin int flags; 238955163Sshin{ 239055163Sshin static char buf[BUFSIZ]; 239155163Sshin 239278064Sume strlcpy(buf, "", sizeof(buf)); 239362607Sitojun#define IFFLAG(s, f) \ 239462607Sitojundo { \ 2395119040Sume if (flags & (f)) { \ 239662607Sitojun if (buf[0]) \ 239778064Sume strlcat(buf, ",", sizeof(buf)); \ 2398119040Sume strlcat(buf, (s), sizeof(buf)); \ 239962607Sitojun } \ 240062607Sitojun} while (0) 240155163Sshin IFFLAG("UP", IFF_UP); 240255163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 240355163Sshin IFFLAG("DEBUG", IFF_DEBUG); 240455163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 240555163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 240655163Sshin#ifdef IFF_NOTRAILERS 240755163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 240855163Sshin#endif 240978064Sume#ifdef IFF_SMART 241078064Sume IFFLAG("SMART", IFF_SMART); 241178064Sume#endif 241255163Sshin IFFLAG("RUNNING", IFF_RUNNING); 241355163Sshin IFFLAG("NOARP", IFF_NOARP); 241455163Sshin IFFLAG("PROMISC", IFF_PROMISC); 241555163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 241655163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 241755163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 241855163Sshin IFFLAG("LINK0", IFF_LINK0); 241955163Sshin IFFLAG("LINK1", IFF_LINK1); 242055163Sshin IFFLAG("LINK2", IFF_LINK2); 242155163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 242255163Sshin#undef IFFLAG 242355163Sshin return buf; 242455163Sshin} 242555163Sshin 242655163Sshinvoid 242755163Sshinkrtread(again) 242855163Sshin int again; 242955163Sshin{ 243055163Sshin int mib[6]; 243155163Sshin size_t msize; 243255163Sshin char *buf, *p, *lim; 243355163Sshin struct rt_msghdr *rtm; 243455163Sshin int retry; 243555163Sshin const char *errmsg; 243655163Sshin 243755163Sshin retry = 0; 243855163Sshin buf = NULL; 243955163Sshin mib[0] = CTL_NET; 244055163Sshin mib[1] = PF_ROUTE; 244155163Sshin mib[2] = 0; 244255163Sshin mib[3] = AF_INET6; /* Address family */ 244355163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 244455163Sshin mib[5] = 0; /* No flags */ 244555163Sshin do { 244655163Sshin retry++; 244755163Sshin errmsg = NULL; 244855163Sshin if (buf) 244955163Sshin free(buf); 245055163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 245155163Sshin errmsg = "sysctl estimate"; 245255163Sshin continue; 245355163Sshin } 245455163Sshin if ((buf = malloc(msize)) == NULL) { 245555163Sshin errmsg = "malloc"; 245655163Sshin continue; 245755163Sshin } 245855163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 245955163Sshin errmsg = "sysctl NET_RT_DUMP"; 246055163Sshin continue; 246155163Sshin } 246255163Sshin } while (retry < 5 && errmsg != NULL); 246378064Sume if (errmsg) { 246469279Sume fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 246569279Sume (u_long)msize); 246678064Sume /*NOTREACHED*/ 246778064Sume } else if (1 < retry) 246855163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 246955163Sshin 247055163Sshin lim = buf + msize; 247155163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 247255163Sshin rtm = (struct rt_msghdr *)p; 247355163Sshin rt_entry(rtm, again); 247455163Sshin } 247555163Sshin free(buf); 247655163Sshin} 247755163Sshin 247855163Sshinvoid 247955163Sshinrt_entry(rtm, again) 248055163Sshin struct rt_msghdr *rtm; 248155163Sshin int again; 248255163Sshin{ 248355163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 248455163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 248555163Sshin char *rtmp, *ifname = NULL; 248678064Sume struct riprt *rrt, *orrt; 248755163Sshin struct netinfo6 *np; 248855163Sshin int s; 248955163Sshin 249055163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 249155163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 249262607Sitojun (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) { 249355163Sshin return; /* not interested in the link route */ 249462607Sitojun } 249569279Sume /* do not look at cloned routes */ 249669279Sume#ifdef RTF_WASCLONED 249769279Sume if (rtm->rtm_flags & RTF_WASCLONED) 249869279Sume return; 249969279Sume#endif 250069279Sume#ifdef RTF_CLONED 250169279Sume if (rtm->rtm_flags & RTF_CLONED) 250269279Sume return; 250369279Sume#endif 250469279Sume /* 250569279Sume * do not look at dynamic routes. 250669279Sume * netbsd/openbsd cloned routes have UGHD. 250769279Sume */ 250869279Sume if (rtm->rtm_flags & RTF_DYNAMIC) 250969279Sume return; 251055163Sshin rtmp = (char *)(rtm + 1); 251155163Sshin /* Destination */ 251255163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 251355163Sshin return; /* ignore routes without destination address */ 251455163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 251564631Sitojun rtmp += ROUNDUP(sin6_dst->sin6_len); 251655163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 251755163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 251855163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 251955163Sshin } 252055163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 252155163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 252255163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 252355163Sshin } 252455163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 252555163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 252655163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 252755163Sshin } 252855163Sshin if (rtm->rtm_addrs & RTA_IFP) { 252955163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 253055163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 253155163Sshin } 253255163Sshin 253355163Sshin /* Destination */ 253455163Sshin if (sin6_dst->sin6_family != AF_INET6) 253555163Sshin return; 253655163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 253755163Sshin return; /* Link-local */ 253855163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 253955163Sshin return; /* Loopback */ 254055163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 254155163Sshin return; 254255163Sshin 254378064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 254455163Sshin fatal("malloc: struct riprt"); 254578064Sume /*NOTREACHED*/ 254678064Sume } 254762607Sitojun memset(rrt, 0, sizeof(*rrt)); 254855163Sshin np = &rrt->rrt_info; 254955163Sshin rrt->rrt_same = NULL; 255055163Sshin rrt->rrt_t = time(NULL); 255155163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 255255163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 255355163Sshin np->rip6_tag = 0; 255455163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 255555163Sshin if (np->rip6_metric < 1) 255655163Sshin np->rip6_metric = 1; 255755163Sshin rrt->rrt_flags = rtm->rtm_flags; 255855163Sshin np->rip6_dest = sin6_dst->sin6_addr; 255955163Sshin 256055163Sshin /* Mask or plen */ 256155163Sshin if (rtm->rtm_flags & RTF_HOST) 256255163Sshin np->rip6_plen = 128; /* Host route */ 256378064Sume else if (sin6_mask) 256478064Sume np->rip6_plen = sin6mask2len(sin6_mask); 256578064Sume else 256655163Sshin np->rip6_plen = 0; 256755163Sshin 256878064Sume orrt = rtsearch(np, NULL); 256978064Sume if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 257055163Sshin /* Already found */ 257155163Sshin if (!again) { 257255163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 257355163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 257455163Sshin rtflags(rtm)); 257555163Sshin } 257655163Sshin free(rrt); 257755163Sshin return; 257855163Sshin } 257955163Sshin /* Gateway */ 258055163Sshin if (!sin6_gw) 258155163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 258255163Sshin else { 258355163Sshin if (sin6_gw->sin6_family == AF_INET6) 258455163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 258555163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 258655163Sshin /* XXX in case ppp link? */ 258755163Sshin rrt->rrt_gw = in6addr_loopback; 258855163Sshin } else 258955163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 259055163Sshin } 259155163Sshin trace(1, "route: %s/%d flags %s", 259255163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 259355163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 259455163Sshin 259555163Sshin /* Interface */ 259655163Sshin s = rtm->rtm_index; 259755163Sshin if (s < nindex2ifc && index2ifc[s]) 259855163Sshin ifname = index2ifc[s]->ifc_name; 259958070Sshin else { 260058070Sshin trace(1, " not configured\n"); 260162607Sitojun free(rrt); 260258070Sshin return; 260358070Sshin } 260462607Sitojun trace(1, " if %s sock %d", ifname, s); 260555163Sshin rrt->rrt_index = s; 260655163Sshin 260762607Sitojun trace(1, "\n"); 260862607Sitojun 260955163Sshin /* Check gateway */ 261055163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 261155163Sshin !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) 261255163Sshin#ifdef __FreeBSD__ 261355163Sshin && (rrt->rrt_flags & RTF_LOCAL) == 0 261455163Sshin#endif 261555163Sshin ) { 261655163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 261755163Sshin inet6_n2p(&rrt->rrt_gw)); 261855163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 261962607Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 262062607Sitojun rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 262155163Sshin } 262255163Sshin 262355163Sshin /* Put it to the route list */ 262478064Sume if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 262578064Sume /* replace route list */ 262678064Sume rrt->rrt_next = orrt->rrt_next; 262778064Sume *orrt = *rrt; 262878064Sume trace(1, "route: %s/%d flags %s: replace new route\n", 262978064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 263078064Sume rtflags(rtm)); 263178064Sume free(rrt); 263278064Sume } else { 263378064Sume rrt->rrt_next = riprt; 263478064Sume riprt = rrt; 263578064Sume } 263655163Sshin} 263755163Sshin 263855163Sshinint 263955163Sshinaddroute(rrt, gw, ifcp) 264055163Sshin struct riprt *rrt; 264155163Sshin const struct in6_addr *gw; 264255163Sshin struct ifc *ifcp; 264355163Sshin{ 264455163Sshin struct netinfo6 *np; 264555163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 264655163Sshin struct rt_msghdr *rtm; 2647119031Sume struct sockaddr_in6 *sin6; 264855163Sshin int len; 264955163Sshin 265055163Sshin np = &rrt->rrt_info; 265178064Sume inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 265255163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 265355163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 265455163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 265555163Sshin np->rip6_metric - 1, buf2); 265655163Sshin if (rtlog) 265755163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 265855163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 265955163Sshin np->rip6_metric - 1, buf2); 266055163Sshin if (nflag) 266155163Sshin return 0; 266255163Sshin 266355163Sshin memset(buf, 0, sizeof(buf)); 266455163Sshin rtm = (struct rt_msghdr *)buf; 266555163Sshin rtm->rtm_type = RTM_ADD; 266655163Sshin rtm->rtm_version = RTM_VERSION; 266755163Sshin rtm->rtm_seq = ++seq; 266855163Sshin rtm->rtm_pid = pid; 266962607Sitojun rtm->rtm_flags = rrt->rrt_flags; 267055163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 267155163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 267255163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 2673119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 267455163Sshin /* Destination */ 2675119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2676119031Sume sin6->sin6_family = AF_INET6; 2677119031Sume sin6->sin6_addr = np->rip6_dest; 2678119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 267955163Sshin /* Gateway */ 2680119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2681119031Sume sin6->sin6_family = AF_INET6; 2682119031Sume sin6->sin6_addr = *gw; 2683119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 268455163Sshin /* Netmask */ 2685119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2686119031Sume sin6->sin6_family = AF_INET6; 2687119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2688119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 268955163Sshin 2690119031Sume len = (char *)sin6 - (char *)buf; 269155163Sshin rtm->rtm_msglen = len; 269255163Sshin if (write(rtsock, buf, len) > 0) 269355163Sshin return 0; 269455163Sshin 269555163Sshin if (errno == EEXIST) { 269655163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 2697119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 269855163Sshin if (rtlog) 269955163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2700119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 270155163Sshin } else { 270255163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 2703119035Sume strerror(errno)); 270455163Sshin if (rtlog) 270555163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2706119035Sume strerror(errno)); 270755163Sshin } 270855163Sshin return -1; 270955163Sshin} 271055163Sshin 271155163Sshinint 271255163Sshindelroute(np, gw) 271355163Sshin struct netinfo6 *np; 271455163Sshin struct in6_addr *gw; 271555163Sshin{ 271655163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 271755163Sshin struct rt_msghdr *rtm; 2718119031Sume struct sockaddr_in6 *sin6; 271955163Sshin int len; 272055163Sshin 272155163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 272255163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 272355163Sshin np->rip6_plen, buf2); 272455163Sshin if (rtlog) 272555163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 272655163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 272755163Sshin if (nflag) 272855163Sshin return 0; 272955163Sshin 273055163Sshin memset(buf, 0, sizeof(buf)); 273155163Sshin rtm = (struct rt_msghdr *)buf; 273255163Sshin rtm->rtm_type = RTM_DELETE; 273355163Sshin rtm->rtm_version = RTM_VERSION; 273455163Sshin rtm->rtm_seq = ++seq; 273555163Sshin rtm->rtm_pid = pid; 273655163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 273778064Sume if (np->rip6_plen == sizeof(struct in6_addr) * 8) 273878064Sume rtm->rtm_flags |= RTF_HOST; 273955163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2740119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 274155163Sshin /* Destination */ 2742119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2743119031Sume sin6->sin6_family = AF_INET6; 2744119031Sume sin6->sin6_addr = np->rip6_dest; 2745119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 274655163Sshin /* Gateway */ 2747119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2748119031Sume sin6->sin6_family = AF_INET6; 2749119031Sume sin6->sin6_addr = *gw; 2750119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 275155163Sshin /* Netmask */ 2752119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2753119031Sume sin6->sin6_family = AF_INET6; 2754119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2755119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 275655163Sshin 2757119031Sume len = (char *)sin6 - (char *)buf; 275855163Sshin rtm->rtm_msglen = len; 275955163Sshin if (write(rtsock, buf, len) >= 0) 276055163Sshin return 0; 276155163Sshin 276255163Sshin if (errno == ESRCH) { 276355163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2764119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 276555163Sshin if (rtlog) 276655163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2767119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 276855163Sshin } else { 276955163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 2770119035Sume strerror(errno)); 277155163Sshin if (rtlog) 277255163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2773119035Sume strerror(errno)); 277455163Sshin } 277555163Sshin return -1; 277655163Sshin} 277755163Sshin 277855163Sshinstruct in6_addr * 277955163Sshingetroute(np, gw) 278055163Sshin struct netinfo6 *np; 278155163Sshin struct in6_addr *gw; 278255163Sshin{ 278355163Sshin u_char buf[BUFSIZ]; 278455163Sshin u_long myseq; 278555163Sshin int len; 278655163Sshin struct rt_msghdr *rtm; 2787119031Sume struct sockaddr_in6 *sin6; 278855163Sshin 278955163Sshin rtm = (struct rt_msghdr *)buf; 279055163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 279155163Sshin memset(rtm, 0, len); 279255163Sshin rtm->rtm_type = RTM_GET; 279355163Sshin rtm->rtm_version = RTM_VERSION; 279455163Sshin myseq = ++seq; 279555163Sshin rtm->rtm_seq = myseq; 279655163Sshin rtm->rtm_addrs = RTA_DST; 279755163Sshin rtm->rtm_msglen = len; 2798119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2799119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2800119031Sume sin6->sin6_family = AF_INET6; 2801119031Sume sin6->sin6_addr = np->rip6_dest; 280255163Sshin if (write(rtsock, buf, len) < 0) { 280355163Sshin if (errno == ESRCH) /* No such route found */ 280455163Sshin return NULL; 280555163Sshin perror("write to rtsock"); 280678064Sume exit(1); 280755163Sshin } 280855163Sshin do { 280955163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 281055163Sshin perror("read from rtsock"); 281178064Sume exit(1); 281255163Sshin } 281355163Sshin rtm = (struct rt_msghdr *)buf; 281455163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 2815119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 281655163Sshin if (rtm->rtm_addrs & RTA_DST) { 2817119031Sume sin6 = (struct sockaddr_in6 *) 2818119031Sume ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 281955163Sshin } 282055163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 2821119031Sume *gw = sin6->sin6_addr; 282255163Sshin return gw; 282355163Sshin } 282455163Sshin return NULL; 282555163Sshin} 282655163Sshin 282755163Sshinconst char * 282855163Sshininet6_n2p(p) 282955163Sshin const struct in6_addr *p; 283055163Sshin{ 283155163Sshin static char buf[BUFSIZ]; 283255163Sshin 283378064Sume return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 283455163Sshin} 283555163Sshin 283655163Sshinvoid 283755163Sshinifrtdump(sig) 283855163Sshin int sig; 283955163Sshin{ 284055163Sshin 284155163Sshin ifdump(sig); 284255163Sshin rtdump(sig); 284355163Sshin} 284455163Sshin 284555163Sshinvoid 284655163Sshinifdump(sig) 284755163Sshin int sig; 284855163Sshin{ 284955163Sshin struct ifc *ifcp; 285055163Sshin FILE *dump; 285155163Sshin int i; 285255163Sshin 285355163Sshin if (sig == 0) 285455163Sshin dump = stderr; 285555163Sshin else 285655163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 285755163Sshin dump = stderr; 285855163Sshin 285955163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 286055163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 286155163Sshin for (i = 0; i < 2; i++) { 286255163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 286355163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 286455163Sshin if (i == 0) { 286555163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 286655163Sshin continue; 286755163Sshin if (iff_find(ifcp, 'N') != NULL) 286855163Sshin continue; 286955163Sshin } else { 287055163Sshin if (ifcp->ifc_flags & IFF_UP) 287155163Sshin continue; 287255163Sshin } 287355163Sshin ifdump0(dump, ifcp); 287455163Sshin } 287555163Sshin } 287655163Sshin fprintf(dump, "\n"); 287755163Sshin if (dump != stderr) 287855163Sshin fclose(dump); 287955163Sshin} 288055163Sshin 288155163Sshinvoid 288255163Sshinifdump0(dump, ifcp) 288355163Sshin FILE *dump; 288455163Sshin const struct ifc *ifcp; 288555163Sshin{ 288655163Sshin struct ifac *ifa; 288755163Sshin struct iff *iffp; 288855163Sshin char buf[BUFSIZ]; 288955163Sshin const char *ft; 289055163Sshin int addr; 289155163Sshin 289255163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 289355163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 289455163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 289555163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 289655163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 289755163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 289855163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 289955163Sshin buf, sizeof(buf)); 290055163Sshin fprintf(dump, "\t%s/%d -- %s\n", 290155163Sshin inet6_n2p(&ifa->ifa_addr), 290255163Sshin ifa->ifa_plen, buf); 290355163Sshin } else { 290455163Sshin fprintf(dump, "\t%s/%d\n", 290555163Sshin inet6_n2p(&ifa->ifa_addr), 290655163Sshin ifa->ifa_plen); 290755163Sshin } 290855163Sshin } 290955163Sshin if (ifcp->ifc_filter) { 291055163Sshin fprintf(dump, "\tFilter:"); 291155163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 291255163Sshin addr = 0; 291355163Sshin switch (iffp->iff_type) { 291455163Sshin case 'A': 291555163Sshin ft = "Aggregate"; addr++; break; 291655163Sshin case 'N': 291778064Sume ft = "No-use"; break; 291855163Sshin case 'O': 291955163Sshin ft = "Advertise-only"; addr++; break; 292055163Sshin case 'T': 292155163Sshin ft = "Default-only"; break; 292255163Sshin case 'L': 292355163Sshin ft = "Listen-only"; addr++; break; 292455163Sshin default: 292555163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 292655163Sshin ft = buf; 292755163Sshin addr++; 292855163Sshin break; 292955163Sshin } 293055163Sshin fprintf(dump, " %s", ft); 293155163Sshin if (addr) { 293255163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 293355163Sshin iffp->iff_plen); 293455163Sshin } 293555163Sshin } 293655163Sshin fprintf(dump, "\n"); 293755163Sshin } 293855163Sshin} 293955163Sshin 294055163Sshinvoid 294155163Sshinrtdump(sig) 294255163Sshin int sig; 294355163Sshin{ 294455163Sshin struct riprt *rrt; 294555163Sshin char buf[BUFSIZ]; 294655163Sshin FILE *dump; 294755163Sshin time_t t, age; 294855163Sshin 294955163Sshin if (sig == 0) 295055163Sshin dump = stderr; 295155163Sshin else 295255163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 295355163Sshin dump = stderr; 295455163Sshin 295555163Sshin t = time(NULL); 295655163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 295755163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 295855163Sshin if (rrt->rrt_t == 0) 295955163Sshin age = 0; 296055163Sshin else 296155163Sshin age = t - rrt->rrt_t; 296255163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 296355163Sshin buf, sizeof(buf)); 296455163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 296555163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 296655163Sshin index2ifc[rrt->rrt_index]->ifc_name, 296755163Sshin inet6_n2p(&rrt->rrt_gw), 296855163Sshin rrt->rrt_info.rip6_metric, (long)age); 296955163Sshin if (rrt->rrt_info.rip6_tag) { 297055163Sshin fprintf(dump, " tag(0x%04x)", 297155163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 297255163Sshin } 297362607Sitojun if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 297455163Sshin fprintf(dump, " NOT-LL"); 297562607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 297655163Sshin fprintf(dump, " NO-ADV"); 297755163Sshin fprintf(dump, "\n"); 297855163Sshin } 297955163Sshin fprintf(dump, "\n"); 298055163Sshin if (dump != stderr) 298155163Sshin fclose(dump); 298255163Sshin} 298355163Sshin 298455163Sshin/* 298555163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 298678064Sume * specified interface structures. Each of the -A/O option has the following 298755163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 298855163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 298955163Sshin */ 299055163Sshinvoid 299155163Sshinfilterconfig() 299255163Sshin{ 299355163Sshin int i; 299455163Sshin char *p, *ap, *iflp, *ifname; 299578064Sume struct iff ftmp, *iff_obj; 299678064Sume struct ifc *ifcp; 299778064Sume struct riprt *rrt; 299864631Sitojun#if 0 299978064Sume struct in6_addr gw; 300064631Sitojun#endif 300155163Sshin 300255163Sshin for (i = 0; i < nfilter; i++) { 300355163Sshin ap = filter[i]; 300455163Sshin iflp = NULL; 300555163Sshin ifcp = NULL; 300655163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 300755163Sshin iflp = ap; 300855163Sshin goto ifonly; 300955163Sshin } 3010119038Sume if ((p = strchr(ap, ',')) != NULL) { 301155163Sshin *p++ = '\0'; 301255163Sshin iflp = p; 301355163Sshin } 3014119038Sume if ((p = strchr(ap, '/')) == NULL) { 301555163Sshin fatal("no prefixlen specified for '%s'", ap); 301678064Sume /*NOTREACHED*/ 301778064Sume } 301855163Sshin *p++ = '\0'; 301978064Sume if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 302055163Sshin fatal("invalid prefix specified for '%s'", ap); 302178064Sume /*NOTREACHED*/ 302278064Sume } 302355163Sshin ftmp.iff_plen = atoi(p); 302455163Sshin ftmp.iff_next = NULL; 302555163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 302655163Sshinifonly: 302755163Sshin ftmp.iff_type = filtertype[i]; 302878064Sume if (iflp == NULL || *iflp == '\0') { 302955163Sshin fatal("no interface specified for '%s'", ap); 303078064Sume /*NOTREACHED*/ 303178064Sume } 303255163Sshin /* parse the interface listing portion */ 303355163Sshin while (iflp) { 303455163Sshin ifname = iflp; 3035119038Sume if ((iflp = strchr(iflp, ',')) != NULL) 303655163Sshin *iflp++ = '\0'; 303755163Sshin ifcp = ifc_find(ifname); 303878064Sume if (ifcp == NULL) { 303955163Sshin fatal("no interface %s exists", ifname); 304078064Sume /*NOTREACHED*/ 304178064Sume } 304255163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 304378064Sume if (iff_obj == NULL) { 304455163Sshin fatal("malloc of iff_obj"); 304578064Sume /*NOTREACHED*/ 304678064Sume } 304755163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 304878064Sume sizeof(struct iff)); 304955163Sshin /* link it to the interface filter */ 305055163Sshin iff_obj->iff_next = ifcp->ifc_filter; 305155163Sshin ifcp->ifc_filter = iff_obj; 305255163Sshin } 305378064Sume 305478064Sume /* 305578064Sume * -A: aggregate configuration. 305678064Sume */ 305755163Sshin if (filtertype[i] != 'A') 305855163Sshin continue; 305955163Sshin /* put the aggregate to the kernel routing table */ 306055163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 306178064Sume if (rrt == NULL) { 306255163Sshin fatal("malloc: rrt"); 306378064Sume /*NOTREACHED*/ 306478064Sume } 306555163Sshin memset(rrt, 0, sizeof(struct riprt)); 306655163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 306755163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 306855163Sshin rrt->rrt_info.rip6_metric = 1; 306955163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 307055163Sshin rrt->rrt_gw = in6addr_loopback; 307162607Sitojun rrt->rrt_flags = RTF_UP | RTF_REJECT; 307262607Sitojun rrt->rrt_rflags = RRTF_AGGREGATE; 307355163Sshin rrt->rrt_t = 0; 3074119039Sume rrt->rrt_index = loopifcp->ifc_index; 307564631Sitojun#if 0 307664631Sitojun if (getroute(&rrt->rrt_info, &gw)) { 307764631Sitojun#if 0 307864631Sitojun /* 307964631Sitojun * When the address has already been registered in the 308064631Sitojun * kernel routing table, it should be removed 308164631Sitojun */ 308264631Sitojun delroute(&rrt->rrt_info, &gw); 308364631Sitojun#else 308478064Sume /* it is safer behavior */ 308564631Sitojun errno = EINVAL; 308664631Sitojun fatal("%s/%u already in routing table, " 308764631Sitojun "cannot aggregate", 308864631Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), 308964631Sitojun rrt->rrt_info.rip6_plen); 309078064Sume /*NOTREACHED*/ 309164631Sitojun#endif 309264631Sitojun } 309364631Sitojun#endif 309455163Sshin /* Put the route to the list */ 309555163Sshin rrt->rrt_next = riprt; 309655163Sshin riprt = rrt; 309755163Sshin trace(1, "Aggregate: %s/%d for %s\n", 309855163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 309955163Sshin ifcp->ifc_name); 310055163Sshin /* Add this route to the kernel */ 310155163Sshin if (nflag) /* do not modify kernel routing table */ 310255163Sshin continue; 310355163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 310455163Sshin } 310555163Sshin} 310655163Sshin 310755163Sshin/***************** utility functions *****************/ 310855163Sshin 310955163Sshin/* 311055163Sshin * Returns a pointer to ifac whose address and prefix length matches 311155163Sshin * with the address and prefix length specified in the arguments. 311255163Sshin */ 311355163Sshinstruct ifac * 311455163Sshinifa_match(ifcp, ia, plen) 311555163Sshin const struct ifc *ifcp; 311655163Sshin const struct in6_addr *ia; 311755163Sshin int plen; 311855163Sshin{ 311955163Sshin struct ifac *ifa; 312055163Sshin 312155163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 312255163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 312355163Sshin ifa->ifa_plen == plen) 312455163Sshin break; 312555163Sshin } 312655163Sshin return ifa; 312755163Sshin} 312855163Sshin 312955163Sshin/* 313055163Sshin * Return a pointer to riprt structure whose address and prefix length 313155163Sshin * matches with the address and prefix length found in the argument. 313278064Sume * Note: This is not a rtalloc(). Therefore exact match is necessary. 313355163Sshin */ 313455163Sshinstruct riprt * 313578064Sumertsearch(np, prev_rrt) 313655163Sshin struct netinfo6 *np; 313778064Sume struct riprt **prev_rrt; 313855163Sshin{ 313955163Sshin struct riprt *rrt; 314055163Sshin 314178064Sume if (prev_rrt) 314278064Sume *prev_rrt = NULL; 314355163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 314455163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 314555163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 314655163Sshin &np->rip6_dest)) 314755163Sshin return rrt; 314878064Sume if (prev_rrt) 314978064Sume *prev_rrt = rrt; 315055163Sshin } 315178064Sume if (prev_rrt) 315278064Sume *prev_rrt = NULL; 315355163Sshin return 0; 315455163Sshin} 315555163Sshin 315655163Sshinint 315778064Sumesin6mask2len(sin6) 315878064Sume const struct sockaddr_in6 *sin6; 315978064Sume{ 316078064Sume 316178064Sume return mask2len(&sin6->sin6_addr, 316278064Sume sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 316378064Sume} 316478064Sume 316578064Sumeint 316655163Sshinmask2len(addr, lenlim) 316755163Sshin const struct in6_addr *addr; 316855163Sshin int lenlim; 316955163Sshin{ 317055163Sshin int i = 0, j; 317178064Sume const u_char *p = (const u_char *)addr; 317262607Sitojun 317355163Sshin for (j = 0; j < lenlim; j++, p++) { 317455163Sshin if (*p != 0xff) 317555163Sshin break; 317655163Sshin i += 8; 317755163Sshin } 317855163Sshin if (j < lenlim) { 317955163Sshin switch (*p) { 318062607Sitojun#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 318162607Sitojun MASKLEN(0xfe, 7); break; 318262607Sitojun MASKLEN(0xfc, 6); break; 318362607Sitojun MASKLEN(0xf8, 5); break; 318462607Sitojun MASKLEN(0xf0, 4); break; 318562607Sitojun MASKLEN(0xe0, 3); break; 318662607Sitojun MASKLEN(0xc0, 2); break; 318762607Sitojun MASKLEN(0x80, 1); break; 318855163Sshin#undef MASKLEN 318955163Sshin } 319055163Sshin } 319155163Sshin return i; 319255163Sshin} 319355163Sshin 319455163Sshinvoid 319555163Sshinapplymask(addr, mask) 319655163Sshin struct in6_addr *addr, *mask; 319755163Sshin{ 319855163Sshin int i; 319955163Sshin u_long *p, *q; 320055163Sshin 320155163Sshin p = (u_long *)addr; q = (u_long *)mask; 320255163Sshin for (i = 0; i < 4; i++) 320355163Sshin *p++ &= *q++; 320455163Sshin} 320555163Sshin 320655163Sshinstatic const u_char plent[8] = { 320755163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 320855163Sshin}; 320955163Sshin 321055163Sshinvoid 321155163Sshinapplyplen(ia, plen) 321255163Sshin struct in6_addr *ia; 321355163Sshin int plen; 321455163Sshin{ 321555163Sshin u_char *p; 321655163Sshin int i; 321755163Sshin 321855163Sshin p = ia->s6_addr; 321955163Sshin for (i = 0; i < 16; i++) { 322055163Sshin if (plen <= 0) 322155163Sshin *p = 0; 322255163Sshin else if (plen < 8) 322355163Sshin *p &= plent[plen]; 322455163Sshin p++, plen -= 8; 322555163Sshin } 322655163Sshin} 322755163Sshin 322855163Sshinstatic const int pl2m[9] = { 322955163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 323055163Sshin}; 323155163Sshin 323255163Sshinstruct in6_addr * 323355163Sshinplen2mask(n) 323455163Sshin int n; 323555163Sshin{ 323655163Sshin static struct in6_addr ia; 323755163Sshin u_char *p; 323855163Sshin int i; 323955163Sshin 324055163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 324155163Sshin p = (u_char *)&ia; 324255163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 324355163Sshin if (n >= 8) { 324455163Sshin *p = 0xff; 324555163Sshin continue; 324655163Sshin } 324755163Sshin *p = pl2m[n]; 324855163Sshin break; 324955163Sshin } 325055163Sshin return &ia; 325155163Sshin} 325255163Sshin 325355163Sshinchar * 325455163Sshinallocopy(p) 325555163Sshin char *p; 325655163Sshin{ 3257119033Sume int len = strlen(p) + 1; 3258119033Sume char *q = (char *)malloc(len); 325955163Sshin 3260119033Sume if (!q) { 3261119033Sume fatal("malloc"); 3262119033Sume /*NOTREACHED*/ 3263119033Sume } 3264119033Sume 3265119033Sume strlcpy(q, p, len); 326655163Sshin return q; 326755163Sshin} 326855163Sshin 326955163Sshinchar * 327055163Sshinhms() 327155163Sshin{ 327255163Sshin static char buf[BUFSIZ]; 327355163Sshin time_t t; 327455163Sshin struct tm *tm; 327555163Sshin 327655163Sshin t = time(NULL); 327778064Sume if ((tm = localtime(&t)) == 0) { 327855163Sshin fatal("localtime"); 327978064Sume /*NOTREACHED*/ 328078064Sume } 328178064Sume snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 328278064Sume tm->tm_sec); 328355163Sshin return buf; 328455163Sshin} 328555163Sshin 328655163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 328755163Sshin 328855163Sshinint 328955163Sshinripinterval(timer) 329055163Sshin int timer; 329155163Sshin{ 329255163Sshin double r = rand(); 329355163Sshin 329455163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 329555163Sshin nextalarm = time(NULL) + interval; 329655163Sshin return interval; 329755163Sshin} 329855163Sshin 329955163Sshintime_t 330055163Sshinripsuptrig() 330155163Sshin{ 330255163Sshin time_t t; 330355163Sshin 330455163Sshin double r = rand(); 330562607Sitojun t = (int)(RIP_TRIG_INT6_MIN + 330678064Sume (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 330755163Sshin sup_trig_update = time(NULL) + t; 330855163Sshin return t; 330955163Sshin} 331055163Sshin 331155163Sshinvoid 331255163Sshin#ifdef __STDC__ 331355163Sshinfatal(const char *fmt, ...) 331455163Sshin#else 331555163Sshinfatal(fmt, va_alist) 331655163Sshin char *fmt; 331755163Sshin va_dcl 331855163Sshin#endif 331955163Sshin{ 332055163Sshin va_list ap; 332155163Sshin char buf[1024]; 332255163Sshin 332355163Sshin#ifdef __STDC__ 332455163Sshin va_start(ap, fmt); 332555163Sshin#else 332655163Sshin va_start(ap); 332755163Sshin#endif 332855163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 332955163Sshin perror(buf); 333055163Sshin syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 333178064Sume rtdexit(); 333255163Sshin va_end(ap); 333355163Sshin} 333455163Sshin 333555163Sshinvoid 333655163Sshin#ifdef __STDC__ 333755163Sshintracet(int level, const char *fmt, ...) 333855163Sshin#else 333955163Sshintracet(level, fmt, va_alist) 334055163Sshin int level; 334155163Sshin char *fmt; 334255163Sshin va_dcl 334355163Sshin#endif 334455163Sshin{ 334555163Sshin va_list ap; 334655163Sshin 334755163Sshin#ifdef __STDC__ 334855163Sshin va_start(ap, fmt); 334955163Sshin#else 335055163Sshin va_start(ap); 335155163Sshin#endif 335255163Sshin if (level <= dflag) { 335355163Sshin fprintf(stderr, "%s: ", hms()); 335455163Sshin vfprintf(stderr, fmt, ap); 335555163Sshin } 335655163Sshin if (dflag) { 335755163Sshin if (level > 0) 335855163Sshin vsyslog(LOG_DEBUG, fmt, ap); 335955163Sshin else 336055163Sshin vsyslog(LOG_WARNING, fmt, ap); 336155163Sshin } 336255163Sshin va_end(ap); 336355163Sshin} 336455163Sshin 336555163Sshinvoid 336655163Sshin#ifdef __STDC__ 336755163Sshintrace(int level, const char *fmt, ...) 336855163Sshin#else 336955163Sshintrace(level, fmt, va_alist) 337055163Sshin int level; 337155163Sshin char *fmt; 337255163Sshin va_dcl 337355163Sshin#endif 337455163Sshin{ 337555163Sshin va_list ap; 337655163Sshin 337755163Sshin#ifdef __STDC__ 337855163Sshin va_start(ap, fmt); 337955163Sshin#else 338055163Sshin va_start(ap); 338155163Sshin#endif 338255163Sshin if (level <= dflag) 338355163Sshin vfprintf(stderr, fmt, ap); 338455163Sshin if (dflag) { 338555163Sshin if (level > 0) 338655163Sshin vsyslog(LOG_DEBUG, fmt, ap); 338755163Sshin else 338855163Sshin vsyslog(LOG_WARNING, fmt, ap); 338955163Sshin } 339055163Sshin va_end(ap); 339155163Sshin} 339255163Sshin 339355163Sshinunsigned int 339455163Sshinif_maxindex() 339555163Sshin{ 339655163Sshin struct if_nameindex *p, *p0; 339755163Sshin unsigned int max = 0; 339855163Sshin 339955163Sshin p0 = if_nameindex(); 340055163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 340155163Sshin if (max < p->if_index) 340255163Sshin max = p->if_index; 340355163Sshin } 340455163Sshin if_freenameindex(p0); 340555163Sshin return max; 340655163Sshin} 340755163Sshin 340855163Sshinstruct ifc * 340955163Sshinifc_find(name) 341055163Sshin char *name; 341155163Sshin{ 341255163Sshin struct ifc *ifcp; 341355163Sshin 341455163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 341555163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 341655163Sshin return ifcp; 341755163Sshin } 341855163Sshin return (struct ifc *)NULL; 341955163Sshin} 342055163Sshin 342155163Sshinstruct iff * 342255163Sshiniff_find(ifcp, type) 342355163Sshin struct ifc *ifcp; 342455163Sshin int type; 342555163Sshin{ 342655163Sshin struct iff *iffp; 342755163Sshin 342855163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 342955163Sshin if (iffp->iff_type == type) 343055163Sshin return iffp; 343155163Sshin } 343255163Sshin return NULL; 343355163Sshin} 343455163Sshin 343555163Sshinvoid 343678064Sumesetindex2ifc(idx, ifcp) 343778064Sume int idx; 343855163Sshin struct ifc *ifcp; 343955163Sshin{ 344055163Sshin int n; 344162607Sitojun struct ifc **p; 344255163Sshin 344355163Sshin if (!index2ifc) { 344455163Sshin nindex2ifc = 5; /*initial guess*/ 344555163Sshin index2ifc = (struct ifc **) 344655163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 344778064Sume if (index2ifc == NULL) { 344855163Sshin fatal("malloc"); 344978064Sume /*NOTREACHED*/ 345078064Sume } 345155163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 345255163Sshin } 345355163Sshin n = nindex2ifc; 345478064Sume while (nindex2ifc <= idx) 345555163Sshin nindex2ifc *= 2; 345655163Sshin if (n != nindex2ifc) { 345762607Sitojun p = (struct ifc **)realloc(index2ifc, 345862607Sitojun sizeof(*index2ifc) * nindex2ifc); 345978064Sume if (p == NULL) { 346055163Sshin fatal("realloc"); 346178064Sume /*NOTREACHED*/ 346278064Sume } 346378064Sume memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 346462607Sitojun index2ifc = p; 346555163Sshin } 346678064Sume index2ifc[idx] = ifcp; 346755163Sshin} 3468