if.c revision 20339
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 3920339Swollman#ident "$Revision: 1.21 $" 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 6319880Swollman * aliases 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; 7418316Swollman 7518316Swollmanint have_ripv1_out; /* have a RIPv1 interface */ 7618316Swollmanint have_ripv1_in; 7718316Swollman 7818316Swollman 7919880Swollmanvoid 8019880Swollmanif_link(struct interface *ifp) 8119880Swollman{ 8219880Swollman int i; 8319880Swollman char *p; 8419880Swollman struct interface **hifp; 8519880Swollman 8619880Swollman ifp->int_prev = &ifnet; 8719880Swollman ifp->int_next = ifnet; 8819880Swollman if (ifnet != 0) 8919880Swollman ifnet->int_prev = &ifp->int_next; 9019880Swollman ifnet = ifp; 9119880Swollman 9219880Swollman hifp = AHASH(ifp->int_addr); 9319880Swollman ifp->int_ahash_prev = hifp; 9419880Swollman ifp->int_ahash = *hifp; 9519880Swollman if ((ifp->int_ahash = *hifp) != 0) 9619880Swollman (*hifp)->int_ahash_prev = &ifp->int_ahash; 9719880Swollman *hifp = ifp; 9819880Swollman 9919880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 10019880Swollman hifp = BHASH(ifp->int_brdaddr); 10119880Swollman ifp->int_bhash = *hifp; 10219880Swollman ifp->int_bhash_prev = hifp; 10319880Swollman if ((ifp->int_bhash = *hifp) != 0) 10419880Swollman (*hifp)->int_bhash_prev = &ifp->int_bhash; 10519880Swollman *hifp = ifp; 10619880Swollman } 10719880Swollman 10819880Swollman if (ifp->int_state & IS_REMOTE) { 10919880Swollman ifp->int_rlink_prev = &remote_if; 11019880Swollman ifp->int_rlink = remote_if; 11119880Swollman if (remote_if != 0) 11219880Swollman remote_if->int_rlink_prev = &ifp->int_rlink; 11319880Swollman remote_if = ifp; 11419880Swollman } 11519880Swollman 11619880Swollman for (i = 0, p = ifp->int_name; *p != '\0'; p++) 11719880Swollman i += *p; 11819880Swollman hifp = &nhash[i % NHASH_LEN]; 11919880Swollman if (ifp->int_state & IS_ALIAS) { 12019880Swollman while (*hifp != 0) 12119880Swollman hifp = &(*hifp)->int_nhash; 12219880Swollman } 12319880Swollman ifp->int_nhash = *hifp; 12419880Swollman ifp->int_nhash_prev = hifp; 12519880Swollman if ((ifp->int_nhash = *hifp) != 0) 12619880Swollman (*hifp)->int_nhash_prev = &ifp->int_nhash; 12719880Swollman *hifp = ifp; 12819880Swollman} 12919880Swollman 13019880Swollman 13118316Swollman/* Find the interface with an address 13218316Swollman */ 13318316Swollmanstruct interface * 13418316Swollmanifwithaddr(naddr addr, 13518316Swollman int bcast, /* notice IFF_BROADCAST address */ 13618316Swollman int remote) /* include IS_REMOTE interfaces */ 13718316Swollman{ 13818316Swollman struct interface *ifp, *possible = 0; 13918316Swollman 14019880Swollman remote = (remote == 0) ? IS_REMOTE : 0; 14118316Swollman 14219880Swollman for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) { 14319880Swollman if (ifp->int_addr != addr) 14419880Swollman continue; 14519880Swollman if ((ifp->int_state & remote) != 0) 14619880Swollman continue; 14719880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 14819880Swollman return ifp; 14919880Swollman possible = ifp; 15019880Swollman } 15118316Swollman 15219880Swollman if (possible || !bcast) 15319880Swollman return possible; 15419880Swollman 15519880Swollman for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) { 15619880Swollman if (ifp->int_brdaddr != addr) 15719880Swollman continue; 15819880Swollman if ((ifp->int_state & remote) != 0) 15919880Swollman continue; 16019880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 16119880Swollman return ifp; 16219880Swollman possible = ifp; 16318316Swollman } 16418316Swollman 16518316Swollman return possible; 16618316Swollman} 16718316Swollman 16818316Swollman 16918316Swollman/* find the interface with a name 17018316Swollman */ 17118316Swollmanstruct interface * 17218316Swollmanifwithname(char *name, /* "ec0" or whatever */ 17318316Swollman naddr addr) /* 0 or network address */ 17418316Swollman{ 17518316Swollman struct interface *ifp; 17619880Swollman int i; 17719880Swollman char *p; 17818316Swollman 17919880Swollman for (i = 0, p = name; *p != '\0'; p++) 18019880Swollman i += *p; 18119880Swollman for (ifp = nhash[i % NHASH_LEN]; ifp != 0; ifp = ifp->int_nhash) { 18219880Swollman /* If the network address is not specified, 18319880Swollman * ignore any alias interfaces. Otherwise, look 18419880Swollman * for the interface with the target name and address. 18519880Swollman */ 18618316Swollman if (!strcmp(ifp->int_name, name) 18719880Swollman && ((addr == 0 && !(ifp->int_state & IS_ALIAS)) 18819880Swollman || (ifp->int_addr == addr))) 18918316Swollman return ifp; 19018316Swollman } 19118316Swollman return 0; 19218316Swollman} 19318316Swollman 19418316Swollman 19518316Swollmanstruct interface * 19618316Swollmanifwithindex(u_short index) 19718316Swollman{ 19818316Swollman struct interface *ifp; 19918316Swollman 20018316Swollman 20118316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 20218316Swollman if (ifp->int_index == index) 20318316Swollman return ifp; 20418316Swollman } 20518316Swollman return 0; 20618316Swollman} 20718316Swollman 20818316Swollman 20918316Swollman/* Find an interface from which the specified address 21018316Swollman * should have come from. Used for figuring out which 21120339Swollman * interface a packet came in on. 21218316Swollman */ 21318316Swollmanstruct interface * 21418316Swollmaniflookup(naddr addr) 21518316Swollman{ 21618316Swollman struct interface *ifp, *maybe; 21720339Swollman static struct timeval retried; 21818316Swollman 21918316Swollman maybe = 0; 22020339Swollman for (;;) { 22120339Swollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 22220339Swollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 22320339Swollman /* finished with a match */ 22420339Swollman if (ifp->int_dstaddr == addr) 22520339Swollman return ifp; 22618316Swollman 22720339Swollman } else { 22820339Swollman /* finished with an exact match */ 22920339Swollman if (ifp->int_addr == addr) 23020339Swollman return ifp; 23118316Swollman 23220339Swollman /* Look for the longest approximate match. 23320339Swollman */ 23420339Swollman if (on_net(addr, ifp->int_net, ifp->int_mask) 23520339Swollman && (maybe == 0 23620339Swollman || ifp->int_mask > maybe->int_mask)) 23720339Swollman maybe = ifp; 23820339Swollman } 23918316Swollman } 24020339Swollman 24120339Swollman if (maybe != 0 24220339Swollman || (retried.tv_sec == now.tv_sec 24320339Swollman && retried.tv_usec == now.tv_usec)) 24420339Swollman return maybe; 24520339Swollman 24620339Swollman /* If there is no known interface, maybe there is a 24720339Swollman * new interface. So just once look for new interfaces. 24820339Swollman */ 24920339Swollman ifinit(); 25020339Swollman retried = now; 25118316Swollman } 25218316Swollman} 25318316Swollman 25418316Swollman 25518316Swollman/* Return the classical netmask for an IP address. 25618316Swollman */ 25720339Swollmannaddr /* host byte order */ 25820339Swollmanstd_mask(naddr addr) /* network byte order */ 25918316Swollman{ 26018316Swollman NTOHL(addr); /* was a host, not a network */ 26118316Swollman 26218316Swollman if (addr == 0) /* default route has mask 0 */ 26318316Swollman return 0; 26418316Swollman if (IN_CLASSA(addr)) 26518316Swollman return IN_CLASSA_NET; 26618316Swollman if (IN_CLASSB(addr)) 26718316Swollman return IN_CLASSB_NET; 26818316Swollman return IN_CLASSC_NET; 26918316Swollman} 27018316Swollman 27118316Swollman 27218316Swollman/* Find the netmask that would be inferred by RIPv1 listeners 27318316Swollman * on the given interface for a given network. 27418316Swollman * If no interface is specified, look for the best fitting interface. 27518316Swollman */ 27618316Swollmannaddr 27718316Swollmanripv1_mask_net(naddr addr, /* in network byte order */ 27818316Swollman struct interface *ifp) /* as seen on this interface */ 27918316Swollman{ 28018316Swollman naddr mask = 0; 28118316Swollman 28218316Swollman if (addr == 0) /* default always has 0 mask */ 28318316Swollman return mask; 28418316Swollman 28518316Swollman if (ifp != 0) { 28618316Swollman /* If the target network is that of the associated interface 28718316Swollman * on which it arrived, then use the netmask of the interface. 28818316Swollman */ 28918316Swollman if (on_net(addr, ifp->int_net, ifp->int_std_mask)) 29018316Swollman mask = ifp->int_ripv1_mask; 29118316Swollman 29218316Swollman } else { 29318316Swollman /* Examine all interfaces, and if it the target seems 29418316Swollman * to have the same network number of an interface, use the 29518316Swollman * netmask of that interface. If there is more than one 29618316Swollman * such interface, prefer the interface with the longest 29718316Swollman * match. 29818316Swollman */ 29918316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 30018316Swollman if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) 30118316Swollman && ifp->int_ripv1_mask > mask) 30218316Swollman mask = ifp->int_ripv1_mask; 30318316Swollman } 30418316Swollman } 30518316Swollman 30618316Swollman /* Otherwise, make the classic A/B/C guess. 30718316Swollman */ 30818316Swollman if (mask == 0) 30918316Swollman mask = std_mask(addr); 31018316Swollman 31118316Swollman return mask; 31218316Swollman} 31318316Swollman 31418316Swollman 31518316Swollmannaddr 31618316Swollmanripv1_mask_host(naddr addr, /* in network byte order */ 31718316Swollman struct interface *ifp) /* as seen on this interface */ 31818316Swollman{ 31918316Swollman naddr mask = ripv1_mask_net(addr, ifp); 32018316Swollman 32118316Swollman 32218316Swollman /* If the computed netmask does not mask the address, 32318316Swollman * then assume it is a host address 32418316Swollman */ 32518316Swollman if ((ntohl(addr) & ~mask) != 0) 32618316Swollman mask = HOST_MASK; 32718316Swollman return mask; 32818316Swollman} 32918316Swollman 33018316Swollman 33118316Swollman/* See if a IP address looks reasonable as a destination 33218316Swollman */ 33318316Swollmanint /* 0=bad */ 33418316Swollmancheck_dst(naddr addr) 33518316Swollman{ 33618316Swollman NTOHL(addr); 33718316Swollman 33818316Swollman if (IN_CLASSA(addr)) { 33918316Swollman if (addr == 0) 34018316Swollman return 1; /* default */ 34118316Swollman 34218316Swollman addr >>= IN_CLASSA_NSHIFT; 34318316Swollman return (addr != 0 && addr != IN_LOOPBACKNET); 34418316Swollman } 34518316Swollman 34618316Swollman return (IN_CLASSB(addr) || IN_CLASSC(addr)); 34718316Swollman} 34818316Swollman 34918316Swollman 35019880Swollman/* See a new interface duplicates an existing interface. 35119880Swollman */ 35219880Swollmanstruct interface * 35320339Swollmancheck_dup(naddr addr, /* IP address, so network byte order */ 35420339Swollman naddr dstaddr, /* ditto */ 35520339Swollman naddr mask, /* mask, so host byte order */ 35619880Swollman int if_flags) 35719880Swollman{ 35819880Swollman struct interface *ifp; 35919880Swollman 36019880Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 36119880Swollman if (ifp->int_mask != mask) 36219880Swollman continue; 36319880Swollman 36419880Swollman if (!iff_alive(ifp->int_if_flags)) 36519880Swollman continue; 36619880Swollman 36719880Swollman /* The local address can only be shared with a point-to- 36819880Swollman * point link. 36919880Swollman */ 37019880Swollman if (ifp->int_addr == addr 37119880Swollman && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) 37219880Swollman return ifp; 37319880Swollman 37419880Swollman if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask)) 37519880Swollman return ifp; 37619880Swollman } 37719880Swollman return 0; 37819880Swollman} 37919880Swollman 38019880Swollman 38119880Swollman/* See that a remote gateway is reachable. 38219880Swollman * Note that the answer can change as real interfaces come and go. 38319880Swollman */ 38419880Swollmanint /* 0=bad */ 38519880Swollmancheck_remote(struct interface *ifp) 38619880Swollman{ 38719880Swollman struct rt_entry *rt; 38819880Swollman 38919880Swollman /* do not worry about other kinds */ 39019880Swollman if (!(ifp->int_state & IS_REMOTE)) 39119880Swollman return 1; 39219880Swollman 39319880Swollman rt = rtfind(ifp->int_addr); 39419880Swollman if (rt != 0 39519880Swollman && rt->rt_ifp != 0 39619880Swollman &&on_net(ifp->int_addr, 39719880Swollman rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) 39819880Swollman return 1; 39919880Swollman 40019880Swollman /* the gateway cannot be reached directly from one of our 40119880Swollman * interfaces 40219880Swollman */ 40319880Swollman if (!(ifp->int_state & IS_BROKE)) { 40419880Swollman msglog("unreachable gateway %s in "_PATH_GATEWAYS, 40519880Swollman naddr_ntoa(ifp->int_addr)); 40619880Swollman if_bad(ifp); 40719880Swollman } 40819880Swollman return 0; 40919880Swollman} 41019880Swollman 41119880Swollman 41218316Swollman/* Delete an interface. 41318316Swollman */ 41418316Swollmanstatic void 41518316Swollmanifdel(struct interface *ifp) 41618316Swollman{ 41718316Swollman struct ip_mreq m; 41818316Swollman struct interface *ifp1; 41918316Swollman 42018316Swollman 42118316Swollman trace_if("Del", ifp); 42218316Swollman 42318316Swollman ifp->int_state |= IS_BROKE; 42418316Swollman 42518316Swollman /* unlink the interface 42618316Swollman */ 42719880Swollman *ifp->int_prev = ifp->int_next; 42818316Swollman if (ifp->int_next != 0) 42918316Swollman ifp->int_next->int_prev = ifp->int_prev; 43019880Swollman *ifp->int_ahash_prev = ifp->int_ahash; 43119880Swollman if (ifp->int_ahash != 0) 43219880Swollman ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev; 43319880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 43419880Swollman *ifp->int_bhash_prev = ifp->int_bhash; 43519880Swollman if (ifp->int_bhash != 0) 43619880Swollman ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev; 43719880Swollman } 43819880Swollman if (ifp->int_state & IS_REMOTE) { 43919880Swollman *ifp->int_rlink_prev = ifp->int_rlink; 44019880Swollman if (ifp->int_rlink != 0) 44119880Swollman ifp->int_rlink->int_rlink_prev = ifp->int_rlink_prev; 44219880Swollman } 44318316Swollman 44418316Swollman if (!(ifp->int_state & IS_ALIAS)) { 44519880Swollman /* delete aliases when the main interface dies 44618316Swollman */ 44718316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 44818316Swollman if (ifp1 != ifp 44918316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 45018316Swollman ifdel(ifp1); 45118316Swollman } 45218316Swollman 45318316Swollman if ((ifp->int_if_flags & IFF_MULTICAST) 45418316Swollman#ifdef MCAST_PPP_BUG 45518316Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 45618316Swollman#endif 45718316Swollman && rip_sock >= 0) { 45818316Swollman m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 45918316Swollman m.imr_interface.s_addr = ((ifp->int_if_flags 46018316Swollman & IFF_POINTOPOINT) 46118316Swollman ? ifp->int_dstaddr 46218316Swollman : ifp->int_addr); 46318316Swollman if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP, 46418316Swollman &m, sizeof(m)) < 0 46518316Swollman && errno != EADDRNOTAVAIL 46618316Swollman && !TRACEACTIONS) 46718316Swollman LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)"); 46819880Swollman if (rip_sock_mcast == ifp) 46919880Swollman rip_sock_mcast = 0; 47018316Swollman } 47118316Swollman if (ifp->int_rip_sock >= 0) { 47218316Swollman (void)close(ifp->int_rip_sock); 47318316Swollman ifp->int_rip_sock = -1; 47418316Swollman fix_select(); 47518316Swollman } 47618316Swollman 47718316Swollman tot_interfaces--; 47818316Swollman if (!IS_RIP_OFF(ifp->int_state)) 47918316Swollman rip_interfaces--; 48018316Swollman 48118316Swollman /* Zap all routes associated with this interface. 48218316Swollman * Assume routes just using gateways beyond this interface will 48318316Swollman * timeout naturally, and have probably already died. 48418316Swollman */ 48518316Swollman (void)rn_walktree(rhead, walk_bad, 0); 48618316Swollman 48718316Swollman set_rdisc_mg(ifp, 0); 48818316Swollman if_bad_rdisc(ifp); 48918316Swollman } 49018316Swollman 49118316Swollman free(ifp); 49218316Swollman} 49318316Swollman 49418316Swollman 49518316Swollman/* Mark an interface ill. 49618316Swollman */ 49718316Swollmanvoid 49818316Swollmanif_sick(struct interface *ifp) 49918316Swollman{ 50018316Swollman if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) { 50118316Swollman ifp->int_state |= IS_SICK; 50219880Swollman ifp->int_act_time = NEVER; 50318316Swollman trace_if("Chg", ifp); 50418316Swollman 50518316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 50618316Swollman } 50718316Swollman} 50818316Swollman 50918316Swollman 51018316Swollman/* Mark an interface dead. 51118316Swollman */ 51218316Swollmanvoid 51318316Swollmanif_bad(struct interface *ifp) 51418316Swollman{ 51518316Swollman struct interface *ifp1; 51618316Swollman 51718316Swollman 51818316Swollman if (ifp->int_state & IS_BROKE) 51918316Swollman return; 52018316Swollman 52118316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 52218316Swollman 52318316Swollman ifp->int_state |= (IS_BROKE | IS_SICK); 52419880Swollman ifp->int_act_time = NEVER; 52519880Swollman ifp->int_query_time = NEVER; 52618316Swollman ifp->int_data.ts = 0; 52718316Swollman 52818316Swollman trace_if("Chg", ifp); 52918316Swollman 53018316Swollman if (!(ifp->int_state & IS_ALIAS)) { 53118316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 53218316Swollman if (ifp1 != ifp 53318316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 53418316Swollman if_bad(ifp1); 53518316Swollman } 53618316Swollman (void)rn_walktree(rhead, walk_bad, 0); 53718316Swollman if_bad_rdisc(ifp); 53818316Swollman } 53918316Swollman} 54018316Swollman 54118316Swollman 54218316Swollman/* Mark an interface alive 54318316Swollman */ 54418316Swollmanint /* 1=it was dead */ 54518316Swollmanif_ok(struct interface *ifp, 54618316Swollman char *type) 54718316Swollman{ 54818316Swollman struct interface *ifp1; 54918316Swollman 55018316Swollman 55118316Swollman if (!(ifp->int_state & IS_BROKE)) { 55218316Swollman if (ifp->int_state & IS_SICK) { 55319880Swollman trace_act("%sinterface %s to %s working better", 55418316Swollman type, 55519880Swollman ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 55618316Swollman ifp->int_state &= ~IS_SICK; 55718316Swollman } 55818316Swollman return 0; 55918316Swollman } 56018316Swollman 56118316Swollman msglog("%sinterface %s to %s restored", 56219880Swollman type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 56318316Swollman ifp->int_state &= ~(IS_BROKE | IS_SICK); 56418316Swollman ifp->int_data.ts = 0; 56518316Swollman 56618316Swollman if (!(ifp->int_state & IS_ALIAS)) { 56718316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 56818316Swollman if (ifp1 != ifp 56918316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 57018316Swollman if_ok(ifp1, type); 57118316Swollman } 57218316Swollman if_ok_rdisc(ifp); 57318316Swollman } 57419880Swollman 57519880Swollman if (ifp->int_state & IS_REMOTE) { 57619880Swollman if (!addrouteforif(ifp)) 57719880Swollman return 0; 57819880Swollman } 57918316Swollman return 1; 58018316Swollman} 58118316Swollman 58218316Swollman 58318316Swollman/* disassemble routing message 58418316Swollman */ 58518316Swollmanvoid 58618316Swollmanrt_xaddrs(struct rt_addrinfo *info, 58718316Swollman struct sockaddr *sa, 58818316Swollman struct sockaddr *lim, 58918316Swollman int addrs) 59018316Swollman{ 59118316Swollman int i; 59218316Swollman#ifdef _HAVE_SA_LEN 59318316Swollman static struct sockaddr sa_zero; 59418316Swollman#endif 59518316Swollman#ifdef sgi 59618316Swollman#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \ 59718316Swollman : sizeof(__uint64_t)) 59818316Swollman#else 59918316Swollman#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ 60018316Swollman : sizeof(long)) 60118316Swollman#endif 60218316Swollman 60318316Swollman 60418316Swollman bzero(info, sizeof(*info)); 60518316Swollman info->rti_addrs = addrs; 60618316Swollman for (i = 0; i < RTAX_MAX && sa < lim; i++) { 60718316Swollman if ((addrs & (1 << i)) == 0) 60818316Swollman continue; 60918316Swollman#ifdef _HAVE_SA_LEN 61018316Swollman info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; 61118316Swollman sa = (struct sockaddr *)((char*)(sa) 61218316Swollman + ROUNDUP(sa->sa_len)); 61318316Swollman#else 61418316Swollman info->rti_info[i] = sa; 61518316Swollman sa = (struct sockaddr *)((char*)(sa) 61618316Swollman + ROUNDUP(_FAKE_SA_LEN_DST(sa))); 61718316Swollman#endif 61818316Swollman } 61918316Swollman} 62018316Swollman 62118316Swollman 62218316Swollman/* Find the network interfaces which have configured themselves. 62318316Swollman * This must be done regularly, if only for extra addresses 62418316Swollman * that come and go on interfaces. 62518316Swollman */ 62618316Swollmanvoid 62718316Swollmanifinit(void) 62818316Swollman{ 62918316Swollman static char *sysctl_buf; 63018316Swollman static size_t sysctl_buf_size = 0; 63118316Swollman uint complaints = 0; 63218316Swollman static u_int prev_complaints = 0; 63318316Swollman# define COMP_NOT_INET 0x001 63419880Swollman# define COMP_NOADDR 0x002 63519880Swollman# define COMP_BADADDR 0x004 63619880Swollman# define COMP_NODST 0x008 63719880Swollman# define COMP_NOBADR 0x010 63819880Swollman# define COMP_NOMASK 0x020 63919880Swollman# define COMP_DUP 0x040 64019880Swollman# define COMP_BAD_METRIC 0x080 64119880Swollman# define COMP_NETMASK 0x100 64218316Swollman 64318316Swollman struct interface ifs, ifs0, *ifp, *ifp1; 64418316Swollman struct rt_entry *rt; 64518316Swollman size_t needed; 64618316Swollman int mib[6]; 64718316Swollman struct if_msghdr *ifm; 64818316Swollman struct ifa_msghdr *ifam, *ifam_lim, *ifam2; 64918316Swollman int in, ierr, out, oerr; 65018316Swollman struct intnet *intnetp; 65118316Swollman struct rt_addrinfo info; 65218316Swollman#ifdef SIOCGIFMETRIC 65318316Swollman struct ifreq ifr; 65418316Swollman#endif 65518316Swollman 65618316Swollman 65718316Swollman ifinit_timer.tv_sec = now.tv_sec + (supplier 65818316Swollman ? CHECK_ACT_INTERVAL 65918316Swollman : CHECK_QUIET_INTERVAL); 66018316Swollman 66118316Swollman /* mark all interfaces so we can get rid of thost that disappear */ 66218316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) 66318316Swollman ifp->int_state &= ~(IS_CHECKED | IS_DUP); 66418316Swollman 66518316Swollman /* Fetch the interface list, without too many system calls 66618316Swollman * since we do it repeatedly. 66718316Swollman */ 66818316Swollman mib[0] = CTL_NET; 66918316Swollman mib[1] = PF_ROUTE; 67018316Swollman mib[2] = 0; 67118316Swollman mib[3] = AF_INET; 67218316Swollman mib[4] = NET_RT_IFLIST; 67318316Swollman mib[5] = 0; 67418316Swollman for (;;) { 67518316Swollman if ((needed = sysctl_buf_size) != 0) { 67618316Swollman if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 67718316Swollman break; 67818316Swollman if (errno != ENOMEM && errno != EFAULT) 67918316Swollman BADERR(1, "ifinit: get interface table"); 68018316Swollman free(sysctl_buf); 68118316Swollman needed = 0; 68218316Swollman } 68318316Swollman if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 68418316Swollman BADERR(1,"ifinit: route-sysctl-estimate"); 68518316Swollman sysctl_buf = rtmalloc(sysctl_buf_size = needed, "ifinit"); 68618316Swollman } 68718316Swollman 68818316Swollman ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed); 68918316Swollman for (ifam = (struct ifa_msghdr *)sysctl_buf; 69018316Swollman ifam < ifam_lim; 69118316Swollman ifam = ifam2) { 69218316Swollman 69318316Swollman ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); 69418316Swollman 69518316Swollman if (ifam->ifam_type == RTM_IFINFO) { 69619880Swollman struct sockaddr_dl *sdl; 69719880Swollman 69818316Swollman ifm = (struct if_msghdr *)ifam; 69918316Swollman /* make prototype structure for the IP aliases 70018316Swollman */ 70118316Swollman bzero(&ifs0, sizeof(ifs0)); 70218316Swollman ifs0.int_rip_sock = -1; 70318316Swollman ifs0.int_index = ifm->ifm_index; 70418316Swollman ifs0.int_if_flags = ifm->ifm_flags; 70518316Swollman ifs0.int_state = IS_CHECKED; 70620339Swollman ifs0.int_query_time = NEVER; 70718316Swollman ifs0.int_act_time = now.tv_sec; 70818316Swollman ifs0.int_data.ts = now.tv_sec; 70918316Swollman ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; 71018316Swollman ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors; 71118316Swollman ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets; 71218316Swollman ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors; 71318316Swollman#ifdef sgi 71418316Swollman ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops; 71518316Swollman#endif 71618316Swollman sdl = (struct sockaddr_dl *)(ifm + 1); 71718316Swollman sdl->sdl_data[sdl->sdl_nlen] = 0; 71819880Swollman strncpy(ifs0.int_name, sdl->sdl_data, 71919880Swollman MIN(sizeof(ifs0.int_name), sdl->sdl_nlen)); 72018316Swollman continue; 72118316Swollman } 72218316Swollman if (ifam->ifam_type != RTM_NEWADDR) { 72318316Swollman logbad(1,"ifinit: out of sync"); 72418316Swollman continue; 72518316Swollman } 72618316Swollman rt_xaddrs(&info, (struct sockaddr *)(ifam+1), 72718316Swollman (struct sockaddr *)ifam2, 72818316Swollman ifam->ifam_addrs); 72918316Swollman 73019880Swollman /* Prepare for the next address of this interface, which 73119880Swollman * will be an alias. 73219880Swollman * Do not output RIP or Router-Discovery packets via aliases. 73319880Swollman */ 73419880Swollman bcopy(&ifs0, &ifs, sizeof(ifs)); 73519880Swollman ifs0.int_state |= (IS_ALIAS | IS_NO_RIP | IS_NO_RDISC); 73619880Swollman 73718316Swollman if (INFO_IFA(&info) == 0) { 73818316Swollman if (iff_alive(ifs.int_if_flags)) { 73918316Swollman if (!(prev_complaints & COMP_NOADDR)) 74018316Swollman msglog("%s has no address", 74119880Swollman ifs.int_name); 74218316Swollman complaints |= COMP_NOADDR; 74318316Swollman } 74418316Swollman continue; 74518316Swollman } 74618316Swollman if (INFO_IFA(&info)->sa_family != AF_INET) { 74718316Swollman if (iff_alive(ifs.int_if_flags)) { 74818316Swollman if (!(prev_complaints & COMP_NOT_INET)) 74919880Swollman trace_act("%s: not AF_INET", 75019880Swollman ifs.int_name); 75118316Swollman complaints |= COMP_NOT_INET; 75218316Swollman } 75318316Swollman continue; 75418316Swollman } 75518316Swollman 75618316Swollman ifs.int_addr = S_ADDR(INFO_IFA(&info)); 75718316Swollman 75818316Swollman if (ntohl(ifs.int_addr)>>24 == 0 75918316Swollman || ntohl(ifs.int_addr)>>24 == 0xff) { 76018316Swollman if (iff_alive(ifs.int_if_flags)) { 76118316Swollman if (!(prev_complaints & COMP_BADADDR)) 76218316Swollman msglog("%s has a bad address", 76319880Swollman ifs.int_name); 76418316Swollman complaints |= COMP_BADADDR; 76518316Swollman } 76618316Swollman continue; 76718316Swollman } 76818316Swollman 76919880Swollman if (ifs.int_if_flags & IFF_LOOPBACK) { 77019880Swollman ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC; 77118316Swollman ifs.int_dstaddr = ifs.int_addr; 77219880Swollman ifs.int_mask = HOST_MASK; 77319880Swollman ifs.int_ripv1_mask = HOST_MASK; 77419880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 77519880Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 77619880Swollman if (!foundloopback) { 77719880Swollman foundloopback = 1; 77819880Swollman loopaddr = ifs.int_addr; 77918316Swollman } 78018316Swollman 78118316Swollman } else if (ifs.int_if_flags & IFF_POINTOPOINT) { 78218316Swollman if (INFO_BRD(&info) == 0 78318316Swollman || INFO_BRD(&info)->sa_family != AF_INET) { 78418316Swollman if (iff_alive(ifs.int_if_flags)) { 78518316Swollman if (!(prev_complaints & COMP_NODST)) 78618316Swollman msglog("%s has a bad" 78718316Swollman " destination address", 78819880Swollman ifs.int_name); 78918316Swollman complaints |= COMP_NODST; 79018316Swollman } 79118316Swollman continue; 79218316Swollman } 79318316Swollman ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); 79418316Swollman if (ntohl(ifs.int_dstaddr)>>24 == 0 79518316Swollman || ntohl(ifs.int_dstaddr)>>24 == 0xff) { 79618316Swollman if (iff_alive(ifs.int_if_flags)) { 79718316Swollman if (!(prev_complaints & COMP_NODST)) 79818316Swollman msglog("%s has a bad" 79918316Swollman " destination address", 80019880Swollman ifs.int_name); 80118316Swollman complaints |= COMP_NODST; 80218316Swollman } 80318316Swollman continue; 80418316Swollman } 80518316Swollman ifs.int_mask = HOST_MASK; 80618316Swollman ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); 80719880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 80818316Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 80918316Swollman 81019880Swollman } else { 81119880Swollman if (INFO_MASK(&info) == 0) { 81219880Swollman if (iff_alive(ifs.int_if_flags)) { 81319880Swollman if (!(prev_complaints & COMP_NOMASK)) 81419880Swollman msglog("%s has no netmask", 81519880Swollman ifs.int_name); 81619880Swollman complaints |= COMP_NOMASK; 81719880Swollman } 81819880Swollman continue; 81919880Swollman } 82018316Swollman ifs.int_dstaddr = ifs.int_addr; 82119880Swollman ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); 82219880Swollman ifs.int_ripv1_mask = ifs.int_mask; 82319880Swollman ifs.int_std_mask = std_mask(ifs.int_addr); 82419880Swollman ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; 82519880Swollman if (ifs.int_mask != ifs.int_std_mask) 82619880Swollman ifs.int_state |= IS_SUBNET; 82719880Swollman 82819880Swollman if (ifs.int_if_flags & IFF_BROADCAST) { 82919880Swollman if (INFO_BRD(&info) == 0) { 83019880Swollman if (iff_alive(ifs.int_if_flags)) { 83119880Swollman if (!(prev_complaints 83219880Swollman & COMP_NOBADR)) 83319880Swollman msglog("%s has" 83419880Swollman "no broadcast address", 83519880Swollman ifs.int_name); 83619880Swollman complaints |= COMP_NOBADR; 83719880Swollman } 83819880Swollman continue; 83919880Swollman } 84019880Swollman ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); 84118316Swollman } 84218316Swollman } 84318316Swollman ifs.int_std_net = ifs.int_net & ifs.int_std_mask; 84418316Swollman ifs.int_std_addr = htonl(ifs.int_std_net); 84518316Swollman 84618316Swollman /* Use a minimum metric of one. Treat the interface metric 84718316Swollman * (default 0) as an increment to the hop count of one. 84818316Swollman * 84918316Swollman * The metric obtained from the routing socket dump of 85018316Swollman * interface addresses is wrong. It is not set by the 85118316Swollman * SIOCSIFMETRIC ioctl. 85218316Swollman */ 85318316Swollman#ifdef SIOCGIFMETRIC 85419880Swollman strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name)); 85518316Swollman if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) { 85618316Swollman DBGERR(1, "ioctl(SIOCGIFMETRIC)"); 85718316Swollman ifs.int_metric = 0; 85818316Swollman } else { 85918316Swollman ifs.int_metric = ifr.ifr_metric; 86018316Swollman } 86118316Swollman#else 86218316Swollman ifs.int_metric = ifam->ifam_metric; 86318316Swollman#endif 86418316Swollman if (ifs.int_metric > HOPCNT_INFINITY) { 86518316Swollman ifs.int_metric = 0; 86618316Swollman if (!(prev_complaints & COMP_BAD_METRIC) 86718316Swollman && iff_alive(ifs.int_if_flags)) { 86818316Swollman complaints |= COMP_BAD_METRIC; 86918316Swollman msglog("%s has a metric of %d", 87019880Swollman ifs.int_name, ifs.int_metric); 87118316Swollman } 87218316Swollman } 87318316Swollman 87418316Swollman /* See if this is a familiar interface. 87518316Swollman * If so, stop worrying about it if it is the same. 87618316Swollman * Start it over if it now is to somewhere else, as happens 87718316Swollman * frequently with PPP and SLIP. 87818316Swollman */ 87919880Swollman ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS) 88019880Swollman ? ifs.int_addr 88119880Swollman : 0)); 88218316Swollman if (ifp != 0) { 88318316Swollman ifp->int_state |= IS_CHECKED; 88418316Swollman 88518316Swollman if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags) 88618316Swollman & (IFF_BROADCAST 88718316Swollman | IFF_LOOPBACK 88818316Swollman | IFF_POINTOPOINT 88918316Swollman | IFF_MULTICAST)) 89018316Swollman || 0 != ((ifp->int_state ^ ifs.int_state) 89118316Swollman & IS_ALIAS) 89218316Swollman || ifp->int_addr != ifs.int_addr 89318316Swollman || ifp->int_brdaddr != ifs.int_brdaddr 89418316Swollman || ifp->int_dstaddr != ifs.int_dstaddr 89518316Swollman || ifp->int_mask != ifs.int_mask 89618316Swollman || ifp->int_metric != ifs.int_metric) { 89718316Swollman /* Forget old information about 89818316Swollman * a changed interface. 89918316Swollman */ 90019880Swollman trace_act("interface %s has changed", 90118316Swollman ifp->int_name); 90218316Swollman ifdel(ifp); 90318316Swollman ifp = 0; 90418316Swollman } 90518316Swollman } 90618316Swollman 90718316Swollman if (ifp != 0) { 90818316Swollman /* The primary representative of an alias worries 90918316Swollman * about how things are working. 91018316Swollman */ 91118316Swollman if (ifp->int_state & IS_ALIAS) 91218316Swollman continue; 91318316Swollman 91418316Swollman /* note interfaces that have been turned off 91518316Swollman */ 91618316Swollman if (!iff_alive(ifs.int_if_flags)) { 91718316Swollman if (iff_alive(ifp->int_if_flags)) { 91818316Swollman msglog("interface %s to %s turned off", 91918316Swollman ifp->int_name, 92019880Swollman naddr_ntoa(ifp->int_dstaddr)); 92118316Swollman if_bad(ifp); 92218316Swollman ifp->int_if_flags &= ~IFF_UP_RUNNING; 92318316Swollman } 92418316Swollman continue; 92518316Swollman } 92618316Swollman /* or that were off and are now ok */ 92718316Swollman if (!iff_alive(ifp->int_if_flags)) { 92818316Swollman ifp->int_if_flags |= IFF_UP_RUNNING; 92918316Swollman (void)if_ok(ifp, ""); 93018316Swollman } 93118316Swollman 93218316Swollman /* If it has been long enough, 93318316Swollman * see if the interface is broken. 93418316Swollman */ 93518316Swollman if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL) 93618316Swollman continue; 93718316Swollman 93818316Swollman in = ifs.int_data.ipackets - ifp->int_data.ipackets; 93918316Swollman ierr = ifs.int_data.ierrors - ifp->int_data.ierrors; 94018316Swollman out = ifs.int_data.opackets - ifp->int_data.opackets; 94118316Swollman oerr = ifs.int_data.oerrors - ifp->int_data.oerrors; 94218316Swollman#ifdef sgi 94318316Swollman /* Through at least IRIX 6.2, PPP and SLIP 94418316Swollman * count packets dropped by the filters. 94518316Swollman * But FDDI rings stuck non-operational count 94618316Swollman * dropped packets as they wait for improvement. 94718316Swollman */ 94818316Swollman if (!(ifp->int_if_flags & IFF_POINTOPOINT)) 94918316Swollman oerr += (ifs.int_data.odrops 95018316Swollman - ifp->int_data.odrops); 95118316Swollman#endif 95218316Swollman /* If the interface just awoke, restart the counters. 95318316Swollman */ 95418316Swollman if (ifp->int_data.ts == 0) { 95518316Swollman ifp->int_data = ifs.int_data; 95618316Swollman continue; 95718316Swollman } 95818316Swollman ifp->int_data = ifs.int_data; 95918316Swollman 96018316Swollman /* Withhold judgement when the short error 96118316Swollman * counters wrap or the interface is reset. 96218316Swollman */ 96318316Swollman if (ierr < 0 || in < 0 || oerr < 0 || out < 0) { 96418316Swollman LIM_SEC(ifinit_timer, 96518316Swollman now.tv_sec+CHECK_BAD_INTERVAL); 96618316Swollman continue; 96718316Swollman } 96818316Swollman 96918316Swollman /* Withhold judgement when there is no traffic 97018316Swollman */ 97118316Swollman if (in == 0 && out == 0 && ierr == 0 && oerr == 0) 97218316Swollman continue; 97318316Swollman 97418316Swollman /* It is bad if input or output is not working. 97518316Swollman * Require presistent problems before marking it dead. 97618316Swollman */ 97718316Swollman if ((in <= ierr && ierr > 0) 97818316Swollman || (out <= oerr && oerr > 0)) { 97918316Swollman if (!(ifp->int_state & IS_SICK)) { 98018316Swollman trace_act("interface %s to %s" 98118316Swollman " sick: in=%d ierr=%d" 98219880Swollman " out=%d oerr=%d", 98318316Swollman ifp->int_name, 98419880Swollman naddr_ntoa(ifp->int_dstaddr), 98518316Swollman in, ierr, out, oerr); 98618316Swollman if_sick(ifp); 98718316Swollman continue; 98818316Swollman } 98918316Swollman if (!(ifp->int_state & IS_BROKE)) { 99019880Swollman msglog("interface %s to %s broken:" 99118316Swollman " in=%d ierr=%d out=%d oerr=%d", 99218316Swollman ifp->int_name, 99319880Swollman naddr_ntoa(ifp->int_dstaddr), 99418316Swollman in, ierr, out, oerr); 99518316Swollman if_bad(ifp); 99618316Swollman } 99718316Swollman continue; 99818316Swollman } 99918316Swollman 100018316Swollman /* otherwise, it is active and healthy 100118316Swollman */ 100218316Swollman ifp->int_act_time = now.tv_sec; 100318316Swollman (void)if_ok(ifp, ""); 100418316Swollman continue; 100518316Swollman } 100618316Swollman 100718316Swollman /* This is a new interface. 100818316Swollman * If it is dead, forget it. 100918316Swollman */ 101018316Swollman if (!iff_alive(ifs.int_if_flags)) 101118316Swollman continue; 101218316Swollman 101319880Swollman /* If it duplicates an existing interface, 101419880Swollman * complain about it, mark the other one 101519880Swollman * duplicated, and forget this one. 101618316Swollman */ 101719880Swollman ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, 101819880Swollman ifs.int_if_flags); 101919880Swollman if (ifp != 0) { 102018316Swollman if (!(prev_complaints & COMP_DUP)) { 102118316Swollman complaints |= COMP_DUP; 102220339Swollman msglog("%s (%s%s%s) is duplicated by" 102320339Swollman " %s (%s%s%s)", 102420339Swollman ifs.int_name, 102520339Swollman addrname(ifs.int_addr,ifs.int_mask,1), 102620339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 102720339Swollman ? "-->" : ""), 102820339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 102920339Swollman ? naddr_ntoa(ifs.int_dstaddr) : ""), 103020339Swollman ifp->int_name, 103120339Swollman addrname(ifp->int_addr,ifp->int_mask,1), 103220339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 103320339Swollman ? "-->" : ""), 103420339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 103520339Swollman ? naddr_ntoa(ifp->int_dstaddr) : "")); 103618316Swollman } 103718316Swollman ifp->int_state |= IS_DUP; 103819880Swollman continue; 103918316Swollman } 104018316Swollman 104119880Swollman if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST)) 104219880Swollman && !(ifs.int_state & IS_PASSIVE)) { 104319880Swollman trace_act("%s is neither broadcast, point-to-point," 104419880Swollman " nor loopback", 104519880Swollman ifs.int_name); 104619880Swollman if (!(ifs.int_state & IFF_MULTICAST)) 104719880Swollman ifs.int_state |= IS_NO_RDISC; 104819880Swollman } 104918316Swollman 105019880Swollman 105119880Swollman /* It is new and ok. Add it to the list of interfaces 105218316Swollman */ 105318316Swollman ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit"); 105418316Swollman bcopy(&ifs, ifp, sizeof(*ifp)); 105519880Swollman get_parms(ifp); 105619880Swollman if_link(ifp); 105718316Swollman trace_if("Add", ifp); 105818316Swollman 105918316Swollman /* Notice likely bad netmask. 106018316Swollman */ 106118316Swollman if (!(prev_complaints & COMP_NETMASK) 106219880Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 106319880Swollman && ifp->int_addr != RIP_DEFAULT) { 106418316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 106518316Swollman if (ifp1->int_mask == ifp->int_mask) 106618316Swollman continue; 106718316Swollman if (ifp1->int_if_flags & IFF_POINTOPOINT) 106818316Swollman continue; 106919880Swollman if (ifp1->int_dstaddr == RIP_DEFAULT) 107019880Swollman continue; 107119880Swollman if (on_net(ifp->int_dstaddr, 107218316Swollman ifp1->int_net, ifp1->int_mask) 107319880Swollman || on_net(ifp1->int_dstaddr, 107418316Swollman ifp->int_net, ifp->int_mask)) { 107518316Swollman msglog("possible netmask problem" 107619880Swollman " between %s:%s and %s:%s", 107718316Swollman ifp->int_name, 107818316Swollman addrname(htonl(ifp->int_net), 107918316Swollman ifp->int_mask, 1), 108018316Swollman ifp1->int_name, 108118316Swollman addrname(htonl(ifp1->int_net), 108218316Swollman ifp1->int_mask, 1)); 108318316Swollman complaints |= COMP_NETMASK; 108418316Swollman } 108518316Swollman } 108618316Swollman } 108718316Swollman 108818316Swollman if (!(ifp->int_state & IS_ALIAS)) { 108919880Swollman /* Count the # of directly connected networks. 109019880Swollman */ 109118316Swollman if (!(ifp->int_if_flags & IFF_LOOPBACK)) 109218316Swollman tot_interfaces++; 109318316Swollman if (!IS_RIP_OFF(ifp->int_state)) 109418316Swollman rip_interfaces++; 109519880Swollman 109619880Swollman /* turn on router discovery and RIP If needed */ 109719880Swollman if_ok_rdisc(ifp); 109819880Swollman rip_on(ifp); 109918316Swollman } 110018316Swollman } 110118316Swollman 110219880Swollman /* If we are multi-homed and have at least two interfaces 110318316Swollman * listening to RIP, then output by default. 110418316Swollman */ 110518316Swollman if (!supplier_set && rip_interfaces > 1) 110618316Swollman set_supplier(); 110718316Swollman 110818316Swollman /* If we are multi-homed, optionally advertise a route to 110918316Swollman * our main address. 111018316Swollman */ 111118316Swollman if (advertise_mhome 111218316Swollman || (tot_interfaces > 1 111318316Swollman && mhome 111418316Swollman && (ifp = ifwithaddr(myaddr, 0, 0)) != 0 111518316Swollman && foundloopback)) { 111618316Swollman advertise_mhome = 1; 111718316Swollman rt = rtget(myaddr, HOST_MASK); 111818316Swollman if (rt != 0) { 111918316Swollman if (rt->rt_ifp != ifp 112018316Swollman || rt->rt_router != loopaddr) { 112118316Swollman rtdelete(rt); 112218316Swollman rt = 0; 112318316Swollman } else { 112418316Swollman rtchange(rt, rt->rt_state | RS_MHOME, 112518316Swollman loopaddr, loopaddr, 112618316Swollman 0, 0, ifp, rt->rt_time, 0); 112718316Swollman } 112818316Swollman } 112918316Swollman if (rt == 0) 113018316Swollman rtadd(myaddr, HOST_MASK, loopaddr, loopaddr, 113118316Swollman 0, 0, RS_MHOME, ifp); 113218316Swollman } 113318316Swollman 113418316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp1) { 113518316Swollman ifp1 = ifp->int_next; /* because we may delete it */ 113618316Swollman 113718316Swollman /* Forget any interfaces that have disappeared. 113818316Swollman */ 113918316Swollman if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { 114019880Swollman trace_act("interface %s has disappeared", 114118316Swollman ifp->int_name); 114218316Swollman ifdel(ifp); 114318316Swollman continue; 114418316Swollman } 114518316Swollman 114618316Swollman if ((ifp->int_state & IS_BROKE) 114718316Swollman && !(ifp->int_state & IS_PASSIVE)) 114818316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 114918316Swollman 115018316Swollman /* If we ever have a RIPv1 interface, assume we always will. 115118316Swollman * It might come back if it ever goes away. 115218316Swollman */ 115318316Swollman if (!(ifp->int_state & IS_NO_RIPV1_OUT) && supplier) 115418316Swollman have_ripv1_out = 1; 115518316Swollman if (!(ifp->int_state & IS_NO_RIPV1_IN)) 115618316Swollman have_ripv1_in = 1; 115718316Swollman } 115818316Swollman 115918316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 116018316Swollman /* Ensure there is always a network route for interfaces, 116118316Swollman * after any dead interfaces have been deleted, which 116218316Swollman * might affect routes for point-to-point links. 116318316Swollman */ 116419880Swollman if (!addrouteforif(ifp)) 116519880Swollman continue; 116618316Swollman 116718316Swollman /* Add routes to the local end of point-to-point interfaces 116818316Swollman * using loopback. 116918316Swollman */ 117018316Swollman if ((ifp->int_if_flags & IFF_POINTOPOINT) 117118316Swollman && !(ifp->int_state & IS_REMOTE) 117218316Swollman && foundloopback) { 117318316Swollman /* Delete any routes to the network address through 117418316Swollman * foreign routers. Remove even static routes. 117518316Swollman */ 117618316Swollman del_static(ifp->int_addr, HOST_MASK, 0); 117718316Swollman rt = rtget(ifp->int_addr, HOST_MASK); 117818316Swollman if (rt != 0 && rt->rt_router != loopaddr) { 117918316Swollman rtdelete(rt); 118018316Swollman rt = 0; 118118316Swollman } 118218316Swollman if (rt != 0) { 118318316Swollman if (!(rt->rt_state & RS_LOCAL) 118418316Swollman || rt->rt_metric > ifp->int_metric) { 118518316Swollman ifp1 = ifp; 118618316Swollman } else { 118718316Swollman ifp1 = rt->rt_ifp; 118818316Swollman } 118918316Swollman rtchange(rt,((rt->rt_state & ~RS_NET_SYN) 119018316Swollman | (RS_IF|RS_LOCAL)), 119118316Swollman loopaddr, loopaddr, 119218316Swollman 0, 0, ifp1, rt->rt_time, 0); 119318316Swollman } else { 119418316Swollman rtadd(ifp->int_addr, HOST_MASK, 119518316Swollman loopaddr, loopaddr, 119618316Swollman 0, 0, (RS_IF | RS_LOCAL), ifp); 119718316Swollman } 119818316Swollman } 119918316Swollman } 120018316Swollman 120118316Swollman /* add the authority routes */ 120218316Swollman for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) { 120318316Swollman rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); 120418316Swollman if (rt != 0 120518316Swollman && !(rt->rt_state & RS_NO_NET_SYN) 120618316Swollman && !(rt->rt_state & RS_NET_INT)) { 120718316Swollman rtdelete(rt); 120818316Swollman rt = 0; 120918316Swollman } 121018316Swollman if (rt == 0) 121118316Swollman rtadd(intnetp->intnet_addr, intnetp->intnet_mask, 121218316Swollman loopaddr, loopaddr, intnetp->intnet_metric-1, 121318316Swollman 0, RS_NET_SYN | RS_NET_INT, 0); 121418316Swollman } 121518316Swollman 121618316Swollman prev_complaints = complaints; 121718316Swollman} 121818316Swollman 121918316Swollman 122018316Swollmanstatic void 122118316Swollmancheck_net_syn(struct interface *ifp) 122218316Swollman{ 122318316Swollman struct rt_entry *rt; 122418316Swollman 122518316Swollman 122618316Swollman /* Turn on the need to automatically synthesize a network route 122718316Swollman * for this interface only if we are running RIPv1 on some other 122818316Swollman * interface that is on a different class-A,B,or C network. 122918316Swollman */ 123018316Swollman if (have_ripv1_out || have_ripv1_in) { 123118316Swollman ifp->int_state |= IS_NEED_NET_SYN; 123218316Swollman rt = rtget(ifp->int_std_addr, ifp->int_std_mask); 123318316Swollman if (rt != 0 123418316Swollman && 0 == (rt->rt_state & RS_NO_NET_SYN) 123518316Swollman && (!(rt->rt_state & RS_NET_SYN) 123618316Swollman || rt->rt_metric > ifp->int_metric)) { 123718316Swollman rtdelete(rt); 123818316Swollman rt = 0; 123918316Swollman } 124018316Swollman if (rt == 0) 124118316Swollman rtadd(ifp->int_std_addr, ifp->int_std_mask, 124218316Swollman ifp->int_addr, ifp->int_addr, 124318316Swollman ifp->int_metric, 0, RS_NET_SYN, ifp); 124418316Swollman 124518316Swollman } else { 124618316Swollman ifp->int_state &= ~IS_NEED_NET_SYN; 124718316Swollman 124818316Swollman rt = rtget(ifp->int_std_addr, 124918316Swollman ifp->int_std_mask); 125018316Swollman if (rt != 0 125118316Swollman && (rt->rt_state & RS_NET_SYN) 125218316Swollman && rt->rt_ifp == ifp) 125318316Swollman rtbad_sub(rt); 125418316Swollman } 125518316Swollman} 125618316Swollman 125718316Swollman 125818316Swollman/* Add route for interface if not currently installed. 125918316Swollman * Create route to other end if a point-to-point link, 126018316Swollman * otherwise a route to this (sub)network. 126118316Swollman */ 126219880Swollmanint /* 0=bad interface */ 126318316Swollmanaddrouteforif(struct interface *ifp) 126418316Swollman{ 126518316Swollman struct rt_entry *rt; 126618316Swollman naddr dst, gate; 126718316Swollman 126818316Swollman 126918316Swollman /* skip sick interfaces 127018316Swollman */ 127118316Swollman if (ifp->int_state & IS_BROKE) 127219880Swollman return 0; 127318316Swollman 127418316Swollman /* If the interface on a subnet, then install a RIPv1 route to 127518316Swollman * the network as well (unless it is sick). 127618316Swollman */ 127718316Swollman if (ifp->int_state & IS_SUBNET) 127818316Swollman check_net_syn(ifp); 127918316Swollman 128019880Swollman gate = ifp->int_addr; 128119880Swollman dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) 128219880Swollman ? ifp->int_dstaddr 128319880Swollman : htonl(ifp->int_net)); 128418316Swollman 128519880Swollman /* If we are going to send packets to the gateway, 128619880Swollman * it must be reachable using our physical interfaces 128719880Swollman */ 128819880Swollman if ((ifp->int_state & IS_REMOTE) 128920339Swollman && !(ifp->int_state & IS_EXTERNAL) 129019880Swollman && !check_remote(ifp)) 129119880Swollman return 0; 129218316Swollman 129318316Swollman /* We are finished if the correct main interface route exists. 129418316Swollman * The right route must be for the right interface, not synthesized 129518316Swollman * from a subnet, be a "gateway" or not as appropriate, and so forth. 129618316Swollman */ 129718316Swollman del_static(dst, ifp->int_mask, 0); 129818316Swollman rt = rtget(dst, ifp->int_mask); 129918316Swollman if (rt != 0) { 130018316Swollman if ((rt->rt_ifp != ifp 130118316Swollman || rt->rt_router != ifp->int_addr) 130218316Swollman && (!(ifp->int_state & IS_DUP) 130318316Swollman || rt->rt_ifp == 0 130418316Swollman || (rt->rt_ifp->int_state & IS_BROKE))) { 130518316Swollman rtdelete(rt); 130618316Swollman rt = 0; 130718316Swollman } else { 130818316Swollman rtchange(rt, ((rt->rt_state | RS_IF) 130918316Swollman & ~(RS_NET_SYN | RS_LOCAL)), 131018316Swollman ifp->int_addr, ifp->int_addr, 131118316Swollman ifp->int_metric, 0, ifp, now.tv_sec, 0); 131218316Swollman } 131318316Swollman } 131418316Swollman if (rt == 0) { 131518316Swollman if (ifp->int_transitions++ > 0) 131619880Swollman trace_act("re-install interface %s", 131718316Swollman ifp->int_name); 131818316Swollman 131918316Swollman rtadd(dst, ifp->int_mask, gate, gate, 132018316Swollman ifp->int_metric, 0, RS_IF, ifp); 132118316Swollman } 132219880Swollman 132319880Swollman return 1; 132418316Swollman} 1325