118316Swollman/* 218316Swollman * Copyright (c) 1983, 1993 318316Swollman * The Regents of the University of California. All rights reserved. 418316Swollman * 518316Swollman * Redistribution and use in source and binary forms, with or without 618316Swollman * modification, are permitted provided that the following conditions 718316Swollman * are met: 818316Swollman * 1. Redistributions of source code must retain the above copyright 918316Swollman * notice, this list of conditions and the following disclaimer. 1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright 1118316Swollman * notice, this list of conditions and the following disclaimer in the 1218316Swollman * documentation and/or other materials provided with the distribution. 1318316Swollman * 4. Neither the name of the University nor the names of its contributors 1418316Swollman * may be used to endorse or promote products derived from this software 1518316Swollman * without specific prior written permission. 1618316Swollman * 1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1818316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1918316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2018316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2118316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2218316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2318316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2418316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2518316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2618316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2718316Swollman * SUCH DAMAGE. 2846303Smarkm * 2950476Speter * $FreeBSD$ 3018316Swollman */ 3118316Swollman 32204405Suqs#include <stdint.h> 33204405Suqs 3418316Swollman#include "defs.h" 3518316Swollman#include "pathnames.h" 3618316Swollman 37126250Sbms#ifdef __NetBSD__ 3846303Smarkm__RCSID("$NetBSD$"); 39126250Sbms#elif defined(__FreeBSD__) 40126250Sbms__RCSID("$FreeBSD$"); 41126250Sbms#else 42126250Sbms__RCSID("$Revision: 2.27 $"); 43126250Sbms#ident "$Revision: 2.27 $" 4446303Smarkm#endif 45146838Sstefanf 46190711Sphkstruct ifhead ifnet = LIST_HEAD_INITIALIZER(ifnet); /* all interfaces */ 47201145Santoinestruct ifhead remote_if = LIST_HEAD_INITIALIZER(remote_if); /* remote interfaces */ 4819880Swollman 4919880Swollman/* hash table for all interfaces, big enough to tolerate ridiculous 5019880Swollman * numbers of IP aliases. Crazy numbers of aliases such as 7000 5119880Swollman * still will not do well, but not just in looking up interfaces 5219880Swollman * by name or address. 5319880Swollman */ 5419880Swollman#define AHASH_LEN 211 /* must be prime */ 5521378Swollman#define AHASH(a) &ahash_tbl[(a)%AHASH_LEN] 56190715Sphkstatic struct interface *ahash_tbl[AHASH_LEN]; 5719880Swollman 5819880Swollman#define BHASH_LEN 211 /* must be prime */ 5921378Swollman#define BHASH(a) &bhash_tbl[(a)%BHASH_LEN] 60190715Sphkstatic struct interface *bhash_tbl[BHASH_LEN]; 6119880Swollman 6219880Swollman 6319880Swollman/* hash for physical interface names. 6419880Swollman * Assume there are never more 100 or 200 real interfaces, and that 6520606Swollman * aliases are put on the end of the hash chains. 6619880Swollman */ 6719880Swollman#define NHASH_LEN 97 68190715Sphkstatic struct interface *nhash_tbl[NHASH_LEN]; 6919880Swollman 7018316Swollmanint tot_interfaces; /* # of remote and local interfaces */ 7118316Swollmanint rip_interfaces; /* # of interfaces doing RIP */ 72190715Sphkstatic int foundloopback; /* valid flag for loopaddr */ 7318316Swollmannaddr loopaddr; /* our address on loopback */ 74190715Sphkstatic struct rt_spare loop_rts; 7518316Swollman 7618316Swollmanstruct timeval ifinit_timer; 7720606Swollmanstatic struct timeval last_ifinit; 7846303Smarkm#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec \ 7946303Smarkm && last_ifinit.tv_usec == now.tv_usec \ 8046303Smarkm && timercmp(&ifinit_timer, &now, >)) 8118316Swollman 8218316Swollmanint have_ripv1_out; /* have a RIPv1 interface */ 83190715Sphkstatic int have_ripv1_in; 8418316Swollman 8518316Swollman 86190715Sphkstatic void if_bad(struct interface *); 87190715Sphkstatic int addrouteforif(struct interface *); 88190715Sphk 8921378Swollmanstatic struct interface** 9046303Smarkmnhash(char *p) 9121378Swollman{ 9246303Smarkm u_int i; 9321378Swollman 9421378Swollman for (i = 0; *p != '\0'; p++) { 9521378Swollman i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1); 9621378Swollman i ^= *p; 9721378Swollman } 9821378Swollman return &nhash_tbl[i % NHASH_LEN]; 9921378Swollman} 10021378Swollman 10121378Swollman 10220606Swollman/* Link a new interface into the lists and hash tables. 10320606Swollman */ 10419880Swollmanvoid 10519880Swollmanif_link(struct interface *ifp) 10619880Swollman{ 10719880Swollman struct interface **hifp; 10819880Swollman 109190711Sphk LIST_INSERT_HEAD(&ifnet, ifp, int_list); 11019880Swollman 11119880Swollman hifp = AHASH(ifp->int_addr); 11219880Swollman ifp->int_ahash_prev = hifp; 11319880Swollman if ((ifp->int_ahash = *hifp) != 0) 11419880Swollman (*hifp)->int_ahash_prev = &ifp->int_ahash; 11519880Swollman *hifp = ifp; 11619880Swollman 11719880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 11819880Swollman hifp = BHASH(ifp->int_brdaddr); 11919880Swollman ifp->int_bhash_prev = hifp; 12019880Swollman if ((ifp->int_bhash = *hifp) != 0) 12119880Swollman (*hifp)->int_bhash_prev = &ifp->int_bhash; 12219880Swollman *hifp = ifp; 12319880Swollman } 12419880Swollman 125190713Sphk if (ifp->int_state & IS_REMOTE) 126190713Sphk LIST_INSERT_HEAD(&remote_if, ifp, remote_list); 12719880Swollman 12821378Swollman hifp = nhash(ifp->int_name); 12919880Swollman if (ifp->int_state & IS_ALIAS) { 13020606Swollman /* put aliases on the end of the hash chain */ 13119880Swollman while (*hifp != 0) 13219880Swollman hifp = &(*hifp)->int_nhash; 13319880Swollman } 13419880Swollman ifp->int_nhash_prev = hifp; 13519880Swollman if ((ifp->int_nhash = *hifp) != 0) 13619880Swollman (*hifp)->int_nhash_prev = &ifp->int_nhash; 13719880Swollman *hifp = ifp; 13819880Swollman} 13919880Swollman 14019880Swollman 14118316Swollman/* Find the interface with an address 14218316Swollman */ 14318316Swollmanstruct interface * 14418316Swollmanifwithaddr(naddr addr, 14518316Swollman int bcast, /* notice IFF_BROADCAST address */ 14618316Swollman int remote) /* include IS_REMOTE interfaces */ 14718316Swollman{ 14818316Swollman struct interface *ifp, *possible = 0; 14918316Swollman 15019880Swollman remote = (remote == 0) ? IS_REMOTE : 0; 15118316Swollman 15219880Swollman for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) { 15319880Swollman if (ifp->int_addr != addr) 15419880Swollman continue; 15519880Swollman if ((ifp->int_state & remote) != 0) 15619880Swollman continue; 15719880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 15819880Swollman return ifp; 15919880Swollman possible = ifp; 16019880Swollman } 16118316Swollman 16219880Swollman if (possible || !bcast) 16319880Swollman return possible; 16419880Swollman 16519880Swollman for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) { 16619880Swollman if (ifp->int_brdaddr != addr) 16719880Swollman continue; 16819880Swollman if ((ifp->int_state & remote) != 0) 16919880Swollman continue; 17019880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 17119880Swollman return ifp; 17219880Swollman possible = ifp; 17318316Swollman } 17418316Swollman 17518316Swollman return possible; 17618316Swollman} 17718316Swollman 17818316Swollman 17918316Swollman/* find the interface with a name 18018316Swollman */ 181190715Sphkstatic struct interface * 18218316Swollmanifwithname(char *name, /* "ec0" or whatever */ 18318316Swollman naddr addr) /* 0 or network address */ 18418316Swollman{ 18518316Swollman struct interface *ifp; 18618316Swollman 18720606Swollman for (;;) { 18821378Swollman for (ifp = *nhash(name); ifp != 0; ifp = ifp->int_nhash) { 18920606Swollman /* If the network address is not specified, 19020606Swollman * ignore any alias interfaces. Otherwise, look 19120606Swollman * for the interface with the target name and address. 19220606Swollman */ 19320606Swollman if (!strcmp(ifp->int_name, name) 19420606Swollman && ((addr == 0 && !(ifp->int_state & IS_ALIAS)) 19520606Swollman || (ifp->int_addr == addr))) 19620606Swollman return ifp; 19720606Swollman } 19820606Swollman 19920606Swollman /* If there is no known interface, maybe there is a 20020606Swollman * new interface. So just once look for new interfaces. 20119880Swollman */ 20246303Smarkm if (IF_RESCAN_DELAY()) 20320606Swollman return 0; 20420606Swollman ifinit(); 20518316Swollman } 20618316Swollman} 20718316Swollman 20818316Swollman 20918316Swollmanstruct interface * 210126250Sbmsifwithindex(u_short ifindex, 21146303Smarkm int rescan_ok) 21218316Swollman{ 21318316Swollman struct interface *ifp; 21418316Swollman 21546303Smarkm for (;;) { 216190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 217126250Sbms if (ifp->int_index == ifindex) 21846303Smarkm return ifp; 21946303Smarkm } 22018316Swollman 22146303Smarkm /* If there is no known interface, maybe there is a 22246303Smarkm * new interface. So just once look for new interfaces. 22346303Smarkm */ 22446303Smarkm if (!rescan_ok 22546303Smarkm || IF_RESCAN_DELAY()) 22646303Smarkm return 0; 22746303Smarkm ifinit(); 22818316Swollman } 22918316Swollman} 23018316Swollman 23118316Swollman 23218316Swollman/* Find an interface from which the specified address 23318316Swollman * should have come from. Used for figuring out which 23420339Swollman * interface a packet came in on. 23518316Swollman */ 23618316Swollmanstruct interface * 23718316Swollmaniflookup(naddr addr) 23818316Swollman{ 23918316Swollman struct interface *ifp, *maybe; 240126250Sbms int once = 0; 24118316Swollman 24218316Swollman maybe = 0; 24320339Swollman for (;;) { 244190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 24520339Swollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 24620339Swollman /* finished with a match */ 24720339Swollman if (ifp->int_dstaddr == addr) 24820339Swollman return ifp; 24918316Swollman 25020339Swollman } else { 25120339Swollman /* finished with an exact match */ 25220339Swollman if (ifp->int_addr == addr) 25320339Swollman return ifp; 25418316Swollman 25520339Swollman /* Look for the longest approximate match. 25620339Swollman */ 25720339Swollman if (on_net(addr, ifp->int_net, ifp->int_mask) 25820339Swollman && (maybe == 0 25920339Swollman || ifp->int_mask > maybe->int_mask)) 26020339Swollman maybe = ifp; 26120339Swollman } 26218316Swollman } 26320339Swollman 264126250Sbms if (maybe != 0 || once || IF_RESCAN_DELAY()) 26520339Swollman return maybe; 266126250Sbms once = 1; 26720339Swollman 26820339Swollman /* If there is no known interface, maybe there is a 26920339Swollman * new interface. So just once look for new interfaces. 27020339Swollman */ 27120339Swollman ifinit(); 27218316Swollman } 27318316Swollman} 27418316Swollman 27518316Swollman 27618316Swollman/* Return the classical netmask for an IP address. 27718316Swollman */ 27820339Swollmannaddr /* host byte order */ 27920339Swollmanstd_mask(naddr addr) /* network byte order */ 28018316Swollman{ 28190868Smike addr = ntohl(addr); /* was a host, not a network */ 28218316Swollman 28318316Swollman if (addr == 0) /* default route has mask 0 */ 28418316Swollman return 0; 28518316Swollman if (IN_CLASSA(addr)) 28618316Swollman return IN_CLASSA_NET; 28718316Swollman if (IN_CLASSB(addr)) 28818316Swollman return IN_CLASSB_NET; 28918316Swollman return IN_CLASSC_NET; 29018316Swollman} 29118316Swollman 29218316Swollman 29318316Swollman/* Find the netmask that would be inferred by RIPv1 listeners 29418316Swollman * on the given interface for a given network. 29518316Swollman * If no interface is specified, look for the best fitting interface. 29618316Swollman */ 29718316Swollmannaddr 29818316Swollmanripv1_mask_net(naddr addr, /* in network byte order */ 29918316Swollman struct interface *ifp) /* as seen on this interface */ 30018316Swollman{ 30146303Smarkm struct r1net *r1p; 30218316Swollman naddr mask = 0; 30318316Swollman 30418316Swollman if (addr == 0) /* default always has 0 mask */ 30518316Swollman return mask; 30618316Swollman 30746303Smarkm if (ifp != 0 && ifp->int_ripv1_mask != HOST_MASK) { 30818316Swollman /* If the target network is that of the associated interface 30918316Swollman * on which it arrived, then use the netmask of the interface. 31018316Swollman */ 31118316Swollman if (on_net(addr, ifp->int_net, ifp->int_std_mask)) 31218316Swollman mask = ifp->int_ripv1_mask; 31318316Swollman 31418316Swollman } else { 31518316Swollman /* Examine all interfaces, and if it the target seems 31618316Swollman * to have the same network number of an interface, use the 31718316Swollman * netmask of that interface. If there is more than one 31818316Swollman * such interface, prefer the interface with the longest 31918316Swollman * match. 32018316Swollman */ 321190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 32218316Swollman if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) 32346303Smarkm && ifp->int_ripv1_mask > mask 32446303Smarkm && ifp->int_ripv1_mask != HOST_MASK) 32518316Swollman mask = ifp->int_ripv1_mask; 32618316Swollman } 32746303Smarkm 32818316Swollman } 32918316Swollman 33046303Smarkm /* check special definitions */ 33146303Smarkm if (mask == 0) { 33246303Smarkm for (r1p = r1nets; r1p != 0; r1p = r1p->r1net_next) { 33346303Smarkm if (on_net(addr, r1p->r1net_net, r1p->r1net_match) 33446303Smarkm && r1p->r1net_mask > mask) 33546303Smarkm mask = r1p->r1net_mask; 33646303Smarkm } 33718316Swollman 33846303Smarkm /* Otherwise, make the classic A/B/C guess. 33946303Smarkm */ 34046303Smarkm if (mask == 0) 34146303Smarkm mask = std_mask(addr); 34246303Smarkm } 34346303Smarkm 34418316Swollman return mask; 34518316Swollman} 34618316Swollman 34718316Swollman 34818316Swollmannaddr 34918316Swollmanripv1_mask_host(naddr addr, /* in network byte order */ 35018316Swollman struct interface *ifp) /* as seen on this interface */ 35118316Swollman{ 35218316Swollman naddr mask = ripv1_mask_net(addr, ifp); 35318316Swollman 35418316Swollman 35518316Swollman /* If the computed netmask does not mask the address, 35618316Swollman * then assume it is a host address 35718316Swollman */ 35818316Swollman if ((ntohl(addr) & ~mask) != 0) 35918316Swollman mask = HOST_MASK; 36018316Swollman return mask; 36118316Swollman} 36218316Swollman 36318316Swollman 364108533Sschweikh/* See if an IP address looks reasonable as a destination. 36518316Swollman */ 36618316Swollmanint /* 0=bad */ 36718316Swollmancheck_dst(naddr addr) 36818316Swollman{ 36990868Smike addr = ntohl(addr); 37018316Swollman 37118316Swollman if (IN_CLASSA(addr)) { 37218316Swollman if (addr == 0) 37318316Swollman return 1; /* default */ 37418316Swollman 37518316Swollman addr >>= IN_CLASSA_NSHIFT; 37618316Swollman return (addr != 0 && addr != IN_LOOPBACKNET); 37718316Swollman } 37818316Swollman 37918316Swollman return (IN_CLASSB(addr) || IN_CLASSC(addr)); 38018316Swollman} 38118316Swollman 38218316Swollman 38319880Swollman/* See a new interface duplicates an existing interface. 38419880Swollman */ 38519880Swollmanstruct interface * 38620339Swollmancheck_dup(naddr addr, /* IP address, so network byte order */ 38720339Swollman naddr dstaddr, /* ditto */ 38820339Swollman naddr mask, /* mask, so host byte order */ 38919880Swollman int if_flags) 39019880Swollman{ 39119880Swollman struct interface *ifp; 39219880Swollman 393190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 39419880Swollman if (ifp->int_mask != mask) 39519880Swollman continue; 39619880Swollman 39746303Smarkm if (!iff_up(ifp->int_if_flags)) 39819880Swollman continue; 39919880Swollman 40046303Smarkm /* The local address can only be shared with a point-to-point 40146303Smarkm * link. 40219880Swollman */ 403126250Sbms if ((!(ifp->int_state & IS_REMOTE) || !(if_flags & IS_REMOTE)) 404126250Sbms && ifp->int_addr == addr 40519880Swollman && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) 40619880Swollman return ifp; 40719880Swollman 40819880Swollman if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask)) 40919880Swollman return ifp; 41019880Swollman } 41119880Swollman return 0; 41219880Swollman} 41319880Swollman 41419880Swollman 41519880Swollman/* See that a remote gateway is reachable. 41619880Swollman * Note that the answer can change as real interfaces come and go. 41719880Swollman */ 41819880Swollmanint /* 0=bad */ 41919880Swollmancheck_remote(struct interface *ifp) 42019880Swollman{ 42119880Swollman struct rt_entry *rt; 42219880Swollman 42319880Swollman /* do not worry about other kinds */ 42419880Swollman if (!(ifp->int_state & IS_REMOTE)) 42519880Swollman return 1; 42619880Swollman 42719880Swollman rt = rtfind(ifp->int_addr); 42819880Swollman if (rt != 0 42919880Swollman && rt->rt_ifp != 0 43019880Swollman &&on_net(ifp->int_addr, 43119880Swollman rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) 43219880Swollman return 1; 43319880Swollman 43419880Swollman /* the gateway cannot be reached directly from one of our 43519880Swollman * interfaces 43619880Swollman */ 43719880Swollman if (!(ifp->int_state & IS_BROKE)) { 43819880Swollman msglog("unreachable gateway %s in "_PATH_GATEWAYS, 43919880Swollman naddr_ntoa(ifp->int_addr)); 44019880Swollman if_bad(ifp); 44119880Swollman } 44219880Swollman return 0; 44319880Swollman} 44419880Swollman 44519880Swollman 44618316Swollman/* Delete an interface. 44718316Swollman */ 44818316Swollmanstatic void 44918316Swollmanifdel(struct interface *ifp) 45018316Swollman{ 45118316Swollman struct interface *ifp1; 45218316Swollman 45318316Swollman 45418316Swollman trace_if("Del", ifp); 45518316Swollman 45618316Swollman ifp->int_state |= IS_BROKE; 45718316Swollman 458190711Sphk LIST_REMOVE(ifp, int_list); 45919880Swollman *ifp->int_ahash_prev = ifp->int_ahash; 46019880Swollman if (ifp->int_ahash != 0) 46119880Swollman ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev; 46221378Swollman *ifp->int_nhash_prev = ifp->int_nhash; 46321378Swollman if (ifp->int_nhash != 0) 46421378Swollman ifp->int_nhash->int_nhash_prev = ifp->int_nhash_prev; 46519880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 46619880Swollman *ifp->int_bhash_prev = ifp->int_bhash; 46719880Swollman if (ifp->int_bhash != 0) 46819880Swollman ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev; 46919880Swollman } 470190713Sphk if (ifp->int_state & IS_REMOTE) 471190713Sphk LIST_REMOVE(ifp, remote_list); 47218316Swollman 47318316Swollman if (!(ifp->int_state & IS_ALIAS)) { 47419880Swollman /* delete aliases when the main interface dies 47518316Swollman */ 476190711Sphk LIST_FOREACH(ifp1, &ifnet, int_list) { 47718316Swollman if (ifp1 != ifp 47818316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 47918316Swollman ifdel(ifp1); 48018316Swollman } 48118316Swollman 482180993Sphk if ((ifp->int_if_flags & IFF_MULTICAST) && rip_sock >= 0) { 483180993Sphk struct group_req gr; 484180993Sphk struct sockaddr_in *sin; 485180993Sphk 486180993Sphk memset(&gr, 0, sizeof(gr)); 487180993Sphk gr.gr_interface = ifp->int_index; 488180993Sphk sin = (struct sockaddr_in *)&gr.gr_group; 489180993Sphk sin->sin_family = AF_INET; 490180993Sphk#ifdef _HAVE_SIN_LEN 491180993Sphk sin->sin_len = sizeof(struct sockaddr_in); 49218316Swollman#endif 493180993Sphk sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); 494180993Sphk if (setsockopt(rip_sock, IPPROTO_IP, MCAST_LEAVE_GROUP, 495180993Sphk &gr, sizeof(gr)) < 0 49618316Swollman && errno != EADDRNOTAVAIL 49718316Swollman && !TRACEACTIONS) 498180993Sphk LOGERR("setsockopt(MCAST_LEAVE_GROUP RIP)"); 49919880Swollman if (rip_sock_mcast == ifp) 50019880Swollman rip_sock_mcast = 0; 50118316Swollman } 50218316Swollman if (ifp->int_rip_sock >= 0) { 50318316Swollman (void)close(ifp->int_rip_sock); 50418316Swollman ifp->int_rip_sock = -1; 50518316Swollman fix_select(); 50618316Swollman } 50718316Swollman 50818316Swollman tot_interfaces--; 50918316Swollman if (!IS_RIP_OFF(ifp->int_state)) 51018316Swollman rip_interfaces--; 51118316Swollman 51218316Swollman /* Zap all routes associated with this interface. 51346303Smarkm * Assume routes just using gateways beyond this interface 51446303Smarkm * will timeout naturally, and have probably already died. 51518316Swollman */ 51618316Swollman (void)rn_walktree(rhead, walk_bad, 0); 51718316Swollman 51818316Swollman set_rdisc_mg(ifp, 0); 51918316Swollman if_bad_rdisc(ifp); 52018316Swollman } 52118316Swollman 52218316Swollman free(ifp); 52318316Swollman} 52418316Swollman 52518316Swollman 52618316Swollman/* Mark an interface ill. 52718316Swollman */ 52818316Swollmanvoid 52918316Swollmanif_sick(struct interface *ifp) 53018316Swollman{ 53118316Swollman if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) { 53218316Swollman ifp->int_state |= IS_SICK; 53319880Swollman ifp->int_act_time = NEVER; 53418316Swollman trace_if("Chg", ifp); 53518316Swollman 53618316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 53718316Swollman } 53818316Swollman} 53918316Swollman 54018316Swollman 54118316Swollman/* Mark an interface dead. 54218316Swollman */ 543190715Sphkstatic void 54418316Swollmanif_bad(struct interface *ifp) 54518316Swollman{ 54618316Swollman struct interface *ifp1; 54718316Swollman 54818316Swollman 54918316Swollman if (ifp->int_state & IS_BROKE) 55018316Swollman return; 55118316Swollman 55218316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 55318316Swollman 55418316Swollman ifp->int_state |= (IS_BROKE | IS_SICK); 55519880Swollman ifp->int_act_time = NEVER; 55619880Swollman ifp->int_query_time = NEVER; 55746303Smarkm ifp->int_data.ts = now.tv_sec; 55818316Swollman 55918316Swollman trace_if("Chg", ifp); 56018316Swollman 56118316Swollman if (!(ifp->int_state & IS_ALIAS)) { 562190711Sphk LIST_FOREACH(ifp1, &ifnet, int_list) { 56318316Swollman if (ifp1 != ifp 56418316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 56518316Swollman if_bad(ifp1); 56618316Swollman } 56718316Swollman (void)rn_walktree(rhead, walk_bad, 0); 56818316Swollman if_bad_rdisc(ifp); 56918316Swollman } 57018316Swollman} 57118316Swollman 57218316Swollman 57318316Swollman/* Mark an interface alive 57418316Swollman */ 57518316Swollmanint /* 1=it was dead */ 57618316Swollmanif_ok(struct interface *ifp, 57746303Smarkm const char *type) 57818316Swollman{ 57918316Swollman struct interface *ifp1; 58018316Swollman 58118316Swollman 58218316Swollman if (!(ifp->int_state & IS_BROKE)) { 58318316Swollman if (ifp->int_state & IS_SICK) { 58419880Swollman trace_act("%sinterface %s to %s working better", 58518316Swollman type, 58619880Swollman ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 58718316Swollman ifp->int_state &= ~IS_SICK; 58818316Swollman } 58918316Swollman return 0; 59018316Swollman } 59118316Swollman 59218316Swollman msglog("%sinterface %s to %s restored", 59319880Swollman type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 59418316Swollman ifp->int_state &= ~(IS_BROKE | IS_SICK); 59518316Swollman ifp->int_data.ts = 0; 59618316Swollman 59718316Swollman if (!(ifp->int_state & IS_ALIAS)) { 598190711Sphk LIST_FOREACH(ifp1, &ifnet, int_list) { 59918316Swollman if (ifp1 != ifp 60018316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 60118316Swollman if_ok(ifp1, type); 60218316Swollman } 60318316Swollman if_ok_rdisc(ifp); 60418316Swollman } 60519880Swollman 60619880Swollman if (ifp->int_state & IS_REMOTE) { 60719880Swollman if (!addrouteforif(ifp)) 60819880Swollman return 0; 60919880Swollman } 61018316Swollman return 1; 61118316Swollman} 61218316Swollman 61318316Swollman 61446303Smarkm/* disassemble routing message 61518316Swollman */ 61618316Swollmanvoid 61718316Swollmanrt_xaddrs(struct rt_addrinfo *info, 61818316Swollman struct sockaddr *sa, 61918316Swollman struct sockaddr *lim, 62018316Swollman int addrs) 62118316Swollman{ 62218316Swollman int i; 62346303Smarkm#ifdef _HAVE_SA_LEN 62446303Smarkm static struct sockaddr sa_zero; 62546303Smarkm#endif 62618316Swollman 62746303Smarkm memset(info, 0, sizeof(*info)); 62818316Swollman info->rti_addrs = addrs; 62918316Swollman for (i = 0; i < RTAX_MAX && sa < lim; i++) { 63018316Swollman if ((addrs & (1 << i)) == 0) 63118316Swollman continue; 63246303Smarkm info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; 633128186Sluigi sa = (struct sockaddr *)((char*)(sa) + SA_SIZE(sa)); 63418316Swollman } 63518316Swollman} 63618316Swollman 63718316Swollman 63818316Swollman/* Find the network interfaces which have configured themselves. 63918316Swollman * This must be done regularly, if only for extra addresses 64018316Swollman * that come and go on interfaces. 64118316Swollman */ 64218316Swollmanvoid 64318316Swollmanifinit(void) 64418316Swollman{ 645190717Sphk static struct ifa_msghdr *sysctl_buf; 64618316Swollman static size_t sysctl_buf_size = 0; 64718316Swollman uint complaints = 0; 64818316Swollman static u_int prev_complaints = 0; 64918316Swollman# define COMP_NOT_INET 0x001 65019880Swollman# define COMP_NOADDR 0x002 65119880Swollman# define COMP_BADADDR 0x004 65219880Swollman# define COMP_NODST 0x008 65319880Swollman# define COMP_NOBADR 0x010 65419880Swollman# define COMP_NOMASK 0x020 65519880Swollman# define COMP_DUP 0x040 65619880Swollman# define COMP_BAD_METRIC 0x080 65719880Swollman# define COMP_NETMASK 0x100 65818316Swollman 65918316Swollman struct interface ifs, ifs0, *ifp, *ifp1; 66018316Swollman struct rt_entry *rt; 66118316Swollman size_t needed; 66218316Swollman int mib[6]; 66318316Swollman struct if_msghdr *ifm; 664190717Sphk void *ifam_lim; 665190717Sphk struct ifa_msghdr *ifam, *ifam2; 66618316Swollman int in, ierr, out, oerr; 66718316Swollman struct intnet *intnetp; 66818316Swollman struct rt_addrinfo info; 66918316Swollman#ifdef SIOCGIFMETRIC 67018316Swollman struct ifreq ifr; 67118316Swollman#endif 67218316Swollman 67318316Swollman 67420606Swollman last_ifinit = now; 67518316Swollman ifinit_timer.tv_sec = now.tv_sec + (supplier 67618316Swollman ? CHECK_ACT_INTERVAL 67718316Swollman : CHECK_QUIET_INTERVAL); 67818316Swollman 67937908Scharnier /* mark all interfaces so we can get rid of those that disappear */ 680190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) 68118316Swollman ifp->int_state &= ~(IS_CHECKED | IS_DUP); 68218316Swollman 68318316Swollman /* Fetch the interface list, without too many system calls 68418316Swollman * since we do it repeatedly. 68518316Swollman */ 68618316Swollman mib[0] = CTL_NET; 68718316Swollman mib[1] = PF_ROUTE; 68818316Swollman mib[2] = 0; 68918316Swollman mib[3] = AF_INET; 69018316Swollman mib[4] = NET_RT_IFLIST; 69118316Swollman mib[5] = 0; 69218316Swollman for (;;) { 69318316Swollman if ((needed = sysctl_buf_size) != 0) { 69418316Swollman if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 69518316Swollman break; 69646303Smarkm /* retry if the table grew */ 69718316Swollman if (errno != ENOMEM && errno != EFAULT) 69846303Smarkm BADERR(1, "ifinit: sysctl(RT_IFLIST)"); 69918316Swollman free(sysctl_buf); 70018316Swollman needed = 0; 70118316Swollman } 70218316Swollman if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 70346303Smarkm BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate"); 70446303Smarkm sysctl_buf = rtmalloc(sysctl_buf_size = needed, 70546303Smarkm "ifinit sysctl"); 70618316Swollman } 70718316Swollman 708190717Sphk /* XXX: thanks to malloc(3), alignment can be presumed OK */ 709190717Sphk ifam_lim = (char *)sysctl_buf + needed; 710190717Sphk for (ifam = sysctl_buf; (void *)ifam < ifam_lim; ifam = ifam2) { 71118316Swollman 71218316Swollman ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); 71318316Swollman 714126250Sbms#ifdef RTM_OIFINFO 715126250Sbms if (ifam->ifam_type == RTM_OIFINFO) 716126250Sbms continue; /* just ignore compat message */ 717126250Sbms#endif 71818316Swollman if (ifam->ifam_type == RTM_IFINFO) { 71919880Swollman struct sockaddr_dl *sdl; 72019880Swollman 72118316Swollman ifm = (struct if_msghdr *)ifam; 72218316Swollman /* make prototype structure for the IP aliases 72318316Swollman */ 72446303Smarkm memset(&ifs0, 0, sizeof(ifs0)); 72518316Swollman ifs0.int_rip_sock = -1; 72618316Swollman ifs0.int_index = ifm->ifm_index; 72718316Swollman ifs0.int_if_flags = ifm->ifm_flags; 72818316Swollman ifs0.int_state = IS_CHECKED; 72920339Swollman ifs0.int_query_time = NEVER; 73018316Swollman ifs0.int_act_time = now.tv_sec; 73118316Swollman ifs0.int_data.ts = now.tv_sec; 73218316Swollman ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; 73318316Swollman ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors; 73418316Swollman ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets; 73518316Swollman ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors; 73618316Swollman#ifdef sgi 73718316Swollman ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops; 73818316Swollman#endif 73918316Swollman sdl = (struct sockaddr_dl *)(ifm + 1); 74018316Swollman sdl->sdl_data[sdl->sdl_nlen] = 0; 74119880Swollman strncpy(ifs0.int_name, sdl->sdl_data, 74219880Swollman MIN(sizeof(ifs0.int_name), sdl->sdl_nlen)); 74318316Swollman continue; 74418316Swollman } 74518316Swollman if (ifam->ifam_type != RTM_NEWADDR) { 74618316Swollman logbad(1,"ifinit: out of sync"); 74718316Swollman continue; 74818316Swollman } 74918316Swollman rt_xaddrs(&info, (struct sockaddr *)(ifam+1), 75018316Swollman (struct sockaddr *)ifam2, 75118316Swollman ifam->ifam_addrs); 75218316Swollman 75319880Swollman /* Prepare for the next address of this interface, which 75419880Swollman * will be an alias. 75519880Swollman * Do not output RIP or Router-Discovery packets via aliases. 75619880Swollman */ 75746303Smarkm memcpy(&ifs, &ifs0, sizeof(ifs)); 75846303Smarkm ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC); 75919880Swollman 76018316Swollman if (INFO_IFA(&info) == 0) { 76146303Smarkm if (iff_up(ifs.int_if_flags)) { 76218316Swollman if (!(prev_complaints & COMP_NOADDR)) 76318316Swollman msglog("%s has no address", 76419880Swollman ifs.int_name); 76518316Swollman complaints |= COMP_NOADDR; 76618316Swollman } 76718316Swollman continue; 76818316Swollman } 76918316Swollman if (INFO_IFA(&info)->sa_family != AF_INET) { 77046303Smarkm if (iff_up(ifs.int_if_flags)) { 77118316Swollman if (!(prev_complaints & COMP_NOT_INET)) 77219880Swollman trace_act("%s: not AF_INET", 77319880Swollman ifs.int_name); 77418316Swollman complaints |= COMP_NOT_INET; 77518316Swollman } 77618316Swollman continue; 77718316Swollman } 77818316Swollman 77918316Swollman ifs.int_addr = S_ADDR(INFO_IFA(&info)); 78018316Swollman 78118316Swollman if (ntohl(ifs.int_addr)>>24 == 0 78218316Swollman || ntohl(ifs.int_addr)>>24 == 0xff) { 78346303Smarkm if (iff_up(ifs.int_if_flags)) { 78418316Swollman if (!(prev_complaints & COMP_BADADDR)) 78518316Swollman msglog("%s has a bad address", 78619880Swollman ifs.int_name); 78718316Swollman complaints |= COMP_BADADDR; 78818316Swollman } 78918316Swollman continue; 79018316Swollman } 79118316Swollman 79219880Swollman if (ifs.int_if_flags & IFF_LOOPBACK) { 793133715Sphk ifs.int_state |= IS_NO_RIP | IS_NO_RDISC; 794153558Smaxim if (ifs.int_addr == htonl(INADDR_LOOPBACK)) 795133715Sphk ifs.int_state |= IS_PASSIVE; 79618316Swollman ifs.int_dstaddr = ifs.int_addr; 79719880Swollman ifs.int_mask = HOST_MASK; 79819880Swollman ifs.int_ripv1_mask = HOST_MASK; 79919880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 80019880Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 80119880Swollman if (!foundloopback) { 80219880Swollman foundloopback = 1; 80319880Swollman loopaddr = ifs.int_addr; 80446303Smarkm loop_rts.rts_gate = loopaddr; 80546303Smarkm loop_rts.rts_router = loopaddr; 80618316Swollman } 80718316Swollman 80818316Swollman } else if (ifs.int_if_flags & IFF_POINTOPOINT) { 80918316Swollman if (INFO_BRD(&info) == 0 81018316Swollman || INFO_BRD(&info)->sa_family != AF_INET) { 81146303Smarkm if (iff_up(ifs.int_if_flags)) { 81218316Swollman if (!(prev_complaints & COMP_NODST)) 81318316Swollman msglog("%s has a bad" 81418316Swollman " destination address", 81519880Swollman ifs.int_name); 81618316Swollman complaints |= COMP_NODST; 81718316Swollman } 81818316Swollman continue; 81918316Swollman } 82018316Swollman ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); 82118316Swollman if (ntohl(ifs.int_dstaddr)>>24 == 0 82218316Swollman || ntohl(ifs.int_dstaddr)>>24 == 0xff) { 82346303Smarkm if (iff_up(ifs.int_if_flags)) { 82418316Swollman if (!(prev_complaints & COMP_NODST)) 82518316Swollman msglog("%s has a bad" 82618316Swollman " destination address", 82719880Swollman ifs.int_name); 82818316Swollman complaints |= COMP_NODST; 82918316Swollman } 83018316Swollman continue; 83118316Swollman } 83218316Swollman ifs.int_mask = HOST_MASK; 83318316Swollman ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); 83419880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 83518316Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 83618316Swollman 83719880Swollman } else { 83819880Swollman if (INFO_MASK(&info) == 0) { 83946303Smarkm if (iff_up(ifs.int_if_flags)) { 84019880Swollman if (!(prev_complaints & COMP_NOMASK)) 84119880Swollman msglog("%s has no netmask", 84219880Swollman ifs.int_name); 84319880Swollman complaints |= COMP_NOMASK; 84419880Swollman } 84519880Swollman continue; 84619880Swollman } 84718316Swollman ifs.int_dstaddr = ifs.int_addr; 84819880Swollman ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); 84919880Swollman ifs.int_ripv1_mask = ifs.int_mask; 85019880Swollman ifs.int_std_mask = std_mask(ifs.int_addr); 85119880Swollman ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; 85219880Swollman if (ifs.int_mask != ifs.int_std_mask) 85319880Swollman ifs.int_state |= IS_SUBNET; 85419880Swollman 85519880Swollman if (ifs.int_if_flags & IFF_BROADCAST) { 85619880Swollman if (INFO_BRD(&info) == 0) { 85746303Smarkm if (iff_up(ifs.int_if_flags)) { 85819880Swollman if (!(prev_complaints 85919880Swollman & COMP_NOBADR)) 86019880Swollman msglog("%s has" 86119880Swollman "no broadcast address", 86219880Swollman ifs.int_name); 86319880Swollman complaints |= COMP_NOBADR; 86419880Swollman } 86519880Swollman continue; 86619880Swollman } 86719880Swollman ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); 86818316Swollman } 86918316Swollman } 87018316Swollman ifs.int_std_net = ifs.int_net & ifs.int_std_mask; 87118316Swollman ifs.int_std_addr = htonl(ifs.int_std_net); 87218316Swollman 87318316Swollman /* Use a minimum metric of one. Treat the interface metric 87418316Swollman * (default 0) as an increment to the hop count of one. 87518316Swollman * 87618316Swollman * The metric obtained from the routing socket dump of 87718316Swollman * interface addresses is wrong. It is not set by the 87818316Swollman * SIOCSIFMETRIC ioctl. 87918316Swollman */ 88018316Swollman#ifdef SIOCGIFMETRIC 88119880Swollman strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name)); 88218316Swollman if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) { 88318316Swollman DBGERR(1, "ioctl(SIOCGIFMETRIC)"); 88418316Swollman ifs.int_metric = 0; 88518316Swollman } else { 88618316Swollman ifs.int_metric = ifr.ifr_metric; 88718316Swollman } 88818316Swollman#else 88918316Swollman ifs.int_metric = ifam->ifam_metric; 89018316Swollman#endif 89118316Swollman if (ifs.int_metric > HOPCNT_INFINITY) { 89218316Swollman ifs.int_metric = 0; 89318316Swollman if (!(prev_complaints & COMP_BAD_METRIC) 89446303Smarkm && iff_up(ifs.int_if_flags)) { 89518316Swollman complaints |= COMP_BAD_METRIC; 89618316Swollman msglog("%s has a metric of %d", 89719880Swollman ifs.int_name, ifs.int_metric); 89818316Swollman } 89918316Swollman } 90018316Swollman 90118316Swollman /* See if this is a familiar interface. 90218316Swollman * If so, stop worrying about it if it is the same. 90318316Swollman * Start it over if it now is to somewhere else, as happens 90418316Swollman * frequently with PPP and SLIP. 90518316Swollman */ 90619880Swollman ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS) 90719880Swollman ? ifs.int_addr 90819880Swollman : 0)); 90918316Swollman if (ifp != 0) { 91018316Swollman ifp->int_state |= IS_CHECKED; 91118316Swollman 91218316Swollman if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags) 91318316Swollman & (IFF_BROADCAST 91418316Swollman | IFF_LOOPBACK 91518316Swollman | IFF_POINTOPOINT 91618316Swollman | IFF_MULTICAST)) 91718316Swollman || 0 != ((ifp->int_state ^ ifs.int_state) 91818316Swollman & IS_ALIAS) 91918316Swollman || ifp->int_addr != ifs.int_addr 92018316Swollman || ifp->int_brdaddr != ifs.int_brdaddr 92118316Swollman || ifp->int_dstaddr != ifs.int_dstaddr 92218316Swollman || ifp->int_mask != ifs.int_mask 92318316Swollman || ifp->int_metric != ifs.int_metric) { 92418316Swollman /* Forget old information about 92518316Swollman * a changed interface. 92618316Swollman */ 92719880Swollman trace_act("interface %s has changed", 92818316Swollman ifp->int_name); 92918316Swollman ifdel(ifp); 93018316Swollman ifp = 0; 93118316Swollman } 93218316Swollman } 93318316Swollman 93418316Swollman if (ifp != 0) { 93518316Swollman /* The primary representative of an alias worries 93618316Swollman * about how things are working. 93718316Swollman */ 93818316Swollman if (ifp->int_state & IS_ALIAS) 93918316Swollman continue; 94018316Swollman 94118316Swollman /* note interfaces that have been turned off 94218316Swollman */ 94346303Smarkm if (!iff_up(ifs.int_if_flags)) { 94446303Smarkm if (iff_up(ifp->int_if_flags)) { 94518316Swollman msglog("interface %s to %s turned off", 94618316Swollman ifp->int_name, 94719880Swollman naddr_ntoa(ifp->int_dstaddr)); 94818316Swollman if_bad(ifp); 94946303Smarkm ifp->int_if_flags &= ~IFF_UP; 95046303Smarkm } else if (now.tv_sec>(ifp->int_data.ts 95146303Smarkm + CHECK_BAD_INTERVAL)) { 95246303Smarkm trace_act("interface %s has been off" 953204405Suqs " %jd seconds; forget it", 95446303Smarkm ifp->int_name, 955204405Suqs (intmax_t)now.tv_sec - 956190712Sphk ifp->int_data.ts); 95746303Smarkm ifdel(ifp); 95818316Swollman } 95918316Swollman continue; 96018316Swollman } 96118316Swollman /* or that were off and are now ok */ 96246303Smarkm if (!iff_up(ifp->int_if_flags)) { 96346303Smarkm ifp->int_if_flags |= IFF_UP; 96418316Swollman (void)if_ok(ifp, ""); 96518316Swollman } 96618316Swollman 96718316Swollman /* If it has been long enough, 96818316Swollman * see if the interface is broken. 96918316Swollman */ 97018316Swollman if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL) 97118316Swollman continue; 97218316Swollman 97318316Swollman in = ifs.int_data.ipackets - ifp->int_data.ipackets; 97418316Swollman ierr = ifs.int_data.ierrors - ifp->int_data.ierrors; 97518316Swollman out = ifs.int_data.opackets - ifp->int_data.opackets; 97618316Swollman oerr = ifs.int_data.oerrors - ifp->int_data.oerrors; 97718316Swollman#ifdef sgi 97818316Swollman /* Through at least IRIX 6.2, PPP and SLIP 97946303Smarkm * count packets dropped by the filters. 98018316Swollman * But FDDI rings stuck non-operational count 98118316Swollman * dropped packets as they wait for improvement. 98218316Swollman */ 98318316Swollman if (!(ifp->int_if_flags & IFF_POINTOPOINT)) 98418316Swollman oerr += (ifs.int_data.odrops 98518316Swollman - ifp->int_data.odrops); 98618316Swollman#endif 98718316Swollman /* If the interface just awoke, restart the counters. 98818316Swollman */ 98918316Swollman if (ifp->int_data.ts == 0) { 99018316Swollman ifp->int_data = ifs.int_data; 99118316Swollman continue; 99218316Swollman } 99318316Swollman ifp->int_data = ifs.int_data; 99418316Swollman 99537908Scharnier /* Withhold judgment when the short error 99618316Swollman * counters wrap or the interface is reset. 99718316Swollman */ 99818316Swollman if (ierr < 0 || in < 0 || oerr < 0 || out < 0) { 99918316Swollman LIM_SEC(ifinit_timer, 100018316Swollman now.tv_sec+CHECK_BAD_INTERVAL); 100118316Swollman continue; 100218316Swollman } 100318316Swollman 100418316Swollman /* Withhold judgement when there is no traffic 100518316Swollman */ 100618316Swollman if (in == 0 && out == 0 && ierr == 0 && oerr == 0) 100718316Swollman continue; 100818316Swollman 100918316Swollman /* It is bad if input or output is not working. 101018316Swollman * Require presistent problems before marking it dead. 101118316Swollman */ 101218316Swollman if ((in <= ierr && ierr > 0) 101318316Swollman || (out <= oerr && oerr > 0)) { 101418316Swollman if (!(ifp->int_state & IS_SICK)) { 101518316Swollman trace_act("interface %s to %s" 101618316Swollman " sick: in=%d ierr=%d" 101719880Swollman " out=%d oerr=%d", 101818316Swollman ifp->int_name, 101919880Swollman naddr_ntoa(ifp->int_dstaddr), 102018316Swollman in, ierr, out, oerr); 102118316Swollman if_sick(ifp); 102218316Swollman continue; 102318316Swollman } 102418316Swollman if (!(ifp->int_state & IS_BROKE)) { 102519880Swollman msglog("interface %s to %s broken:" 102618316Swollman " in=%d ierr=%d out=%d oerr=%d", 102718316Swollman ifp->int_name, 102819880Swollman naddr_ntoa(ifp->int_dstaddr), 102918316Swollman in, ierr, out, oerr); 103018316Swollman if_bad(ifp); 103118316Swollman } 103218316Swollman continue; 103318316Swollman } 103418316Swollman 103518316Swollman /* otherwise, it is active and healthy 103618316Swollman */ 103718316Swollman ifp->int_act_time = now.tv_sec; 103818316Swollman (void)if_ok(ifp, ""); 103918316Swollman continue; 104018316Swollman } 104118316Swollman 104218316Swollman /* This is a new interface. 104318316Swollman * If it is dead, forget it. 104418316Swollman */ 104546303Smarkm if (!iff_up(ifs.int_if_flags)) 104618316Swollman continue; 104718316Swollman 104819880Swollman /* If it duplicates an existing interface, 104919880Swollman * complain about it, mark the other one 105019880Swollman * duplicated, and forget this one. 105118316Swollman */ 105219880Swollman ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, 105319880Swollman ifs.int_if_flags); 105419880Swollman if (ifp != 0) { 105546303Smarkm /* Ignore duplicates of itself, caused by having 105646303Smarkm * IP aliases on the same network. 105746303Smarkm */ 105846303Smarkm if (!strcmp(ifp->int_name, ifs.int_name)) 105946303Smarkm continue; 106046303Smarkm 106118316Swollman if (!(prev_complaints & COMP_DUP)) { 106218316Swollman complaints |= COMP_DUP; 106320339Swollman msglog("%s (%s%s%s) is duplicated by" 106420339Swollman " %s (%s%s%s)", 106520339Swollman ifs.int_name, 106620339Swollman addrname(ifs.int_addr,ifs.int_mask,1), 106720339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 106820339Swollman ? "-->" : ""), 106920339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 107020339Swollman ? naddr_ntoa(ifs.int_dstaddr) : ""), 107120339Swollman ifp->int_name, 107220339Swollman addrname(ifp->int_addr,ifp->int_mask,1), 107320339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 107420339Swollman ? "-->" : ""), 107520339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 107620339Swollman ? naddr_ntoa(ifp->int_dstaddr) : "")); 107718316Swollman } 107818316Swollman ifp->int_state |= IS_DUP; 107919880Swollman continue; 108018316Swollman } 108118316Swollman 1082133715Sphk if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST | IFF_LOOPBACK))) { 108319880Swollman trace_act("%s is neither broadcast, point-to-point," 108419880Swollman " nor loopback", 108519880Swollman ifs.int_name); 108619880Swollman if (!(ifs.int_state & IFF_MULTICAST)) 108719880Swollman ifs.int_state |= IS_NO_RDISC; 108819880Swollman } 108918316Swollman 109019880Swollman 109119880Swollman /* It is new and ok. Add it to the list of interfaces 109218316Swollman */ 109346303Smarkm ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp"); 109446303Smarkm memcpy(ifp, &ifs, sizeof(*ifp)); 109519880Swollman get_parms(ifp); 109619880Swollman if_link(ifp); 109718316Swollman trace_if("Add", ifp); 109818316Swollman 109918316Swollman /* Notice likely bad netmask. 110018316Swollman */ 110118316Swollman if (!(prev_complaints & COMP_NETMASK) 110219880Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 110319880Swollman && ifp->int_addr != RIP_DEFAULT) { 1104190711Sphk LIST_FOREACH(ifp1, &ifnet, int_list) { 110518316Swollman if (ifp1->int_mask == ifp->int_mask) 110618316Swollman continue; 110718316Swollman if (ifp1->int_if_flags & IFF_POINTOPOINT) 110818316Swollman continue; 110919880Swollman if (ifp1->int_dstaddr == RIP_DEFAULT) 111019880Swollman continue; 111164483Ssheldonh /* ignore aliases on the right network */ 111264483Ssheldonh if (!strcmp(ifp->int_name, ifp1->int_name)) 111364483Ssheldonh continue; 111419880Swollman if (on_net(ifp->int_dstaddr, 111518316Swollman ifp1->int_net, ifp1->int_mask) 111619880Swollman || on_net(ifp1->int_dstaddr, 111718316Swollman ifp->int_net, ifp->int_mask)) { 111818316Swollman msglog("possible netmask problem" 111919880Swollman " between %s:%s and %s:%s", 112018316Swollman ifp->int_name, 112118316Swollman addrname(htonl(ifp->int_net), 112218316Swollman ifp->int_mask, 1), 112318316Swollman ifp1->int_name, 112418316Swollman addrname(htonl(ifp1->int_net), 112518316Swollman ifp1->int_mask, 1)); 112618316Swollman complaints |= COMP_NETMASK; 112718316Swollman } 112818316Swollman } 112918316Swollman } 113018316Swollman 113118316Swollman if (!(ifp->int_state & IS_ALIAS)) { 113219880Swollman /* Count the # of directly connected networks. 113319880Swollman */ 113418316Swollman if (!(ifp->int_if_flags & IFF_LOOPBACK)) 113518316Swollman tot_interfaces++; 113618316Swollman if (!IS_RIP_OFF(ifp->int_state)) 113718316Swollman rip_interfaces++; 113819880Swollman 113919880Swollman /* turn on router discovery and RIP If needed */ 114019880Swollman if_ok_rdisc(ifp); 114119880Swollman rip_on(ifp); 114218316Swollman } 114318316Swollman } 114418316Swollman 114519880Swollman /* If we are multi-homed and have at least two interfaces 114618316Swollman * listening to RIP, then output by default. 114718316Swollman */ 114818316Swollman if (!supplier_set && rip_interfaces > 1) 114918316Swollman set_supplier(); 115018316Swollman 115118316Swollman /* If we are multi-homed, optionally advertise a route to 115218316Swollman * our main address. 115318316Swollman */ 115418316Swollman if (advertise_mhome 115518316Swollman || (tot_interfaces > 1 115618316Swollman && mhome 115718316Swollman && (ifp = ifwithaddr(myaddr, 0, 0)) != 0 115818316Swollman && foundloopback)) { 115918316Swollman advertise_mhome = 1; 116018316Swollman rt = rtget(myaddr, HOST_MASK); 116118316Swollman if (rt != 0) { 116218316Swollman if (rt->rt_ifp != ifp 116318316Swollman || rt->rt_router != loopaddr) { 116418316Swollman rtdelete(rt); 116518316Swollman rt = 0; 116618316Swollman } else { 116746303Smarkm loop_rts.rts_ifp = ifp; 116846303Smarkm loop_rts.rts_metric = 0; 116946303Smarkm loop_rts.rts_time = rt->rt_time; 117018316Swollman rtchange(rt, rt->rt_state | RS_MHOME, 117146303Smarkm &loop_rts, 0); 117218316Swollman } 117318316Swollman } 117446303Smarkm if (rt == 0) { 117546303Smarkm loop_rts.rts_ifp = ifp; 117646303Smarkm loop_rts.rts_metric = 0; 117746303Smarkm rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts); 117846303Smarkm } 117918316Swollman } 118018316Swollman 1181190711Sphk LIST_FOREACH_SAFE(ifp, &ifnet, int_list, ifp1) { 118218316Swollman /* Forget any interfaces that have disappeared. 118318316Swollman */ 118418316Swollman if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { 118519880Swollman trace_act("interface %s has disappeared", 118618316Swollman ifp->int_name); 118718316Swollman ifdel(ifp); 118818316Swollman continue; 118918316Swollman } 119018316Swollman 119118316Swollman if ((ifp->int_state & IS_BROKE) 119218316Swollman && !(ifp->int_state & IS_PASSIVE)) 119318316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 119418316Swollman 119518316Swollman /* If we ever have a RIPv1 interface, assume we always will. 119618316Swollman * It might come back if it ever goes away. 119718316Swollman */ 119818316Swollman if (!(ifp->int_state & IS_NO_RIPV1_OUT) && supplier) 119918316Swollman have_ripv1_out = 1; 120018316Swollman if (!(ifp->int_state & IS_NO_RIPV1_IN)) 120118316Swollman have_ripv1_in = 1; 120218316Swollman } 120318316Swollman 1204190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 120518316Swollman /* Ensure there is always a network route for interfaces, 120618316Swollman * after any dead interfaces have been deleted, which 120718316Swollman * might affect routes for point-to-point links. 120818316Swollman */ 120919880Swollman if (!addrouteforif(ifp)) 121019880Swollman continue; 121118316Swollman 121218316Swollman /* Add routes to the local end of point-to-point interfaces 121318316Swollman * using loopback. 121418316Swollman */ 121518316Swollman if ((ifp->int_if_flags & IFF_POINTOPOINT) 121618316Swollman && !(ifp->int_state & IS_REMOTE) 121718316Swollman && foundloopback) { 121818316Swollman /* Delete any routes to the network address through 121918316Swollman * foreign routers. Remove even static routes. 122018316Swollman */ 122146303Smarkm del_static(ifp->int_addr, HOST_MASK, 0, 0); 122218316Swollman rt = rtget(ifp->int_addr, HOST_MASK); 122318316Swollman if (rt != 0 && rt->rt_router != loopaddr) { 122418316Swollman rtdelete(rt); 122518316Swollman rt = 0; 122618316Swollman } 122718316Swollman if (rt != 0) { 122818316Swollman if (!(rt->rt_state & RS_LOCAL) 122918316Swollman || rt->rt_metric > ifp->int_metric) { 123018316Swollman ifp1 = ifp; 123118316Swollman } else { 123218316Swollman ifp1 = rt->rt_ifp; 123318316Swollman } 123446303Smarkm loop_rts.rts_ifp = ifp1; 123546303Smarkm loop_rts.rts_metric = 0; 123646303Smarkm loop_rts.rts_time = rt->rt_time; 123746303Smarkm rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) 123846303Smarkm | (RS_IF|RS_LOCAL)), 123946303Smarkm &loop_rts, 0); 124018316Swollman } else { 124146303Smarkm loop_rts.rts_ifp = ifp; 124246303Smarkm loop_rts.rts_metric = 0; 124318316Swollman rtadd(ifp->int_addr, HOST_MASK, 124446303Smarkm (RS_IF | RS_LOCAL), &loop_rts); 124518316Swollman } 124618316Swollman } 124718316Swollman } 124818316Swollman 124918316Swollman /* add the authority routes */ 125018316Swollman for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) { 125118316Swollman rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); 125218316Swollman if (rt != 0 125318316Swollman && !(rt->rt_state & RS_NO_NET_SYN) 125418316Swollman && !(rt->rt_state & RS_NET_INT)) { 125518316Swollman rtdelete(rt); 125618316Swollman rt = 0; 125718316Swollman } 125846303Smarkm if (rt == 0) { 125946303Smarkm loop_rts.rts_ifp = 0; 126046303Smarkm loop_rts.rts_metric = intnetp->intnet_metric-1; 126118316Swollman rtadd(intnetp->intnet_addr, intnetp->intnet_mask, 126246303Smarkm RS_NET_SYN | RS_NET_INT, &loop_rts); 126346303Smarkm } 126418316Swollman } 126518316Swollman 126618316Swollman prev_complaints = complaints; 126718316Swollman} 126818316Swollman 126918316Swollman 127018316Swollmanstatic void 127118316Swollmancheck_net_syn(struct interface *ifp) 127218316Swollman{ 127318316Swollman struct rt_entry *rt; 127446303Smarkm static struct rt_spare new; 127518316Swollman 127618316Swollman 127718316Swollman /* Turn on the need to automatically synthesize a network route 127818316Swollman * for this interface only if we are running RIPv1 on some other 127918316Swollman * interface that is on a different class-A,B,or C network. 128018316Swollman */ 128118316Swollman if (have_ripv1_out || have_ripv1_in) { 128218316Swollman ifp->int_state |= IS_NEED_NET_SYN; 128318316Swollman rt = rtget(ifp->int_std_addr, ifp->int_std_mask); 128418316Swollman if (rt != 0 128518316Swollman && 0 == (rt->rt_state & RS_NO_NET_SYN) 128618316Swollman && (!(rt->rt_state & RS_NET_SYN) 128718316Swollman || rt->rt_metric > ifp->int_metric)) { 128818316Swollman rtdelete(rt); 128918316Swollman rt = 0; 129018316Swollman } 129146303Smarkm if (rt == 0) { 129246303Smarkm new.rts_ifp = ifp; 129346303Smarkm new.rts_gate = ifp->int_addr; 129446303Smarkm new.rts_router = ifp->int_addr; 129546303Smarkm new.rts_metric = ifp->int_metric; 129618316Swollman rtadd(ifp->int_std_addr, ifp->int_std_mask, 129746303Smarkm RS_NET_SYN, &new); 129846303Smarkm } 129918316Swollman 130018316Swollman } else { 130118316Swollman ifp->int_state &= ~IS_NEED_NET_SYN; 130218316Swollman 130318316Swollman rt = rtget(ifp->int_std_addr, 130418316Swollman ifp->int_std_mask); 130518316Swollman if (rt != 0 130618316Swollman && (rt->rt_state & RS_NET_SYN) 130718316Swollman && rt->rt_ifp == ifp) 130818316Swollman rtbad_sub(rt); 130918316Swollman } 131018316Swollman} 131118316Swollman 131218316Swollman 131318316Swollman/* Add route for interface if not currently installed. 131418316Swollman * Create route to other end if a point-to-point link, 131518316Swollman * otherwise a route to this (sub)network. 131618316Swollman */ 1317190715Sphkstatic int /* 0=bad interface */ 131818316Swollmanaddrouteforif(struct interface *ifp) 131918316Swollman{ 132018316Swollman struct rt_entry *rt; 132146303Smarkm static struct rt_spare new; 132246303Smarkm naddr dst; 132318316Swollman 132418316Swollman 132518316Swollman /* skip sick interfaces 132618316Swollman */ 132718316Swollman if (ifp->int_state & IS_BROKE) 132819880Swollman return 0; 132918316Swollman 133018316Swollman /* If the interface on a subnet, then install a RIPv1 route to 133118316Swollman * the network as well (unless it is sick). 133218316Swollman */ 133318316Swollman if (ifp->int_state & IS_SUBNET) 133418316Swollman check_net_syn(ifp); 133518316Swollman 133619880Swollman dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) 133719880Swollman ? ifp->int_dstaddr 133819880Swollman : htonl(ifp->int_net)); 133918316Swollman 134046303Smarkm new.rts_ifp = ifp; 134146303Smarkm new.rts_router = ifp->int_addr; 134246303Smarkm new.rts_gate = ifp->int_addr; 134346303Smarkm new.rts_metric = ifp->int_metric; 134446303Smarkm new.rts_time = now.tv_sec; 134546303Smarkm 134619880Swollman /* If we are going to send packets to the gateway, 134719880Swollman * it must be reachable using our physical interfaces 134819880Swollman */ 134919880Swollman if ((ifp->int_state & IS_REMOTE) 135020339Swollman && !(ifp->int_state & IS_EXTERNAL) 135119880Swollman && !check_remote(ifp)) 135219880Swollman return 0; 135318316Swollman 135418316Swollman /* We are finished if the correct main interface route exists. 135518316Swollman * The right route must be for the right interface, not synthesized 135618316Swollman * from a subnet, be a "gateway" or not as appropriate, and so forth. 135718316Swollman */ 135846303Smarkm del_static(dst, ifp->int_mask, 0, 0); 135918316Swollman rt = rtget(dst, ifp->int_mask); 136018316Swollman if (rt != 0) { 136118316Swollman if ((rt->rt_ifp != ifp 136218316Swollman || rt->rt_router != ifp->int_addr) 136318316Swollman && (!(ifp->int_state & IS_DUP) 136418316Swollman || rt->rt_ifp == 0 136518316Swollman || (rt->rt_ifp->int_state & IS_BROKE))) { 136618316Swollman rtdelete(rt); 136718316Swollman rt = 0; 136818316Swollman } else { 136918316Swollman rtchange(rt, ((rt->rt_state | RS_IF) 137018316Swollman & ~(RS_NET_SYN | RS_LOCAL)), 137146303Smarkm &new, 0); 137218316Swollman } 137318316Swollman } 137418316Swollman if (rt == 0) { 137518316Swollman if (ifp->int_transitions++ > 0) 137619880Swollman trace_act("re-install interface %s", 137718316Swollman ifp->int_name); 137818316Swollman 137946303Smarkm rtadd(dst, ifp->int_mask, RS_IF, &new); 138018316Swollman } 138119880Swollman 138219880Swollman return 1; 138318316Swollman} 1384