if.c revision 20606
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 * 3. All advertising materials mentioning features or use of this software 1418316Swollman * must display the following acknowledgement: 1518316Swollman * This product includes software developed by the University of 1618316Swollman * California, Berkeley and its contributors. 1718316Swollman * 4. Neither the name of the University nor the names of its contributors 1818316Swollman * may be used to endorse or promote products derived from this software 1918316Swollman * without specific prior written permission. 2018316Swollman * 2118316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2218316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2318316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2418316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2518316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2618316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2718316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2818316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2918316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3018316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3118316Swollman * SUCH DAMAGE. 3218316Swollman */ 3318316Swollman 3418316Swollman#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) 3518316Swollmanstatic char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93"; 3618316Swollman#elif defined(__NetBSD__) 3718316Swollmanstatic char rcsid[] = "$NetBSD$"; 3818316Swollman#endif 3920606Swollman#ident "$Revision: 1.22 $" 4018316Swollman 4118316Swollman#include "defs.h" 4218316Swollman#include "pathnames.h" 4318316Swollman 4419880Swollmanstruct interface *ifnet; /* all interfaces */ 4519880Swollman 4619880Swollman/* hash table for all interfaces, big enough to tolerate ridiculous 4719880Swollman * numbers of IP aliases. Crazy numbers of aliases such as 7000 4819880Swollman * still will not do well, but not just in looking up interfaces 4919880Swollman * by name or address. 5019880Swollman */ 5119880Swollman#define AHASH_LEN 211 /* must be prime */ 5219880Swollman#define AHASH(a) &ahash[(a)%AHASH_LEN] 5319880Swollmanstruct interface *ahash[AHASH_LEN]; 5419880Swollman 5519880Swollman#define BHASH_LEN 211 /* must be prime */ 5619880Swollman#define BHASH(a) &bhash[(a)%BHASH_LEN] 5719880Swollmanstruct interface *bhash[BHASH_LEN]; 5819880Swollman 5919880Swollmanstruct interface *remote_if; /* remote interfaces */ 6019880Swollman 6119880Swollman/* hash for physical interface names. 6219880Swollman * Assume there are never more 100 or 200 real interfaces, and that 6320606Swollman * aliases are put on the end of the hash chains. 6419880Swollman */ 6519880Swollman#define NHASH_LEN 97 6619880Swollmanstruct interface *nhash[NHASH_LEN]; 6719880Swollman 6818316Swollmanint tot_interfaces; /* # of remote and local interfaces */ 6918316Swollmanint rip_interfaces; /* # of interfaces doing RIP */ 7018316Swollmanint foundloopback; /* valid flag for loopaddr */ 7118316Swollmannaddr loopaddr; /* our address on loopback */ 7218316Swollman 7318316Swollmanstruct timeval ifinit_timer; 7420606Swollmanstatic struct timeval last_ifinit; 7518316Swollman 7618316Swollmanint have_ripv1_out; /* have a RIPv1 interface */ 7718316Swollmanint have_ripv1_in; 7818316Swollman 7918316Swollman 8020606Swollman/* Link a new interface into the lists and hash tables. 8120606Swollman */ 8219880Swollmanvoid 8319880Swollmanif_link(struct interface *ifp) 8419880Swollman{ 8519880Swollman int i; 8619880Swollman char *p; 8719880Swollman struct interface **hifp; 8819880Swollman 8919880Swollman ifp->int_prev = &ifnet; 9019880Swollman ifp->int_next = ifnet; 9119880Swollman if (ifnet != 0) 9219880Swollman ifnet->int_prev = &ifp->int_next; 9319880Swollman ifnet = ifp; 9419880Swollman 9519880Swollman hifp = AHASH(ifp->int_addr); 9619880Swollman ifp->int_ahash_prev = hifp; 9719880Swollman ifp->int_ahash = *hifp; 9819880Swollman if ((ifp->int_ahash = *hifp) != 0) 9919880Swollman (*hifp)->int_ahash_prev = &ifp->int_ahash; 10019880Swollman *hifp = ifp; 10119880Swollman 10219880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 10319880Swollman hifp = BHASH(ifp->int_brdaddr); 10419880Swollman ifp->int_bhash = *hifp; 10519880Swollman ifp->int_bhash_prev = hifp; 10619880Swollman if ((ifp->int_bhash = *hifp) != 0) 10719880Swollman (*hifp)->int_bhash_prev = &ifp->int_bhash; 10819880Swollman *hifp = ifp; 10919880Swollman } 11019880Swollman 11119880Swollman if (ifp->int_state & IS_REMOTE) { 11219880Swollman ifp->int_rlink_prev = &remote_if; 11319880Swollman ifp->int_rlink = remote_if; 11419880Swollman if (remote_if != 0) 11519880Swollman remote_if->int_rlink_prev = &ifp->int_rlink; 11619880Swollman remote_if = ifp; 11719880Swollman } 11819880Swollman 11919880Swollman for (i = 0, p = ifp->int_name; *p != '\0'; p++) 12019880Swollman i += *p; 12119880Swollman hifp = &nhash[i % NHASH_LEN]; 12219880Swollman if (ifp->int_state & IS_ALIAS) { 12320606Swollman /* put aliases on the end of the hash chain */ 12419880Swollman while (*hifp != 0) 12519880Swollman hifp = &(*hifp)->int_nhash; 12619880Swollman } 12719880Swollman ifp->int_nhash = *hifp; 12819880Swollman ifp->int_nhash_prev = hifp; 12919880Swollman if ((ifp->int_nhash = *hifp) != 0) 13019880Swollman (*hifp)->int_nhash_prev = &ifp->int_nhash; 13119880Swollman *hifp = ifp; 13219880Swollman} 13319880Swollman 13419880Swollman 13518316Swollman/* Find the interface with an address 13618316Swollman */ 13718316Swollmanstruct interface * 13818316Swollmanifwithaddr(naddr addr, 13918316Swollman int bcast, /* notice IFF_BROADCAST address */ 14018316Swollman int remote) /* include IS_REMOTE interfaces */ 14118316Swollman{ 14218316Swollman struct interface *ifp, *possible = 0; 14318316Swollman 14419880Swollman remote = (remote == 0) ? IS_REMOTE : 0; 14518316Swollman 14619880Swollman for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) { 14719880Swollman if (ifp->int_addr != addr) 14819880Swollman continue; 14919880Swollman if ((ifp->int_state & remote) != 0) 15019880Swollman continue; 15119880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 15219880Swollman return ifp; 15319880Swollman possible = ifp; 15419880Swollman } 15518316Swollman 15619880Swollman if (possible || !bcast) 15719880Swollman return possible; 15819880Swollman 15919880Swollman for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) { 16019880Swollman if (ifp->int_brdaddr != addr) 16119880Swollman continue; 16219880Swollman if ((ifp->int_state & remote) != 0) 16319880Swollman continue; 16419880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 16519880Swollman return ifp; 16619880Swollman possible = ifp; 16718316Swollman } 16818316Swollman 16918316Swollman return possible; 17018316Swollman} 17118316Swollman 17218316Swollman 17318316Swollman/* find the interface with a name 17418316Swollman */ 17518316Swollmanstruct interface * 17618316Swollmanifwithname(char *name, /* "ec0" or whatever */ 17718316Swollman naddr addr) /* 0 or network address */ 17818316Swollman{ 17918316Swollman struct interface *ifp; 18019880Swollman int i; 18119880Swollman char *p; 18218316Swollman 18320606Swollman for (;;) { 18420606Swollman for (i = 0, p = name; *p != '\0'; p++) 18520606Swollman i += *p; 18620606Swollman ifp = nhash[i % NHASH_LEN]; 18720606Swollman 18820606Swollman while (ifp != 0) { 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 ifp = ifp->int_nhash; 19820606Swollman } 19920606Swollman 20020606Swollman 20120606Swollman /* If there is no known interface, maybe there is a 20220606Swollman * new interface. So just once look for new interfaces. 20319880Swollman */ 20420606Swollman if (last_ifinit.tv_sec == now.tv_sec 20520606Swollman && last_ifinit.tv_usec == now.tv_usec) 20620606Swollman return 0; 20720606Swollman ifinit(); 20818316Swollman } 20918316Swollman} 21018316Swollman 21118316Swollman 21218316Swollmanstruct interface * 21318316Swollmanifwithindex(u_short index) 21418316Swollman{ 21518316Swollman struct interface *ifp; 21618316Swollman 21718316Swollman 21818316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 21918316Swollman if (ifp->int_index == index) 22018316Swollman return ifp; 22118316Swollman } 22218316Swollman return 0; 22318316Swollman} 22418316Swollman 22518316Swollman 22618316Swollman/* Find an interface from which the specified address 22718316Swollman * should have come from. Used for figuring out which 22820339Swollman * interface a packet came in on. 22918316Swollman */ 23018316Swollmanstruct interface * 23118316Swollmaniflookup(naddr addr) 23218316Swollman{ 23318316Swollman struct interface *ifp, *maybe; 23418316Swollman 23518316Swollman maybe = 0; 23620339Swollman for (;;) { 23720339Swollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 23820339Swollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 23920339Swollman /* finished with a match */ 24020339Swollman if (ifp->int_dstaddr == addr) 24120339Swollman return ifp; 24218316Swollman 24320339Swollman } else { 24420339Swollman /* finished with an exact match */ 24520339Swollman if (ifp->int_addr == addr) 24620339Swollman return ifp; 24718316Swollman 24820339Swollman /* Look for the longest approximate match. 24920339Swollman */ 25020339Swollman if (on_net(addr, ifp->int_net, ifp->int_mask) 25120339Swollman && (maybe == 0 25220339Swollman || ifp->int_mask > maybe->int_mask)) 25320339Swollman maybe = ifp; 25420339Swollman } 25518316Swollman } 25620339Swollman 25720339Swollman if (maybe != 0 25820606Swollman || (last_ifinit.tv_sec == now.tv_sec 25920606Swollman && last_ifinit.tv_usec == now.tv_usec)) 26020339Swollman return maybe; 26120339Swollman 26220339Swollman /* If there is no known interface, maybe there is a 26320339Swollman * new interface. So just once look for new interfaces. 26420339Swollman */ 26520339Swollman ifinit(); 26618316Swollman } 26718316Swollman} 26818316Swollman 26918316Swollman 27018316Swollman/* Return the classical netmask for an IP address. 27118316Swollman */ 27220339Swollmannaddr /* host byte order */ 27320339Swollmanstd_mask(naddr addr) /* network byte order */ 27418316Swollman{ 27518316Swollman NTOHL(addr); /* was a host, not a network */ 27618316Swollman 27718316Swollman if (addr == 0) /* default route has mask 0 */ 27818316Swollman return 0; 27918316Swollman if (IN_CLASSA(addr)) 28018316Swollman return IN_CLASSA_NET; 28118316Swollman if (IN_CLASSB(addr)) 28218316Swollman return IN_CLASSB_NET; 28318316Swollman return IN_CLASSC_NET; 28418316Swollman} 28518316Swollman 28618316Swollman 28718316Swollman/* Find the netmask that would be inferred by RIPv1 listeners 28818316Swollman * on the given interface for a given network. 28918316Swollman * If no interface is specified, look for the best fitting interface. 29018316Swollman */ 29118316Swollmannaddr 29218316Swollmanripv1_mask_net(naddr addr, /* in network byte order */ 29318316Swollman struct interface *ifp) /* as seen on this interface */ 29418316Swollman{ 29518316Swollman naddr mask = 0; 29618316Swollman 29718316Swollman if (addr == 0) /* default always has 0 mask */ 29818316Swollman return mask; 29918316Swollman 30018316Swollman if (ifp != 0) { 30118316Swollman /* If the target network is that of the associated interface 30218316Swollman * on which it arrived, then use the netmask of the interface. 30318316Swollman */ 30418316Swollman if (on_net(addr, ifp->int_net, ifp->int_std_mask)) 30518316Swollman mask = ifp->int_ripv1_mask; 30618316Swollman 30718316Swollman } else { 30818316Swollman /* Examine all interfaces, and if it the target seems 30918316Swollman * to have the same network number of an interface, use the 31018316Swollman * netmask of that interface. If there is more than one 31118316Swollman * such interface, prefer the interface with the longest 31218316Swollman * match. 31318316Swollman */ 31418316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 31518316Swollman if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) 31618316Swollman && ifp->int_ripv1_mask > mask) 31718316Swollman mask = ifp->int_ripv1_mask; 31818316Swollman } 31918316Swollman } 32018316Swollman 32118316Swollman /* Otherwise, make the classic A/B/C guess. 32218316Swollman */ 32318316Swollman if (mask == 0) 32418316Swollman mask = std_mask(addr); 32518316Swollman 32618316Swollman return mask; 32718316Swollman} 32818316Swollman 32918316Swollman 33018316Swollmannaddr 33118316Swollmanripv1_mask_host(naddr addr, /* in network byte order */ 33218316Swollman struct interface *ifp) /* as seen on this interface */ 33318316Swollman{ 33418316Swollman naddr mask = ripv1_mask_net(addr, ifp); 33518316Swollman 33618316Swollman 33718316Swollman /* If the computed netmask does not mask the address, 33818316Swollman * then assume it is a host address 33918316Swollman */ 34018316Swollman if ((ntohl(addr) & ~mask) != 0) 34118316Swollman mask = HOST_MASK; 34218316Swollman return mask; 34318316Swollman} 34418316Swollman 34518316Swollman 34618316Swollman/* See if a IP address looks reasonable as a destination 34718316Swollman */ 34818316Swollmanint /* 0=bad */ 34918316Swollmancheck_dst(naddr addr) 35018316Swollman{ 35118316Swollman NTOHL(addr); 35218316Swollman 35318316Swollman if (IN_CLASSA(addr)) { 35418316Swollman if (addr == 0) 35518316Swollman return 1; /* default */ 35618316Swollman 35718316Swollman addr >>= IN_CLASSA_NSHIFT; 35818316Swollman return (addr != 0 && addr != IN_LOOPBACKNET); 35918316Swollman } 36018316Swollman 36118316Swollman return (IN_CLASSB(addr) || IN_CLASSC(addr)); 36218316Swollman} 36318316Swollman 36418316Swollman 36519880Swollman/* See a new interface duplicates an existing interface. 36619880Swollman */ 36719880Swollmanstruct interface * 36820339Swollmancheck_dup(naddr addr, /* IP address, so network byte order */ 36920339Swollman naddr dstaddr, /* ditto */ 37020339Swollman naddr mask, /* mask, so host byte order */ 37119880Swollman int if_flags) 37219880Swollman{ 37319880Swollman struct interface *ifp; 37419880Swollman 37519880Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 37619880Swollman if (ifp->int_mask != mask) 37719880Swollman continue; 37819880Swollman 37919880Swollman if (!iff_alive(ifp->int_if_flags)) 38019880Swollman continue; 38119880Swollman 38219880Swollman /* The local address can only be shared with a point-to- 38319880Swollman * point link. 38419880Swollman */ 38519880Swollman if (ifp->int_addr == addr 38619880Swollman && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) 38719880Swollman return ifp; 38819880Swollman 38919880Swollman if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask)) 39019880Swollman return ifp; 39119880Swollman } 39219880Swollman return 0; 39319880Swollman} 39419880Swollman 39519880Swollman 39619880Swollman/* See that a remote gateway is reachable. 39719880Swollman * Note that the answer can change as real interfaces come and go. 39819880Swollman */ 39919880Swollmanint /* 0=bad */ 40019880Swollmancheck_remote(struct interface *ifp) 40119880Swollman{ 40219880Swollman struct rt_entry *rt; 40319880Swollman 40419880Swollman /* do not worry about other kinds */ 40519880Swollman if (!(ifp->int_state & IS_REMOTE)) 40619880Swollman return 1; 40719880Swollman 40819880Swollman rt = rtfind(ifp->int_addr); 40919880Swollman if (rt != 0 41019880Swollman && rt->rt_ifp != 0 41119880Swollman &&on_net(ifp->int_addr, 41219880Swollman rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) 41319880Swollman return 1; 41419880Swollman 41519880Swollman /* the gateway cannot be reached directly from one of our 41619880Swollman * interfaces 41719880Swollman */ 41819880Swollman if (!(ifp->int_state & IS_BROKE)) { 41919880Swollman msglog("unreachable gateway %s in "_PATH_GATEWAYS, 42019880Swollman naddr_ntoa(ifp->int_addr)); 42119880Swollman if_bad(ifp); 42219880Swollman } 42319880Swollman return 0; 42419880Swollman} 42519880Swollman 42619880Swollman 42718316Swollman/* Delete an interface. 42818316Swollman */ 42918316Swollmanstatic void 43018316Swollmanifdel(struct interface *ifp) 43118316Swollman{ 43218316Swollman struct ip_mreq m; 43318316Swollman struct interface *ifp1; 43418316Swollman 43518316Swollman 43618316Swollman trace_if("Del", ifp); 43718316Swollman 43818316Swollman ifp->int_state |= IS_BROKE; 43918316Swollman 44018316Swollman /* unlink the interface 44118316Swollman */ 44219880Swollman *ifp->int_prev = ifp->int_next; 44318316Swollman if (ifp->int_next != 0) 44418316Swollman ifp->int_next->int_prev = ifp->int_prev; 44519880Swollman *ifp->int_ahash_prev = ifp->int_ahash; 44619880Swollman if (ifp->int_ahash != 0) 44719880Swollman ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev; 44819880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 44919880Swollman *ifp->int_bhash_prev = ifp->int_bhash; 45019880Swollman if (ifp->int_bhash != 0) 45119880Swollman ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev; 45219880Swollman } 45319880Swollman if (ifp->int_state & IS_REMOTE) { 45419880Swollman *ifp->int_rlink_prev = ifp->int_rlink; 45519880Swollman if (ifp->int_rlink != 0) 45619880Swollman ifp->int_rlink->int_rlink_prev = ifp->int_rlink_prev; 45719880Swollman } 45818316Swollman 45918316Swollman if (!(ifp->int_state & IS_ALIAS)) { 46019880Swollman /* delete aliases when the main interface dies 46118316Swollman */ 46218316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 46318316Swollman if (ifp1 != ifp 46418316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 46518316Swollman ifdel(ifp1); 46618316Swollman } 46718316Swollman 46818316Swollman if ((ifp->int_if_flags & IFF_MULTICAST) 46918316Swollman#ifdef MCAST_PPP_BUG 47018316Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 47118316Swollman#endif 47218316Swollman && rip_sock >= 0) { 47318316Swollman m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 47418316Swollman m.imr_interface.s_addr = ((ifp->int_if_flags 47518316Swollman & IFF_POINTOPOINT) 47618316Swollman ? ifp->int_dstaddr 47718316Swollman : ifp->int_addr); 47818316Swollman if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP, 47918316Swollman &m, sizeof(m)) < 0 48018316Swollman && errno != EADDRNOTAVAIL 48118316Swollman && !TRACEACTIONS) 48218316Swollman LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)"); 48319880Swollman if (rip_sock_mcast == ifp) 48419880Swollman rip_sock_mcast = 0; 48518316Swollman } 48618316Swollman if (ifp->int_rip_sock >= 0) { 48718316Swollman (void)close(ifp->int_rip_sock); 48818316Swollman ifp->int_rip_sock = -1; 48918316Swollman fix_select(); 49018316Swollman } 49118316Swollman 49218316Swollman tot_interfaces--; 49318316Swollman if (!IS_RIP_OFF(ifp->int_state)) 49418316Swollman rip_interfaces--; 49518316Swollman 49618316Swollman /* Zap all routes associated with this interface. 49718316Swollman * Assume routes just using gateways beyond this interface will 49818316Swollman * timeout naturally, and have probably already died. 49918316Swollman */ 50018316Swollman (void)rn_walktree(rhead, walk_bad, 0); 50118316Swollman 50218316Swollman set_rdisc_mg(ifp, 0); 50318316Swollman if_bad_rdisc(ifp); 50418316Swollman } 50518316Swollman 50618316Swollman free(ifp); 50718316Swollman} 50818316Swollman 50918316Swollman 51018316Swollman/* Mark an interface ill. 51118316Swollman */ 51218316Swollmanvoid 51318316Swollmanif_sick(struct interface *ifp) 51418316Swollman{ 51518316Swollman if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) { 51618316Swollman ifp->int_state |= IS_SICK; 51719880Swollman ifp->int_act_time = NEVER; 51818316Swollman trace_if("Chg", ifp); 51918316Swollman 52018316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 52118316Swollman } 52218316Swollman} 52318316Swollman 52418316Swollman 52518316Swollman/* Mark an interface dead. 52618316Swollman */ 52718316Swollmanvoid 52818316Swollmanif_bad(struct interface *ifp) 52918316Swollman{ 53018316Swollman struct interface *ifp1; 53118316Swollman 53218316Swollman 53318316Swollman if (ifp->int_state & IS_BROKE) 53418316Swollman return; 53518316Swollman 53618316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 53718316Swollman 53818316Swollman ifp->int_state |= (IS_BROKE | IS_SICK); 53919880Swollman ifp->int_act_time = NEVER; 54019880Swollman ifp->int_query_time = NEVER; 54118316Swollman ifp->int_data.ts = 0; 54218316Swollman 54318316Swollman trace_if("Chg", ifp); 54418316Swollman 54518316Swollman if (!(ifp->int_state & IS_ALIAS)) { 54618316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 54718316Swollman if (ifp1 != ifp 54818316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 54918316Swollman if_bad(ifp1); 55018316Swollman } 55118316Swollman (void)rn_walktree(rhead, walk_bad, 0); 55218316Swollman if_bad_rdisc(ifp); 55318316Swollman } 55418316Swollman} 55518316Swollman 55618316Swollman 55718316Swollman/* Mark an interface alive 55818316Swollman */ 55918316Swollmanint /* 1=it was dead */ 56018316Swollmanif_ok(struct interface *ifp, 56118316Swollman char *type) 56218316Swollman{ 56318316Swollman struct interface *ifp1; 56418316Swollman 56518316Swollman 56618316Swollman if (!(ifp->int_state & IS_BROKE)) { 56718316Swollman if (ifp->int_state & IS_SICK) { 56819880Swollman trace_act("%sinterface %s to %s working better", 56918316Swollman type, 57019880Swollman ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 57118316Swollman ifp->int_state &= ~IS_SICK; 57218316Swollman } 57318316Swollman return 0; 57418316Swollman } 57518316Swollman 57618316Swollman msglog("%sinterface %s to %s restored", 57719880Swollman type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 57818316Swollman ifp->int_state &= ~(IS_BROKE | IS_SICK); 57918316Swollman ifp->int_data.ts = 0; 58018316Swollman 58118316Swollman if (!(ifp->int_state & IS_ALIAS)) { 58218316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 58318316Swollman if (ifp1 != ifp 58418316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 58518316Swollman if_ok(ifp1, type); 58618316Swollman } 58718316Swollman if_ok_rdisc(ifp); 58818316Swollman } 58919880Swollman 59019880Swollman if (ifp->int_state & IS_REMOTE) { 59119880Swollman if (!addrouteforif(ifp)) 59219880Swollman return 0; 59319880Swollman } 59418316Swollman return 1; 59518316Swollman} 59618316Swollman 59718316Swollman 59818316Swollman/* disassemble routing message 59918316Swollman */ 60018316Swollmanvoid 60118316Swollmanrt_xaddrs(struct rt_addrinfo *info, 60218316Swollman struct sockaddr *sa, 60318316Swollman struct sockaddr *lim, 60418316Swollman int addrs) 60518316Swollman{ 60618316Swollman int i; 60718316Swollman#ifdef _HAVE_SA_LEN 60818316Swollman static struct sockaddr sa_zero; 60918316Swollman#endif 61018316Swollman#ifdef sgi 61118316Swollman#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \ 61218316Swollman : sizeof(__uint64_t)) 61318316Swollman#else 61418316Swollman#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ 61518316Swollman : sizeof(long)) 61618316Swollman#endif 61718316Swollman 61818316Swollman 61918316Swollman bzero(info, sizeof(*info)); 62018316Swollman info->rti_addrs = addrs; 62118316Swollman for (i = 0; i < RTAX_MAX && sa < lim; i++) { 62218316Swollman if ((addrs & (1 << i)) == 0) 62318316Swollman continue; 62418316Swollman#ifdef _HAVE_SA_LEN 62518316Swollman info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; 62618316Swollman sa = (struct sockaddr *)((char*)(sa) 62718316Swollman + ROUNDUP(sa->sa_len)); 62818316Swollman#else 62918316Swollman info->rti_info[i] = sa; 63018316Swollman sa = (struct sockaddr *)((char*)(sa) 63118316Swollman + ROUNDUP(_FAKE_SA_LEN_DST(sa))); 63218316Swollman#endif 63318316Swollman } 63418316Swollman} 63518316Swollman 63618316Swollman 63718316Swollman/* Find the network interfaces which have configured themselves. 63818316Swollman * This must be done regularly, if only for extra addresses 63918316Swollman * that come and go on interfaces. 64018316Swollman */ 64118316Swollmanvoid 64218316Swollmanifinit(void) 64318316Swollman{ 64418316Swollman static char *sysctl_buf; 64518316Swollman static size_t sysctl_buf_size = 0; 64618316Swollman uint complaints = 0; 64718316Swollman static u_int prev_complaints = 0; 64818316Swollman# define COMP_NOT_INET 0x001 64919880Swollman# define COMP_NOADDR 0x002 65019880Swollman# define COMP_BADADDR 0x004 65119880Swollman# define COMP_NODST 0x008 65219880Swollman# define COMP_NOBADR 0x010 65319880Swollman# define COMP_NOMASK 0x020 65419880Swollman# define COMP_DUP 0x040 65519880Swollman# define COMP_BAD_METRIC 0x080 65619880Swollman# define COMP_NETMASK 0x100 65718316Swollman 65818316Swollman struct interface ifs, ifs0, *ifp, *ifp1; 65918316Swollman struct rt_entry *rt; 66018316Swollman size_t needed; 66118316Swollman int mib[6]; 66218316Swollman struct if_msghdr *ifm; 66318316Swollman struct ifa_msghdr *ifam, *ifam_lim, *ifam2; 66418316Swollman int in, ierr, out, oerr; 66518316Swollman struct intnet *intnetp; 66618316Swollman struct rt_addrinfo info; 66718316Swollman#ifdef SIOCGIFMETRIC 66818316Swollman struct ifreq ifr; 66918316Swollman#endif 67018316Swollman 67118316Swollman 67220606Swollman last_ifinit = now; 67318316Swollman ifinit_timer.tv_sec = now.tv_sec + (supplier 67418316Swollman ? CHECK_ACT_INTERVAL 67518316Swollman : CHECK_QUIET_INTERVAL); 67618316Swollman 67718316Swollman /* mark all interfaces so we can get rid of thost that disappear */ 67818316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) 67918316Swollman ifp->int_state &= ~(IS_CHECKED | IS_DUP); 68018316Swollman 68118316Swollman /* Fetch the interface list, without too many system calls 68218316Swollman * since we do it repeatedly. 68318316Swollman */ 68418316Swollman mib[0] = CTL_NET; 68518316Swollman mib[1] = PF_ROUTE; 68618316Swollman mib[2] = 0; 68718316Swollman mib[3] = AF_INET; 68818316Swollman mib[4] = NET_RT_IFLIST; 68918316Swollman mib[5] = 0; 69018316Swollman for (;;) { 69118316Swollman if ((needed = sysctl_buf_size) != 0) { 69218316Swollman if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 69318316Swollman break; 69418316Swollman if (errno != ENOMEM && errno != EFAULT) 69518316Swollman BADERR(1, "ifinit: get interface table"); 69618316Swollman free(sysctl_buf); 69718316Swollman needed = 0; 69818316Swollman } 69918316Swollman if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 70018316Swollman BADERR(1,"ifinit: route-sysctl-estimate"); 70118316Swollman sysctl_buf = rtmalloc(sysctl_buf_size = needed, "ifinit"); 70218316Swollman } 70318316Swollman 70418316Swollman ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed); 70518316Swollman for (ifam = (struct ifa_msghdr *)sysctl_buf; 70618316Swollman ifam < ifam_lim; 70718316Swollman ifam = ifam2) { 70818316Swollman 70918316Swollman ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); 71018316Swollman 71118316Swollman if (ifam->ifam_type == RTM_IFINFO) { 71219880Swollman struct sockaddr_dl *sdl; 71319880Swollman 71418316Swollman ifm = (struct if_msghdr *)ifam; 71518316Swollman /* make prototype structure for the IP aliases 71618316Swollman */ 71718316Swollman bzero(&ifs0, sizeof(ifs0)); 71818316Swollman ifs0.int_rip_sock = -1; 71918316Swollman ifs0.int_index = ifm->ifm_index; 72018316Swollman ifs0.int_if_flags = ifm->ifm_flags; 72118316Swollman ifs0.int_state = IS_CHECKED; 72220339Swollman ifs0.int_query_time = NEVER; 72318316Swollman ifs0.int_act_time = now.tv_sec; 72418316Swollman ifs0.int_data.ts = now.tv_sec; 72518316Swollman ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; 72618316Swollman ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors; 72718316Swollman ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets; 72818316Swollman ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors; 72918316Swollman#ifdef sgi 73018316Swollman ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops; 73118316Swollman#endif 73218316Swollman sdl = (struct sockaddr_dl *)(ifm + 1); 73318316Swollman sdl->sdl_data[sdl->sdl_nlen] = 0; 73419880Swollman strncpy(ifs0.int_name, sdl->sdl_data, 73519880Swollman MIN(sizeof(ifs0.int_name), sdl->sdl_nlen)); 73618316Swollman continue; 73718316Swollman } 73818316Swollman if (ifam->ifam_type != RTM_NEWADDR) { 73918316Swollman logbad(1,"ifinit: out of sync"); 74018316Swollman continue; 74118316Swollman } 74218316Swollman rt_xaddrs(&info, (struct sockaddr *)(ifam+1), 74318316Swollman (struct sockaddr *)ifam2, 74418316Swollman ifam->ifam_addrs); 74518316Swollman 74619880Swollman /* Prepare for the next address of this interface, which 74719880Swollman * will be an alias. 74819880Swollman * Do not output RIP or Router-Discovery packets via aliases. 74919880Swollman */ 75019880Swollman bcopy(&ifs0, &ifs, sizeof(ifs)); 75119880Swollman ifs0.int_state |= (IS_ALIAS | IS_NO_RIP | IS_NO_RDISC); 75219880Swollman 75318316Swollman if (INFO_IFA(&info) == 0) { 75418316Swollman if (iff_alive(ifs.int_if_flags)) { 75518316Swollman if (!(prev_complaints & COMP_NOADDR)) 75618316Swollman msglog("%s has no address", 75719880Swollman ifs.int_name); 75818316Swollman complaints |= COMP_NOADDR; 75918316Swollman } 76018316Swollman continue; 76118316Swollman } 76218316Swollman if (INFO_IFA(&info)->sa_family != AF_INET) { 76318316Swollman if (iff_alive(ifs.int_if_flags)) { 76418316Swollman if (!(prev_complaints & COMP_NOT_INET)) 76519880Swollman trace_act("%s: not AF_INET", 76619880Swollman ifs.int_name); 76718316Swollman complaints |= COMP_NOT_INET; 76818316Swollman } 76918316Swollman continue; 77018316Swollman } 77118316Swollman 77218316Swollman ifs.int_addr = S_ADDR(INFO_IFA(&info)); 77318316Swollman 77418316Swollman if (ntohl(ifs.int_addr)>>24 == 0 77518316Swollman || ntohl(ifs.int_addr)>>24 == 0xff) { 77618316Swollman if (iff_alive(ifs.int_if_flags)) { 77718316Swollman if (!(prev_complaints & COMP_BADADDR)) 77818316Swollman msglog("%s has a bad address", 77919880Swollman ifs.int_name); 78018316Swollman complaints |= COMP_BADADDR; 78118316Swollman } 78218316Swollman continue; 78318316Swollman } 78418316Swollman 78519880Swollman if (ifs.int_if_flags & IFF_LOOPBACK) { 78619880Swollman ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC; 78718316Swollman ifs.int_dstaddr = ifs.int_addr; 78819880Swollman ifs.int_mask = HOST_MASK; 78919880Swollman ifs.int_ripv1_mask = HOST_MASK; 79019880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 79119880Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 79219880Swollman if (!foundloopback) { 79319880Swollman foundloopback = 1; 79419880Swollman loopaddr = ifs.int_addr; 79518316Swollman } 79618316Swollman 79718316Swollman } else if (ifs.int_if_flags & IFF_POINTOPOINT) { 79818316Swollman if (INFO_BRD(&info) == 0 79918316Swollman || INFO_BRD(&info)->sa_family != AF_INET) { 80018316Swollman if (iff_alive(ifs.int_if_flags)) { 80118316Swollman if (!(prev_complaints & COMP_NODST)) 80218316Swollman msglog("%s has a bad" 80318316Swollman " destination address", 80419880Swollman ifs.int_name); 80518316Swollman complaints |= COMP_NODST; 80618316Swollman } 80718316Swollman continue; 80818316Swollman } 80918316Swollman ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); 81018316Swollman if (ntohl(ifs.int_dstaddr)>>24 == 0 81118316Swollman || ntohl(ifs.int_dstaddr)>>24 == 0xff) { 81218316Swollman if (iff_alive(ifs.int_if_flags)) { 81318316Swollman if (!(prev_complaints & COMP_NODST)) 81418316Swollman msglog("%s has a bad" 81518316Swollman " destination address", 81619880Swollman ifs.int_name); 81718316Swollman complaints |= COMP_NODST; 81818316Swollman } 81918316Swollman continue; 82018316Swollman } 82118316Swollman ifs.int_mask = HOST_MASK; 82218316Swollman ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); 82319880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 82418316Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 82518316Swollman 82619880Swollman } else { 82719880Swollman if (INFO_MASK(&info) == 0) { 82819880Swollman if (iff_alive(ifs.int_if_flags)) { 82919880Swollman if (!(prev_complaints & COMP_NOMASK)) 83019880Swollman msglog("%s has no netmask", 83119880Swollman ifs.int_name); 83219880Swollman complaints |= COMP_NOMASK; 83319880Swollman } 83419880Swollman continue; 83519880Swollman } 83618316Swollman ifs.int_dstaddr = ifs.int_addr; 83719880Swollman ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); 83819880Swollman ifs.int_ripv1_mask = ifs.int_mask; 83919880Swollman ifs.int_std_mask = std_mask(ifs.int_addr); 84019880Swollman ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; 84119880Swollman if (ifs.int_mask != ifs.int_std_mask) 84219880Swollman ifs.int_state |= IS_SUBNET; 84319880Swollman 84419880Swollman if (ifs.int_if_flags & IFF_BROADCAST) { 84519880Swollman if (INFO_BRD(&info) == 0) { 84619880Swollman if (iff_alive(ifs.int_if_flags)) { 84719880Swollman if (!(prev_complaints 84819880Swollman & COMP_NOBADR)) 84919880Swollman msglog("%s has" 85019880Swollman "no broadcast address", 85119880Swollman ifs.int_name); 85219880Swollman complaints |= COMP_NOBADR; 85319880Swollman } 85419880Swollman continue; 85519880Swollman } 85619880Swollman ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); 85718316Swollman } 85818316Swollman } 85918316Swollman ifs.int_std_net = ifs.int_net & ifs.int_std_mask; 86018316Swollman ifs.int_std_addr = htonl(ifs.int_std_net); 86118316Swollman 86218316Swollman /* Use a minimum metric of one. Treat the interface metric 86318316Swollman * (default 0) as an increment to the hop count of one. 86418316Swollman * 86518316Swollman * The metric obtained from the routing socket dump of 86618316Swollman * interface addresses is wrong. It is not set by the 86718316Swollman * SIOCSIFMETRIC ioctl. 86818316Swollman */ 86918316Swollman#ifdef SIOCGIFMETRIC 87019880Swollman strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name)); 87118316Swollman if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) { 87218316Swollman DBGERR(1, "ioctl(SIOCGIFMETRIC)"); 87318316Swollman ifs.int_metric = 0; 87418316Swollman } else { 87518316Swollman ifs.int_metric = ifr.ifr_metric; 87618316Swollman } 87718316Swollman#else 87818316Swollman ifs.int_metric = ifam->ifam_metric; 87918316Swollman#endif 88018316Swollman if (ifs.int_metric > HOPCNT_INFINITY) { 88118316Swollman ifs.int_metric = 0; 88218316Swollman if (!(prev_complaints & COMP_BAD_METRIC) 88318316Swollman && iff_alive(ifs.int_if_flags)) { 88418316Swollman complaints |= COMP_BAD_METRIC; 88518316Swollman msglog("%s has a metric of %d", 88619880Swollman ifs.int_name, ifs.int_metric); 88718316Swollman } 88818316Swollman } 88918316Swollman 89018316Swollman /* See if this is a familiar interface. 89118316Swollman * If so, stop worrying about it if it is the same. 89218316Swollman * Start it over if it now is to somewhere else, as happens 89318316Swollman * frequently with PPP and SLIP. 89418316Swollman */ 89519880Swollman ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS) 89619880Swollman ? ifs.int_addr 89719880Swollman : 0)); 89818316Swollman if (ifp != 0) { 89918316Swollman ifp->int_state |= IS_CHECKED; 90018316Swollman 90118316Swollman if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags) 90218316Swollman & (IFF_BROADCAST 90318316Swollman | IFF_LOOPBACK 90418316Swollman | IFF_POINTOPOINT 90518316Swollman | IFF_MULTICAST)) 90618316Swollman || 0 != ((ifp->int_state ^ ifs.int_state) 90718316Swollman & IS_ALIAS) 90818316Swollman || ifp->int_addr != ifs.int_addr 90918316Swollman || ifp->int_brdaddr != ifs.int_brdaddr 91018316Swollman || ifp->int_dstaddr != ifs.int_dstaddr 91118316Swollman || ifp->int_mask != ifs.int_mask 91218316Swollman || ifp->int_metric != ifs.int_metric) { 91318316Swollman /* Forget old information about 91418316Swollman * a changed interface. 91518316Swollman */ 91619880Swollman trace_act("interface %s has changed", 91718316Swollman ifp->int_name); 91818316Swollman ifdel(ifp); 91918316Swollman ifp = 0; 92018316Swollman } 92118316Swollman } 92218316Swollman 92318316Swollman if (ifp != 0) { 92418316Swollman /* The primary representative of an alias worries 92518316Swollman * about how things are working. 92618316Swollman */ 92718316Swollman if (ifp->int_state & IS_ALIAS) 92818316Swollman continue; 92918316Swollman 93018316Swollman /* note interfaces that have been turned off 93118316Swollman */ 93218316Swollman if (!iff_alive(ifs.int_if_flags)) { 93318316Swollman if (iff_alive(ifp->int_if_flags)) { 93418316Swollman msglog("interface %s to %s turned off", 93518316Swollman ifp->int_name, 93619880Swollman naddr_ntoa(ifp->int_dstaddr)); 93718316Swollman if_bad(ifp); 93818316Swollman ifp->int_if_flags &= ~IFF_UP_RUNNING; 93918316Swollman } 94018316Swollman continue; 94118316Swollman } 94218316Swollman /* or that were off and are now ok */ 94318316Swollman if (!iff_alive(ifp->int_if_flags)) { 94418316Swollman ifp->int_if_flags |= IFF_UP_RUNNING; 94518316Swollman (void)if_ok(ifp, ""); 94618316Swollman } 94718316Swollman 94818316Swollman /* If it has been long enough, 94918316Swollman * see if the interface is broken. 95018316Swollman */ 95118316Swollman if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL) 95218316Swollman continue; 95318316Swollman 95418316Swollman in = ifs.int_data.ipackets - ifp->int_data.ipackets; 95518316Swollman ierr = ifs.int_data.ierrors - ifp->int_data.ierrors; 95618316Swollman out = ifs.int_data.opackets - ifp->int_data.opackets; 95718316Swollman oerr = ifs.int_data.oerrors - ifp->int_data.oerrors; 95818316Swollman#ifdef sgi 95918316Swollman /* Through at least IRIX 6.2, PPP and SLIP 96018316Swollman * count packets dropped by the filters. 96118316Swollman * But FDDI rings stuck non-operational count 96218316Swollman * dropped packets as they wait for improvement. 96318316Swollman */ 96418316Swollman if (!(ifp->int_if_flags & IFF_POINTOPOINT)) 96518316Swollman oerr += (ifs.int_data.odrops 96618316Swollman - ifp->int_data.odrops); 96718316Swollman#endif 96818316Swollman /* If the interface just awoke, restart the counters. 96918316Swollman */ 97018316Swollman if (ifp->int_data.ts == 0) { 97118316Swollman ifp->int_data = ifs.int_data; 97218316Swollman continue; 97318316Swollman } 97418316Swollman ifp->int_data = ifs.int_data; 97518316Swollman 97618316Swollman /* Withhold judgement when the short error 97718316Swollman * counters wrap or the interface is reset. 97818316Swollman */ 97918316Swollman if (ierr < 0 || in < 0 || oerr < 0 || out < 0) { 98018316Swollman LIM_SEC(ifinit_timer, 98118316Swollman now.tv_sec+CHECK_BAD_INTERVAL); 98218316Swollman continue; 98318316Swollman } 98418316Swollman 98518316Swollman /* Withhold judgement when there is no traffic 98618316Swollman */ 98718316Swollman if (in == 0 && out == 0 && ierr == 0 && oerr == 0) 98818316Swollman continue; 98918316Swollman 99018316Swollman /* It is bad if input or output is not working. 99118316Swollman * Require presistent problems before marking it dead. 99218316Swollman */ 99318316Swollman if ((in <= ierr && ierr > 0) 99418316Swollman || (out <= oerr && oerr > 0)) { 99518316Swollman if (!(ifp->int_state & IS_SICK)) { 99618316Swollman trace_act("interface %s to %s" 99718316Swollman " sick: in=%d ierr=%d" 99819880Swollman " out=%d oerr=%d", 99918316Swollman ifp->int_name, 100019880Swollman naddr_ntoa(ifp->int_dstaddr), 100118316Swollman in, ierr, out, oerr); 100218316Swollman if_sick(ifp); 100318316Swollman continue; 100418316Swollman } 100518316Swollman if (!(ifp->int_state & IS_BROKE)) { 100619880Swollman msglog("interface %s to %s broken:" 100718316Swollman " in=%d ierr=%d out=%d oerr=%d", 100818316Swollman ifp->int_name, 100919880Swollman naddr_ntoa(ifp->int_dstaddr), 101018316Swollman in, ierr, out, oerr); 101118316Swollman if_bad(ifp); 101218316Swollman } 101318316Swollman continue; 101418316Swollman } 101518316Swollman 101618316Swollman /* otherwise, it is active and healthy 101718316Swollman */ 101818316Swollman ifp->int_act_time = now.tv_sec; 101918316Swollman (void)if_ok(ifp, ""); 102018316Swollman continue; 102118316Swollman } 102218316Swollman 102318316Swollman /* This is a new interface. 102418316Swollman * If it is dead, forget it. 102518316Swollman */ 102618316Swollman if (!iff_alive(ifs.int_if_flags)) 102718316Swollman continue; 102818316Swollman 102919880Swollman /* If it duplicates an existing interface, 103019880Swollman * complain about it, mark the other one 103119880Swollman * duplicated, and forget this one. 103218316Swollman */ 103319880Swollman ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, 103419880Swollman ifs.int_if_flags); 103519880Swollman if (ifp != 0) { 103618316Swollman if (!(prev_complaints & COMP_DUP)) { 103718316Swollman complaints |= COMP_DUP; 103820339Swollman msglog("%s (%s%s%s) is duplicated by" 103920339Swollman " %s (%s%s%s)", 104020339Swollman ifs.int_name, 104120339Swollman addrname(ifs.int_addr,ifs.int_mask,1), 104220339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 104320339Swollman ? "-->" : ""), 104420339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 104520339Swollman ? naddr_ntoa(ifs.int_dstaddr) : ""), 104620339Swollman ifp->int_name, 104720339Swollman addrname(ifp->int_addr,ifp->int_mask,1), 104820339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 104920339Swollman ? "-->" : ""), 105020339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 105120339Swollman ? naddr_ntoa(ifp->int_dstaddr) : "")); 105218316Swollman } 105318316Swollman ifp->int_state |= IS_DUP; 105419880Swollman continue; 105518316Swollman } 105618316Swollman 105719880Swollman if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST)) 105819880Swollman && !(ifs.int_state & IS_PASSIVE)) { 105919880Swollman trace_act("%s is neither broadcast, point-to-point," 106019880Swollman " nor loopback", 106119880Swollman ifs.int_name); 106219880Swollman if (!(ifs.int_state & IFF_MULTICAST)) 106319880Swollman ifs.int_state |= IS_NO_RDISC; 106419880Swollman } 106518316Swollman 106619880Swollman 106719880Swollman /* It is new and ok. Add it to the list of interfaces 106818316Swollman */ 106918316Swollman ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit"); 107018316Swollman bcopy(&ifs, ifp, sizeof(*ifp)); 107119880Swollman get_parms(ifp); 107219880Swollman if_link(ifp); 107318316Swollman trace_if("Add", ifp); 107418316Swollman 107518316Swollman /* Notice likely bad netmask. 107618316Swollman */ 107718316Swollman if (!(prev_complaints & COMP_NETMASK) 107819880Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 107919880Swollman && ifp->int_addr != RIP_DEFAULT) { 108018316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 108118316Swollman if (ifp1->int_mask == ifp->int_mask) 108218316Swollman continue; 108318316Swollman if (ifp1->int_if_flags & IFF_POINTOPOINT) 108418316Swollman continue; 108519880Swollman if (ifp1->int_dstaddr == RIP_DEFAULT) 108619880Swollman continue; 108719880Swollman if (on_net(ifp->int_dstaddr, 108818316Swollman ifp1->int_net, ifp1->int_mask) 108919880Swollman || on_net(ifp1->int_dstaddr, 109018316Swollman ifp->int_net, ifp->int_mask)) { 109118316Swollman msglog("possible netmask problem" 109219880Swollman " between %s:%s and %s:%s", 109318316Swollman ifp->int_name, 109418316Swollman addrname(htonl(ifp->int_net), 109518316Swollman ifp->int_mask, 1), 109618316Swollman ifp1->int_name, 109718316Swollman addrname(htonl(ifp1->int_net), 109818316Swollman ifp1->int_mask, 1)); 109918316Swollman complaints |= COMP_NETMASK; 110018316Swollman } 110118316Swollman } 110218316Swollman } 110318316Swollman 110418316Swollman if (!(ifp->int_state & IS_ALIAS)) { 110519880Swollman /* Count the # of directly connected networks. 110619880Swollman */ 110718316Swollman if (!(ifp->int_if_flags & IFF_LOOPBACK)) 110818316Swollman tot_interfaces++; 110918316Swollman if (!IS_RIP_OFF(ifp->int_state)) 111018316Swollman rip_interfaces++; 111119880Swollman 111219880Swollman /* turn on router discovery and RIP If needed */ 111319880Swollman if_ok_rdisc(ifp); 111419880Swollman rip_on(ifp); 111518316Swollman } 111618316Swollman } 111718316Swollman 111819880Swollman /* If we are multi-homed and have at least two interfaces 111918316Swollman * listening to RIP, then output by default. 112018316Swollman */ 112118316Swollman if (!supplier_set && rip_interfaces > 1) 112218316Swollman set_supplier(); 112318316Swollman 112418316Swollman /* If we are multi-homed, optionally advertise a route to 112518316Swollman * our main address. 112618316Swollman */ 112718316Swollman if (advertise_mhome 112818316Swollman || (tot_interfaces > 1 112918316Swollman && mhome 113018316Swollman && (ifp = ifwithaddr(myaddr, 0, 0)) != 0 113118316Swollman && foundloopback)) { 113218316Swollman advertise_mhome = 1; 113318316Swollman rt = rtget(myaddr, HOST_MASK); 113418316Swollman if (rt != 0) { 113518316Swollman if (rt->rt_ifp != ifp 113618316Swollman || rt->rt_router != loopaddr) { 113718316Swollman rtdelete(rt); 113818316Swollman rt = 0; 113918316Swollman } else { 114018316Swollman rtchange(rt, rt->rt_state | RS_MHOME, 114118316Swollman loopaddr, loopaddr, 114218316Swollman 0, 0, ifp, rt->rt_time, 0); 114318316Swollman } 114418316Swollman } 114518316Swollman if (rt == 0) 114618316Swollman rtadd(myaddr, HOST_MASK, loopaddr, loopaddr, 114718316Swollman 0, 0, RS_MHOME, ifp); 114818316Swollman } 114918316Swollman 115018316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp1) { 115118316Swollman ifp1 = ifp->int_next; /* because we may delete it */ 115218316Swollman 115318316Swollman /* Forget any interfaces that have disappeared. 115418316Swollman */ 115518316Swollman if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { 115619880Swollman trace_act("interface %s has disappeared", 115718316Swollman ifp->int_name); 115818316Swollman ifdel(ifp); 115918316Swollman continue; 116018316Swollman } 116118316Swollman 116218316Swollman if ((ifp->int_state & IS_BROKE) 116318316Swollman && !(ifp->int_state & IS_PASSIVE)) 116418316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 116518316Swollman 116618316Swollman /* If we ever have a RIPv1 interface, assume we always will. 116718316Swollman * It might come back if it ever goes away. 116818316Swollman */ 116918316Swollman if (!(ifp->int_state & IS_NO_RIPV1_OUT) && supplier) 117018316Swollman have_ripv1_out = 1; 117118316Swollman if (!(ifp->int_state & IS_NO_RIPV1_IN)) 117218316Swollman have_ripv1_in = 1; 117318316Swollman } 117418316Swollman 117518316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 117618316Swollman /* Ensure there is always a network route for interfaces, 117718316Swollman * after any dead interfaces have been deleted, which 117818316Swollman * might affect routes for point-to-point links. 117918316Swollman */ 118019880Swollman if (!addrouteforif(ifp)) 118119880Swollman continue; 118218316Swollman 118318316Swollman /* Add routes to the local end of point-to-point interfaces 118418316Swollman * using loopback. 118518316Swollman */ 118618316Swollman if ((ifp->int_if_flags & IFF_POINTOPOINT) 118718316Swollman && !(ifp->int_state & IS_REMOTE) 118818316Swollman && foundloopback) { 118918316Swollman /* Delete any routes to the network address through 119018316Swollman * foreign routers. Remove even static routes. 119118316Swollman */ 119218316Swollman del_static(ifp->int_addr, HOST_MASK, 0); 119318316Swollman rt = rtget(ifp->int_addr, HOST_MASK); 119418316Swollman if (rt != 0 && rt->rt_router != loopaddr) { 119518316Swollman rtdelete(rt); 119618316Swollman rt = 0; 119718316Swollman } 119818316Swollman if (rt != 0) { 119918316Swollman if (!(rt->rt_state & RS_LOCAL) 120018316Swollman || rt->rt_metric > ifp->int_metric) { 120118316Swollman ifp1 = ifp; 120218316Swollman } else { 120318316Swollman ifp1 = rt->rt_ifp; 120418316Swollman } 120518316Swollman rtchange(rt,((rt->rt_state & ~RS_NET_SYN) 120618316Swollman | (RS_IF|RS_LOCAL)), 120718316Swollman loopaddr, loopaddr, 120818316Swollman 0, 0, ifp1, rt->rt_time, 0); 120918316Swollman } else { 121018316Swollman rtadd(ifp->int_addr, HOST_MASK, 121118316Swollman loopaddr, loopaddr, 121218316Swollman 0, 0, (RS_IF | RS_LOCAL), ifp); 121318316Swollman } 121418316Swollman } 121518316Swollman } 121618316Swollman 121718316Swollman /* add the authority routes */ 121818316Swollman for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) { 121918316Swollman rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); 122018316Swollman if (rt != 0 122118316Swollman && !(rt->rt_state & RS_NO_NET_SYN) 122218316Swollman && !(rt->rt_state & RS_NET_INT)) { 122318316Swollman rtdelete(rt); 122418316Swollman rt = 0; 122518316Swollman } 122618316Swollman if (rt == 0) 122718316Swollman rtadd(intnetp->intnet_addr, intnetp->intnet_mask, 122818316Swollman loopaddr, loopaddr, intnetp->intnet_metric-1, 122918316Swollman 0, RS_NET_SYN | RS_NET_INT, 0); 123018316Swollman } 123118316Swollman 123218316Swollman prev_complaints = complaints; 123318316Swollman} 123418316Swollman 123518316Swollman 123618316Swollmanstatic void 123718316Swollmancheck_net_syn(struct interface *ifp) 123818316Swollman{ 123918316Swollman struct rt_entry *rt; 124018316Swollman 124118316Swollman 124218316Swollman /* Turn on the need to automatically synthesize a network route 124318316Swollman * for this interface only if we are running RIPv1 on some other 124418316Swollman * interface that is on a different class-A,B,or C network. 124518316Swollman */ 124618316Swollman if (have_ripv1_out || have_ripv1_in) { 124718316Swollman ifp->int_state |= IS_NEED_NET_SYN; 124818316Swollman rt = rtget(ifp->int_std_addr, ifp->int_std_mask); 124918316Swollman if (rt != 0 125018316Swollman && 0 == (rt->rt_state & RS_NO_NET_SYN) 125118316Swollman && (!(rt->rt_state & RS_NET_SYN) 125218316Swollman || rt->rt_metric > ifp->int_metric)) { 125318316Swollman rtdelete(rt); 125418316Swollman rt = 0; 125518316Swollman } 125618316Swollman if (rt == 0) 125718316Swollman rtadd(ifp->int_std_addr, ifp->int_std_mask, 125818316Swollman ifp->int_addr, ifp->int_addr, 125918316Swollman ifp->int_metric, 0, RS_NET_SYN, ifp); 126018316Swollman 126118316Swollman } else { 126218316Swollman ifp->int_state &= ~IS_NEED_NET_SYN; 126318316Swollman 126418316Swollman rt = rtget(ifp->int_std_addr, 126518316Swollman ifp->int_std_mask); 126618316Swollman if (rt != 0 126718316Swollman && (rt->rt_state & RS_NET_SYN) 126818316Swollman && rt->rt_ifp == ifp) 126918316Swollman rtbad_sub(rt); 127018316Swollman } 127118316Swollman} 127218316Swollman 127318316Swollman 127418316Swollman/* Add route for interface if not currently installed. 127518316Swollman * Create route to other end if a point-to-point link, 127618316Swollman * otherwise a route to this (sub)network. 127718316Swollman */ 127819880Swollmanint /* 0=bad interface */ 127918316Swollmanaddrouteforif(struct interface *ifp) 128018316Swollman{ 128118316Swollman struct rt_entry *rt; 128218316Swollman naddr dst, gate; 128318316Swollman 128418316Swollman 128518316Swollman /* skip sick interfaces 128618316Swollman */ 128718316Swollman if (ifp->int_state & IS_BROKE) 128819880Swollman return 0; 128918316Swollman 129018316Swollman /* If the interface on a subnet, then install a RIPv1 route to 129118316Swollman * the network as well (unless it is sick). 129218316Swollman */ 129318316Swollman if (ifp->int_state & IS_SUBNET) 129418316Swollman check_net_syn(ifp); 129518316Swollman 129619880Swollman gate = ifp->int_addr; 129719880Swollman dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) 129819880Swollman ? ifp->int_dstaddr 129919880Swollman : htonl(ifp->int_net)); 130018316Swollman 130119880Swollman /* If we are going to send packets to the gateway, 130219880Swollman * it must be reachable using our physical interfaces 130319880Swollman */ 130419880Swollman if ((ifp->int_state & IS_REMOTE) 130520339Swollman && !(ifp->int_state & IS_EXTERNAL) 130619880Swollman && !check_remote(ifp)) 130719880Swollman return 0; 130818316Swollman 130918316Swollman /* We are finished if the correct main interface route exists. 131018316Swollman * The right route must be for the right interface, not synthesized 131118316Swollman * from a subnet, be a "gateway" or not as appropriate, and so forth. 131218316Swollman */ 131318316Swollman del_static(dst, ifp->int_mask, 0); 131418316Swollman rt = rtget(dst, ifp->int_mask); 131518316Swollman if (rt != 0) { 131618316Swollman if ((rt->rt_ifp != ifp 131718316Swollman || rt->rt_router != ifp->int_addr) 131818316Swollman && (!(ifp->int_state & IS_DUP) 131918316Swollman || rt->rt_ifp == 0 132018316Swollman || (rt->rt_ifp->int_state & IS_BROKE))) { 132118316Swollman rtdelete(rt); 132218316Swollman rt = 0; 132318316Swollman } else { 132418316Swollman rtchange(rt, ((rt->rt_state | RS_IF) 132518316Swollman & ~(RS_NET_SYN | RS_LOCAL)), 132618316Swollman ifp->int_addr, ifp->int_addr, 132718316Swollman ifp->int_metric, 0, ifp, now.tv_sec, 0); 132818316Swollman } 132918316Swollman } 133018316Swollman if (rt == 0) { 133118316Swollman if (ifp->int_transitions++ > 0) 133219880Swollman trace_act("re-install interface %s", 133318316Swollman ifp->int_name); 133418316Swollman 133518316Swollman rtadd(dst, ifp->int_mask, gate, gate, 133618316Swollman ifp->int_metric, 0, RS_IF, ifp); 133718316Swollman } 133819880Swollman 133919880Swollman return 1; 134018316Swollman} 1341