if.c revision 90868
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 1446303Smarkm * must display the following acknowledgment: 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. 3246303Smarkm * 3350476Speter * $FreeBSD: head/sbin/routed/if.c 90868 2002-02-18 20:35:27Z mike $ 3418316Swollman */ 3518316Swollman 3618316Swollman#include "defs.h" 3718316Swollman#include "pathnames.h" 3818316Swollman 3946303Smarkm#if !defined(sgi) && !defined(__NetBSD__) 4046303Smarkmstatic char sccsid[] __attribute__((unused)) = "@(#)if.c 8.1 (Berkeley) 6/5/93"; 4146303Smarkm#elif defined(__NetBSD__) 4246303Smarkm#include <sys/cdefs.h> 4346303Smarkm__RCSID("$NetBSD$"); 4446303Smarkm#endif 4550969Speter#ident "$FreeBSD: head/sbin/routed/if.c 90868 2002-02-18 20:35:27Z mike $" 4646303Smarkm 4719880Swollmanstruct interface *ifnet; /* all interfaces */ 4819880Swollman 4919880Swollman/* hash table for all interfaces, big enough to tolerate ridiculous 5019880Swollman * numbers of IP aliases. Crazy numbers of aliases such as 7000 5119880Swollman * still will not do well, but not just in looking up interfaces 5219880Swollman * by name or address. 5319880Swollman */ 5419880Swollman#define AHASH_LEN 211 /* must be prime */ 5521378Swollman#define AHASH(a) &ahash_tbl[(a)%AHASH_LEN] 5621378Swollmanstruct interface *ahash_tbl[AHASH_LEN]; 5719880Swollman 5819880Swollman#define BHASH_LEN 211 /* must be prime */ 5921378Swollman#define BHASH(a) &bhash_tbl[(a)%BHASH_LEN] 6021378Swollmanstruct interface *bhash_tbl[BHASH_LEN]; 6119880Swollman 6219880Swollmanstruct interface *remote_if; /* remote interfaces */ 6319880Swollman 6419880Swollman/* hash for physical interface names. 6519880Swollman * Assume there are never more 100 or 200 real interfaces, and that 6620606Swollman * aliases are put on the end of the hash chains. 6719880Swollman */ 6819880Swollman#define NHASH_LEN 97 6921378Swollmanstruct interface *nhash_tbl[NHASH_LEN]; 7019880Swollman 7118316Swollmanint tot_interfaces; /* # of remote and local interfaces */ 7218316Swollmanint rip_interfaces; /* # of interfaces doing RIP */ 7318316Swollmanint foundloopback; /* valid flag for loopaddr */ 7418316Swollmannaddr loopaddr; /* our address on loopback */ 7546303Smarkmstruct rt_spare loop_rts; 7618316Swollman 7718316Swollmanstruct timeval ifinit_timer; 7820606Swollmanstatic struct timeval last_ifinit; 7946303Smarkm#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec \ 8046303Smarkm && last_ifinit.tv_usec == now.tv_usec \ 8146303Smarkm && timercmp(&ifinit_timer, &now, >)) 8218316Swollman 8318316Swollmanint have_ripv1_out; /* have a RIPv1 interface */ 8418316Swollmanint have_ripv1_in; 8518316Swollman 8618316Swollman 8721378Swollmanstatic struct interface** 8846303Smarkmnhash(char *p) 8921378Swollman{ 9046303Smarkm u_int i; 9121378Swollman 9221378Swollman for (i = 0; *p != '\0'; p++) { 9321378Swollman i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1); 9421378Swollman i ^= *p; 9521378Swollman } 9621378Swollman return &nhash_tbl[i % NHASH_LEN]; 9721378Swollman} 9821378Swollman 9921378Swollman 10020606Swollman/* Link a new interface into the lists and hash tables. 10120606Swollman */ 10219880Swollmanvoid 10319880Swollmanif_link(struct interface *ifp) 10419880Swollman{ 10519880Swollman struct interface **hifp; 10619880Swollman 10719880Swollman ifp->int_prev = &ifnet; 10819880Swollman ifp->int_next = ifnet; 10919880Swollman if (ifnet != 0) 11019880Swollman ifnet->int_prev = &ifp->int_next; 11119880Swollman ifnet = ifp; 11219880Swollman 11319880Swollman hifp = AHASH(ifp->int_addr); 11419880Swollman ifp->int_ahash_prev = hifp; 11519880Swollman if ((ifp->int_ahash = *hifp) != 0) 11619880Swollman (*hifp)->int_ahash_prev = &ifp->int_ahash; 11719880Swollman *hifp = ifp; 11819880Swollman 11919880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 12019880Swollman hifp = BHASH(ifp->int_brdaddr); 12119880Swollman ifp->int_bhash_prev = hifp; 12219880Swollman if ((ifp->int_bhash = *hifp) != 0) 12319880Swollman (*hifp)->int_bhash_prev = &ifp->int_bhash; 12419880Swollman *hifp = ifp; 12519880Swollman } 12619880Swollman 12719880Swollman if (ifp->int_state & IS_REMOTE) { 12819880Swollman ifp->int_rlink_prev = &remote_if; 12919880Swollman ifp->int_rlink = remote_if; 13019880Swollman if (remote_if != 0) 13119880Swollman remote_if->int_rlink_prev = &ifp->int_rlink; 13219880Swollman remote_if = ifp; 13319880Swollman } 13419880Swollman 13521378Swollman hifp = nhash(ifp->int_name); 13619880Swollman if (ifp->int_state & IS_ALIAS) { 13720606Swollman /* put aliases on the end of the hash chain */ 13819880Swollman while (*hifp != 0) 13919880Swollman hifp = &(*hifp)->int_nhash; 14019880Swollman } 14119880Swollman ifp->int_nhash_prev = hifp; 14219880Swollman if ((ifp->int_nhash = *hifp) != 0) 14319880Swollman (*hifp)->int_nhash_prev = &ifp->int_nhash; 14419880Swollman *hifp = ifp; 14519880Swollman} 14619880Swollman 14719880Swollman 14818316Swollman/* Find the interface with an address 14918316Swollman */ 15018316Swollmanstruct interface * 15118316Swollmanifwithaddr(naddr addr, 15218316Swollman int bcast, /* notice IFF_BROADCAST address */ 15318316Swollman int remote) /* include IS_REMOTE interfaces */ 15418316Swollman{ 15518316Swollman struct interface *ifp, *possible = 0; 15618316Swollman 15719880Swollman remote = (remote == 0) ? IS_REMOTE : 0; 15818316Swollman 15919880Swollman for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) { 16019880Swollman if (ifp->int_addr != 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; 16719880Swollman } 16818316Swollman 16919880Swollman if (possible || !bcast) 17019880Swollman return possible; 17119880Swollman 17219880Swollman for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) { 17319880Swollman if (ifp->int_brdaddr != addr) 17419880Swollman continue; 17519880Swollman if ((ifp->int_state & remote) != 0) 17619880Swollman continue; 17719880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 17819880Swollman return ifp; 17919880Swollman possible = ifp; 18018316Swollman } 18118316Swollman 18218316Swollman return possible; 18318316Swollman} 18418316Swollman 18518316Swollman 18618316Swollman/* find the interface with a name 18718316Swollman */ 18818316Swollmanstruct interface * 18918316Swollmanifwithname(char *name, /* "ec0" or whatever */ 19018316Swollman naddr addr) /* 0 or network address */ 19118316Swollman{ 19218316Swollman struct interface *ifp; 19318316Swollman 19420606Swollman for (;;) { 19521378Swollman for (ifp = *nhash(name); ifp != 0; ifp = ifp->int_nhash) { 19620606Swollman /* If the network address is not specified, 19720606Swollman * ignore any alias interfaces. Otherwise, look 19820606Swollman * for the interface with the target name and address. 19920606Swollman */ 20020606Swollman if (!strcmp(ifp->int_name, name) 20120606Swollman && ((addr == 0 && !(ifp->int_state & IS_ALIAS)) 20220606Swollman || (ifp->int_addr == addr))) 20320606Swollman return ifp; 20420606Swollman } 20520606Swollman 20620606Swollman /* If there is no known interface, maybe there is a 20720606Swollman * new interface. So just once look for new interfaces. 20819880Swollman */ 20946303Smarkm if (IF_RESCAN_DELAY()) 21020606Swollman return 0; 21120606Swollman ifinit(); 21218316Swollman } 21318316Swollman} 21418316Swollman 21518316Swollman 21618316Swollmanstruct interface * 21746303Smarkmifwithindex(u_short index, 21846303Smarkm int rescan_ok) 21918316Swollman{ 22018316Swollman struct interface *ifp; 22118316Swollman 22246303Smarkm for (;;) { 22346303Smarkm for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 22446303Smarkm if (ifp->int_index == index) 22546303Smarkm return ifp; 22646303Smarkm } 22718316Swollman 22846303Smarkm /* If there is no known interface, maybe there is a 22946303Smarkm * new interface. So just once look for new interfaces. 23046303Smarkm */ 23146303Smarkm if (!rescan_ok 23246303Smarkm || IF_RESCAN_DELAY()) 23346303Smarkm return 0; 23446303Smarkm ifinit(); 23518316Swollman } 23618316Swollman} 23718316Swollman 23818316Swollman 23918316Swollman/* Find an interface from which the specified address 24018316Swollman * should have come from. Used for figuring out which 24120339Swollman * interface a packet came in on. 24218316Swollman */ 24318316Swollmanstruct interface * 24418316Swollmaniflookup(naddr addr) 24518316Swollman{ 24618316Swollman struct interface *ifp, *maybe; 24718316Swollman 24818316Swollman maybe = 0; 24920339Swollman for (;;) { 25020339Swollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 25120339Swollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 25220339Swollman /* finished with a match */ 25320339Swollman if (ifp->int_dstaddr == addr) 25420339Swollman return ifp; 25518316Swollman 25620339Swollman } else { 25720339Swollman /* finished with an exact match */ 25820339Swollman if (ifp->int_addr == addr) 25920339Swollman return ifp; 26018316Swollman 26120339Swollman /* Look for the longest approximate match. 26220339Swollman */ 26320339Swollman if (on_net(addr, ifp->int_net, ifp->int_mask) 26420339Swollman && (maybe == 0 26520339Swollman || ifp->int_mask > maybe->int_mask)) 26620339Swollman maybe = ifp; 26720339Swollman } 26818316Swollman } 26920339Swollman 27020339Swollman if (maybe != 0 27146303Smarkm || IF_RESCAN_DELAY()) 27220339Swollman return maybe; 27320339Swollman 27420339Swollman /* If there is no known interface, maybe there is a 27520339Swollman * new interface. So just once look for new interfaces. 27620339Swollman */ 27720339Swollman ifinit(); 27818316Swollman } 27918316Swollman} 28018316Swollman 28118316Swollman 28218316Swollman/* Return the classical netmask for an IP address. 28318316Swollman */ 28420339Swollmannaddr /* host byte order */ 28520339Swollmanstd_mask(naddr addr) /* network byte order */ 28618316Swollman{ 28790868Smike addr = ntohl(addr); /* was a host, not a network */ 28818316Swollman 28918316Swollman if (addr == 0) /* default route has mask 0 */ 29018316Swollman return 0; 29118316Swollman if (IN_CLASSA(addr)) 29218316Swollman return IN_CLASSA_NET; 29318316Swollman if (IN_CLASSB(addr)) 29418316Swollman return IN_CLASSB_NET; 29518316Swollman return IN_CLASSC_NET; 29618316Swollman} 29718316Swollman 29818316Swollman 29918316Swollman/* Find the netmask that would be inferred by RIPv1 listeners 30018316Swollman * on the given interface for a given network. 30118316Swollman * If no interface is specified, look for the best fitting interface. 30218316Swollman */ 30318316Swollmannaddr 30418316Swollmanripv1_mask_net(naddr addr, /* in network byte order */ 30518316Swollman struct interface *ifp) /* as seen on this interface */ 30618316Swollman{ 30746303Smarkm struct r1net *r1p; 30818316Swollman naddr mask = 0; 30918316Swollman 31018316Swollman if (addr == 0) /* default always has 0 mask */ 31118316Swollman return mask; 31218316Swollman 31346303Smarkm if (ifp != 0 && ifp->int_ripv1_mask != HOST_MASK) { 31418316Swollman /* If the target network is that of the associated interface 31518316Swollman * on which it arrived, then use the netmask of the interface. 31618316Swollman */ 31718316Swollman if (on_net(addr, ifp->int_net, ifp->int_std_mask)) 31818316Swollman mask = ifp->int_ripv1_mask; 31918316Swollman 32018316Swollman } else { 32118316Swollman /* Examine all interfaces, and if it the target seems 32218316Swollman * to have the same network number of an interface, use the 32318316Swollman * netmask of that interface. If there is more than one 32418316Swollman * such interface, prefer the interface with the longest 32518316Swollman * match. 32618316Swollman */ 32718316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 32818316Swollman if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) 32946303Smarkm && ifp->int_ripv1_mask > mask 33046303Smarkm && ifp->int_ripv1_mask != HOST_MASK) 33118316Swollman mask = ifp->int_ripv1_mask; 33218316Swollman } 33346303Smarkm 33418316Swollman } 33518316Swollman 33646303Smarkm /* check special definitions */ 33746303Smarkm if (mask == 0) { 33846303Smarkm for (r1p = r1nets; r1p != 0; r1p = r1p->r1net_next) { 33946303Smarkm if (on_net(addr, r1p->r1net_net, r1p->r1net_match) 34046303Smarkm && r1p->r1net_mask > mask) 34146303Smarkm mask = r1p->r1net_mask; 34246303Smarkm } 34318316Swollman 34446303Smarkm /* Otherwise, make the classic A/B/C guess. 34546303Smarkm */ 34646303Smarkm if (mask == 0) 34746303Smarkm mask = std_mask(addr); 34846303Smarkm } 34946303Smarkm 35018316Swollman return mask; 35118316Swollman} 35218316Swollman 35318316Swollman 35418316Swollmannaddr 35518316Swollmanripv1_mask_host(naddr addr, /* in network byte order */ 35618316Swollman struct interface *ifp) /* as seen on this interface */ 35718316Swollman{ 35818316Swollman naddr mask = ripv1_mask_net(addr, ifp); 35918316Swollman 36018316Swollman 36118316Swollman /* If the computed netmask does not mask the address, 36218316Swollman * then assume it is a host address 36318316Swollman */ 36418316Swollman if ((ntohl(addr) & ~mask) != 0) 36518316Swollman mask = HOST_MASK; 36618316Swollman return mask; 36718316Swollman} 36818316Swollman 36918316Swollman 37018316Swollman/* See if a IP address looks reasonable as a destination 37118316Swollman */ 37218316Swollmanint /* 0=bad */ 37318316Swollmancheck_dst(naddr addr) 37418316Swollman{ 37590868Smike addr = ntohl(addr); 37618316Swollman 37718316Swollman if (IN_CLASSA(addr)) { 37818316Swollman if (addr == 0) 37918316Swollman return 1; /* default */ 38018316Swollman 38118316Swollman addr >>= IN_CLASSA_NSHIFT; 38218316Swollman return (addr != 0 && addr != IN_LOOPBACKNET); 38318316Swollman } 38418316Swollman 38518316Swollman return (IN_CLASSB(addr) || IN_CLASSC(addr)); 38618316Swollman} 38718316Swollman 38818316Swollman 38919880Swollman/* See a new interface duplicates an existing interface. 39019880Swollman */ 39119880Swollmanstruct interface * 39220339Swollmancheck_dup(naddr addr, /* IP address, so network byte order */ 39320339Swollman naddr dstaddr, /* ditto */ 39420339Swollman naddr mask, /* mask, so host byte order */ 39519880Swollman int if_flags) 39619880Swollman{ 39719880Swollman struct interface *ifp; 39819880Swollman 39919880Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 40019880Swollman if (ifp->int_mask != mask) 40119880Swollman continue; 40219880Swollman 40346303Smarkm if (!iff_up(ifp->int_if_flags)) 40419880Swollman continue; 40519880Swollman 40646303Smarkm /* The local address can only be shared with a point-to-point 40746303Smarkm * link. 40819880Swollman */ 40919880Swollman if (ifp->int_addr == addr 41019880Swollman && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) 41119880Swollman return ifp; 41219880Swollman 41319880Swollman if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask)) 41419880Swollman return ifp; 41519880Swollman } 41619880Swollman return 0; 41719880Swollman} 41819880Swollman 41919880Swollman 42019880Swollman/* See that a remote gateway is reachable. 42119880Swollman * Note that the answer can change as real interfaces come and go. 42219880Swollman */ 42319880Swollmanint /* 0=bad */ 42419880Swollmancheck_remote(struct interface *ifp) 42519880Swollman{ 42619880Swollman struct rt_entry *rt; 42719880Swollman 42819880Swollman /* do not worry about other kinds */ 42919880Swollman if (!(ifp->int_state & IS_REMOTE)) 43019880Swollman return 1; 43119880Swollman 43219880Swollman rt = rtfind(ifp->int_addr); 43319880Swollman if (rt != 0 43419880Swollman && rt->rt_ifp != 0 43519880Swollman &&on_net(ifp->int_addr, 43619880Swollman rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) 43719880Swollman return 1; 43819880Swollman 43919880Swollman /* the gateway cannot be reached directly from one of our 44019880Swollman * interfaces 44119880Swollman */ 44219880Swollman if (!(ifp->int_state & IS_BROKE)) { 44319880Swollman msglog("unreachable gateway %s in "_PATH_GATEWAYS, 44419880Swollman naddr_ntoa(ifp->int_addr)); 44519880Swollman if_bad(ifp); 44619880Swollman } 44719880Swollman return 0; 44819880Swollman} 44919880Swollman 45019880Swollman 45118316Swollman/* Delete an interface. 45218316Swollman */ 45318316Swollmanstatic void 45418316Swollmanifdel(struct interface *ifp) 45518316Swollman{ 45618316Swollman struct ip_mreq m; 45718316Swollman struct interface *ifp1; 45818316Swollman 45918316Swollman 46018316Swollman trace_if("Del", ifp); 46118316Swollman 46218316Swollman ifp->int_state |= IS_BROKE; 46318316Swollman 46418316Swollman /* unlink the interface 46518316Swollman */ 46619880Swollman *ifp->int_prev = ifp->int_next; 46718316Swollman if (ifp->int_next != 0) 46818316Swollman ifp->int_next->int_prev = ifp->int_prev; 46919880Swollman *ifp->int_ahash_prev = ifp->int_ahash; 47019880Swollman if (ifp->int_ahash != 0) 47119880Swollman ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev; 47221378Swollman *ifp->int_nhash_prev = ifp->int_nhash; 47321378Swollman if (ifp->int_nhash != 0) 47421378Swollman ifp->int_nhash->int_nhash_prev = ifp->int_nhash_prev; 47519880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 47619880Swollman *ifp->int_bhash_prev = ifp->int_bhash; 47719880Swollman if (ifp->int_bhash != 0) 47819880Swollman ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev; 47919880Swollman } 48019880Swollman if (ifp->int_state & IS_REMOTE) { 48119880Swollman *ifp->int_rlink_prev = ifp->int_rlink; 48219880Swollman if (ifp->int_rlink != 0) 48319880Swollman ifp->int_rlink->int_rlink_prev = ifp->int_rlink_prev; 48419880Swollman } 48518316Swollman 48618316Swollman if (!(ifp->int_state & IS_ALIAS)) { 48719880Swollman /* delete aliases when the main interface dies 48818316Swollman */ 48918316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 49018316Swollman if (ifp1 != ifp 49118316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 49218316Swollman ifdel(ifp1); 49318316Swollman } 49418316Swollman 49518316Swollman if ((ifp->int_if_flags & IFF_MULTICAST) 49618316Swollman#ifdef MCAST_PPP_BUG 49718316Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 49818316Swollman#endif 49918316Swollman && rip_sock >= 0) { 50018316Swollman m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 50118316Swollman m.imr_interface.s_addr = ((ifp->int_if_flags 50218316Swollman & IFF_POINTOPOINT) 50318316Swollman ? ifp->int_dstaddr 50418316Swollman : ifp->int_addr); 50518316Swollman if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP, 50618316Swollman &m, sizeof(m)) < 0 50718316Swollman && errno != EADDRNOTAVAIL 50818316Swollman && !TRACEACTIONS) 50918316Swollman LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)"); 51019880Swollman if (rip_sock_mcast == ifp) 51119880Swollman rip_sock_mcast = 0; 51218316Swollman } 51318316Swollman if (ifp->int_rip_sock >= 0) { 51418316Swollman (void)close(ifp->int_rip_sock); 51518316Swollman ifp->int_rip_sock = -1; 51618316Swollman fix_select(); 51718316Swollman } 51818316Swollman 51918316Swollman tot_interfaces--; 52018316Swollman if (!IS_RIP_OFF(ifp->int_state)) 52118316Swollman rip_interfaces--; 52218316Swollman 52318316Swollman /* Zap all routes associated with this interface. 52446303Smarkm * Assume routes just using gateways beyond this interface 52546303Smarkm * will timeout naturally, and have probably already died. 52618316Swollman */ 52718316Swollman (void)rn_walktree(rhead, walk_bad, 0); 52818316Swollman 52918316Swollman set_rdisc_mg(ifp, 0); 53018316Swollman if_bad_rdisc(ifp); 53118316Swollman } 53218316Swollman 53318316Swollman free(ifp); 53418316Swollman} 53518316Swollman 53618316Swollman 53718316Swollman/* Mark an interface ill. 53818316Swollman */ 53918316Swollmanvoid 54018316Swollmanif_sick(struct interface *ifp) 54118316Swollman{ 54218316Swollman if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) { 54318316Swollman ifp->int_state |= IS_SICK; 54419880Swollman ifp->int_act_time = NEVER; 54518316Swollman trace_if("Chg", ifp); 54618316Swollman 54718316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 54818316Swollman } 54918316Swollman} 55018316Swollman 55118316Swollman 55218316Swollman/* Mark an interface dead. 55318316Swollman */ 55418316Swollmanvoid 55518316Swollmanif_bad(struct interface *ifp) 55618316Swollman{ 55718316Swollman struct interface *ifp1; 55818316Swollman 55918316Swollman 56018316Swollman if (ifp->int_state & IS_BROKE) 56118316Swollman return; 56218316Swollman 56318316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 56418316Swollman 56518316Swollman ifp->int_state |= (IS_BROKE | IS_SICK); 56619880Swollman ifp->int_act_time = NEVER; 56719880Swollman ifp->int_query_time = NEVER; 56846303Smarkm ifp->int_data.ts = now.tv_sec; 56918316Swollman 57018316Swollman trace_if("Chg", ifp); 57118316Swollman 57218316Swollman if (!(ifp->int_state & IS_ALIAS)) { 57318316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 57418316Swollman if (ifp1 != ifp 57518316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 57618316Swollman if_bad(ifp1); 57718316Swollman } 57818316Swollman (void)rn_walktree(rhead, walk_bad, 0); 57918316Swollman if_bad_rdisc(ifp); 58018316Swollman } 58118316Swollman} 58218316Swollman 58318316Swollman 58418316Swollman/* Mark an interface alive 58518316Swollman */ 58618316Swollmanint /* 1=it was dead */ 58718316Swollmanif_ok(struct interface *ifp, 58846303Smarkm const char *type) 58918316Swollman{ 59018316Swollman struct interface *ifp1; 59118316Swollman 59218316Swollman 59318316Swollman if (!(ifp->int_state & IS_BROKE)) { 59418316Swollman if (ifp->int_state & IS_SICK) { 59519880Swollman trace_act("%sinterface %s to %s working better", 59618316Swollman type, 59719880Swollman ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 59818316Swollman ifp->int_state &= ~IS_SICK; 59918316Swollman } 60018316Swollman return 0; 60118316Swollman } 60218316Swollman 60318316Swollman msglog("%sinterface %s to %s restored", 60419880Swollman type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 60518316Swollman ifp->int_state &= ~(IS_BROKE | IS_SICK); 60618316Swollman ifp->int_data.ts = 0; 60718316Swollman 60818316Swollman if (!(ifp->int_state & IS_ALIAS)) { 60918316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 61018316Swollman if (ifp1 != ifp 61118316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 61218316Swollman if_ok(ifp1, type); 61318316Swollman } 61418316Swollman if_ok_rdisc(ifp); 61518316Swollman } 61619880Swollman 61719880Swollman if (ifp->int_state & IS_REMOTE) { 61819880Swollman if (!addrouteforif(ifp)) 61919880Swollman return 0; 62019880Swollman } 62118316Swollman return 1; 62218316Swollman} 62318316Swollman 62418316Swollman 62546303Smarkm/* disassemble routing message 62618316Swollman */ 62718316Swollmanvoid 62818316Swollmanrt_xaddrs(struct rt_addrinfo *info, 62918316Swollman struct sockaddr *sa, 63018316Swollman struct sockaddr *lim, 63118316Swollman int addrs) 63218316Swollman{ 63318316Swollman int i; 63446303Smarkm#ifdef _HAVE_SA_LEN 63546303Smarkm static struct sockaddr sa_zero; 63646303Smarkm#endif 63718316Swollman#ifdef sgi 63818316Swollman#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \ 63918316Swollman : sizeof(__uint64_t)) 64018316Swollman#else 64118316Swollman#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ 64218316Swollman : sizeof(long)) 64318316Swollman#endif 64418316Swollman 64518316Swollman 64646303Smarkm memset(info, 0, sizeof(*info)); 64718316Swollman info->rti_addrs = addrs; 64818316Swollman for (i = 0; i < RTAX_MAX && sa < lim; i++) { 64918316Swollman if ((addrs & (1 << i)) == 0) 65018316Swollman continue; 65118316Swollman#ifdef _HAVE_SA_LEN 65246303Smarkm info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; 65346303Smarkm sa = (struct sockaddr *)((char*)(sa) 65446303Smarkm + ROUNDUP(sa->sa_len)); 65518316Swollman#else 65646303Smarkm info->rti_info[i] = sa; 65746303Smarkm sa = (struct sockaddr *)((char*)(sa) 65846303Smarkm + ROUNDUP(_FAKE_SA_LEN_DST(sa))); 65927503Sjulian#endif 66018316Swollman } 66118316Swollman} 66218316Swollman 66318316Swollman 66418316Swollman/* Find the network interfaces which have configured themselves. 66518316Swollman * This must be done regularly, if only for extra addresses 66618316Swollman * that come and go on interfaces. 66718316Swollman */ 66818316Swollmanvoid 66918316Swollmanifinit(void) 67018316Swollman{ 67118316Swollman static char *sysctl_buf; 67218316Swollman static size_t sysctl_buf_size = 0; 67318316Swollman uint complaints = 0; 67418316Swollman static u_int prev_complaints = 0; 67518316Swollman# define COMP_NOT_INET 0x001 67619880Swollman# define COMP_NOADDR 0x002 67719880Swollman# define COMP_BADADDR 0x004 67819880Swollman# define COMP_NODST 0x008 67919880Swollman# define COMP_NOBADR 0x010 68019880Swollman# define COMP_NOMASK 0x020 68119880Swollman# define COMP_DUP 0x040 68219880Swollman# define COMP_BAD_METRIC 0x080 68319880Swollman# define COMP_NETMASK 0x100 68418316Swollman 68518316Swollman struct interface ifs, ifs0, *ifp, *ifp1; 68618316Swollman struct rt_entry *rt; 68718316Swollman size_t needed; 68818316Swollman int mib[6]; 68918316Swollman struct if_msghdr *ifm; 69018316Swollman struct ifa_msghdr *ifam, *ifam_lim, *ifam2; 69118316Swollman int in, ierr, out, oerr; 69218316Swollman struct intnet *intnetp; 69318316Swollman struct rt_addrinfo info; 69418316Swollman#ifdef SIOCGIFMETRIC 69518316Swollman struct ifreq ifr; 69618316Swollman#endif 69718316Swollman 69818316Swollman 69920606Swollman last_ifinit = now; 70018316Swollman ifinit_timer.tv_sec = now.tv_sec + (supplier 70118316Swollman ? CHECK_ACT_INTERVAL 70218316Swollman : CHECK_QUIET_INTERVAL); 70318316Swollman 70437908Scharnier /* mark all interfaces so we can get rid of those that disappear */ 70518316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) 70618316Swollman ifp->int_state &= ~(IS_CHECKED | IS_DUP); 70718316Swollman 70818316Swollman /* Fetch the interface list, without too many system calls 70918316Swollman * since we do it repeatedly. 71018316Swollman */ 71118316Swollman mib[0] = CTL_NET; 71218316Swollman mib[1] = PF_ROUTE; 71318316Swollman mib[2] = 0; 71418316Swollman mib[3] = AF_INET; 71518316Swollman mib[4] = NET_RT_IFLIST; 71618316Swollman mib[5] = 0; 71718316Swollman for (;;) { 71818316Swollman if ((needed = sysctl_buf_size) != 0) { 71918316Swollman if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 72018316Swollman break; 72146303Smarkm /* retry if the table grew */ 72218316Swollman if (errno != ENOMEM && errno != EFAULT) 72346303Smarkm BADERR(1, "ifinit: sysctl(RT_IFLIST)"); 72418316Swollman free(sysctl_buf); 72518316Swollman needed = 0; 72618316Swollman } 72718316Swollman if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 72846303Smarkm BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate"); 72946303Smarkm sysctl_buf = rtmalloc(sysctl_buf_size = needed, 73046303Smarkm "ifinit sysctl"); 73118316Swollman } 73218316Swollman 73318316Swollman ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed); 73418316Swollman for (ifam = (struct ifa_msghdr *)sysctl_buf; 73518316Swollman ifam < ifam_lim; 73618316Swollman ifam = ifam2) { 73718316Swollman 73818316Swollman ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); 73918316Swollman 74018316Swollman if (ifam->ifam_type == RTM_IFINFO) { 74119880Swollman struct sockaddr_dl *sdl; 74219880Swollman 74318316Swollman ifm = (struct if_msghdr *)ifam; 74418316Swollman /* make prototype structure for the IP aliases 74518316Swollman */ 74646303Smarkm memset(&ifs0, 0, sizeof(ifs0)); 74718316Swollman ifs0.int_rip_sock = -1; 74818316Swollman ifs0.int_index = ifm->ifm_index; 74918316Swollman ifs0.int_if_flags = ifm->ifm_flags; 75018316Swollman ifs0.int_state = IS_CHECKED; 75120339Swollman ifs0.int_query_time = NEVER; 75218316Swollman ifs0.int_act_time = now.tv_sec; 75318316Swollman ifs0.int_data.ts = now.tv_sec; 75418316Swollman ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; 75518316Swollman ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors; 75618316Swollman ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets; 75718316Swollman ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors; 75818316Swollman#ifdef sgi 75918316Swollman ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops; 76018316Swollman#endif 76118316Swollman sdl = (struct sockaddr_dl *)(ifm + 1); 76218316Swollman sdl->sdl_data[sdl->sdl_nlen] = 0; 76319880Swollman strncpy(ifs0.int_name, sdl->sdl_data, 76419880Swollman MIN(sizeof(ifs0.int_name), sdl->sdl_nlen)); 76518316Swollman continue; 76618316Swollman } 76718316Swollman if (ifam->ifam_type != RTM_NEWADDR) { 76818316Swollman logbad(1,"ifinit: out of sync"); 76918316Swollman continue; 77018316Swollman } 77118316Swollman rt_xaddrs(&info, (struct sockaddr *)(ifam+1), 77218316Swollman (struct sockaddr *)ifam2, 77318316Swollman ifam->ifam_addrs); 77418316Swollman 77519880Swollman /* Prepare for the next address of this interface, which 77619880Swollman * will be an alias. 77719880Swollman * Do not output RIP or Router-Discovery packets via aliases. 77819880Swollman */ 77946303Smarkm memcpy(&ifs, &ifs0, sizeof(ifs)); 78046303Smarkm ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC); 78119880Swollman 78218316Swollman if (INFO_IFA(&info) == 0) { 78346303Smarkm if (iff_up(ifs.int_if_flags)) { 78418316Swollman if (!(prev_complaints & COMP_NOADDR)) 78518316Swollman msglog("%s has no address", 78619880Swollman ifs.int_name); 78718316Swollman complaints |= COMP_NOADDR; 78818316Swollman } 78918316Swollman continue; 79018316Swollman } 79118316Swollman if (INFO_IFA(&info)->sa_family != AF_INET) { 79246303Smarkm if (iff_up(ifs.int_if_flags)) { 79318316Swollman if (!(prev_complaints & COMP_NOT_INET)) 79419880Swollman trace_act("%s: not AF_INET", 79519880Swollman ifs.int_name); 79618316Swollman complaints |= COMP_NOT_INET; 79718316Swollman } 79818316Swollman continue; 79918316Swollman } 80018316Swollman 80118316Swollman ifs.int_addr = S_ADDR(INFO_IFA(&info)); 80218316Swollman 80318316Swollman if (ntohl(ifs.int_addr)>>24 == 0 80418316Swollman || ntohl(ifs.int_addr)>>24 == 0xff) { 80546303Smarkm if (iff_up(ifs.int_if_flags)) { 80618316Swollman if (!(prev_complaints & COMP_BADADDR)) 80718316Swollman msglog("%s has a bad address", 80819880Swollman ifs.int_name); 80918316Swollman complaints |= COMP_BADADDR; 81018316Swollman } 81118316Swollman continue; 81218316Swollman } 81318316Swollman 81419880Swollman if (ifs.int_if_flags & IFF_LOOPBACK) { 81519880Swollman ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC; 81618316Swollman ifs.int_dstaddr = ifs.int_addr; 81719880Swollman ifs.int_mask = HOST_MASK; 81819880Swollman ifs.int_ripv1_mask = HOST_MASK; 81919880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 82019880Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 82119880Swollman if (!foundloopback) { 82219880Swollman foundloopback = 1; 82319880Swollman loopaddr = ifs.int_addr; 82446303Smarkm loop_rts.rts_gate = loopaddr; 82546303Smarkm loop_rts.rts_router = loopaddr; 82618316Swollman } 82718316Swollman 82818316Swollman } else if (ifs.int_if_flags & IFF_POINTOPOINT) { 82918316Swollman if (INFO_BRD(&info) == 0 83018316Swollman || INFO_BRD(&info)->sa_family != AF_INET) { 83146303Smarkm if (iff_up(ifs.int_if_flags)) { 83218316Swollman if (!(prev_complaints & COMP_NODST)) 83318316Swollman msglog("%s has a bad" 83418316Swollman " destination address", 83519880Swollman ifs.int_name); 83618316Swollman complaints |= COMP_NODST; 83718316Swollman } 83818316Swollman continue; 83918316Swollman } 84018316Swollman ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); 84118316Swollman if (ntohl(ifs.int_dstaddr)>>24 == 0 84218316Swollman || ntohl(ifs.int_dstaddr)>>24 == 0xff) { 84346303Smarkm if (iff_up(ifs.int_if_flags)) { 84418316Swollman if (!(prev_complaints & COMP_NODST)) 84518316Swollman msglog("%s has a bad" 84618316Swollman " destination address", 84719880Swollman ifs.int_name); 84818316Swollman complaints |= COMP_NODST; 84918316Swollman } 85018316Swollman continue; 85118316Swollman } 85218316Swollman ifs.int_mask = HOST_MASK; 85318316Swollman ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); 85419880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 85518316Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 85618316Swollman 85719880Swollman } else { 85819880Swollman if (INFO_MASK(&info) == 0) { 85946303Smarkm if (iff_up(ifs.int_if_flags)) { 86019880Swollman if (!(prev_complaints & COMP_NOMASK)) 86119880Swollman msglog("%s has no netmask", 86219880Swollman ifs.int_name); 86319880Swollman complaints |= COMP_NOMASK; 86419880Swollman } 86519880Swollman continue; 86619880Swollman } 86718316Swollman ifs.int_dstaddr = ifs.int_addr; 86819880Swollman ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); 86919880Swollman ifs.int_ripv1_mask = ifs.int_mask; 87019880Swollman ifs.int_std_mask = std_mask(ifs.int_addr); 87119880Swollman ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; 87219880Swollman if (ifs.int_mask != ifs.int_std_mask) 87319880Swollman ifs.int_state |= IS_SUBNET; 87419880Swollman 87519880Swollman if (ifs.int_if_flags & IFF_BROADCAST) { 87619880Swollman if (INFO_BRD(&info) == 0) { 87746303Smarkm if (iff_up(ifs.int_if_flags)) { 87819880Swollman if (!(prev_complaints 87919880Swollman & COMP_NOBADR)) 88019880Swollman msglog("%s has" 88119880Swollman "no broadcast address", 88219880Swollman ifs.int_name); 88319880Swollman complaints |= COMP_NOBADR; 88419880Swollman } 88519880Swollman continue; 88619880Swollman } 88719880Swollman ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); 88818316Swollman } 88918316Swollman } 89018316Swollman ifs.int_std_net = ifs.int_net & ifs.int_std_mask; 89118316Swollman ifs.int_std_addr = htonl(ifs.int_std_net); 89218316Swollman 89318316Swollman /* Use a minimum metric of one. Treat the interface metric 89418316Swollman * (default 0) as an increment to the hop count of one. 89518316Swollman * 89618316Swollman * The metric obtained from the routing socket dump of 89718316Swollman * interface addresses is wrong. It is not set by the 89818316Swollman * SIOCSIFMETRIC ioctl. 89918316Swollman */ 90018316Swollman#ifdef SIOCGIFMETRIC 90119880Swollman strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name)); 90218316Swollman if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) { 90318316Swollman DBGERR(1, "ioctl(SIOCGIFMETRIC)"); 90418316Swollman ifs.int_metric = 0; 90518316Swollman } else { 90618316Swollman ifs.int_metric = ifr.ifr_metric; 90718316Swollman } 90818316Swollman#else 90918316Swollman ifs.int_metric = ifam->ifam_metric; 91018316Swollman#endif 91118316Swollman if (ifs.int_metric > HOPCNT_INFINITY) { 91218316Swollman ifs.int_metric = 0; 91318316Swollman if (!(prev_complaints & COMP_BAD_METRIC) 91446303Smarkm && iff_up(ifs.int_if_flags)) { 91518316Swollman complaints |= COMP_BAD_METRIC; 91618316Swollman msglog("%s has a metric of %d", 91719880Swollman ifs.int_name, ifs.int_metric); 91818316Swollman } 91918316Swollman } 92018316Swollman 92118316Swollman /* See if this is a familiar interface. 92218316Swollman * If so, stop worrying about it if it is the same. 92318316Swollman * Start it over if it now is to somewhere else, as happens 92418316Swollman * frequently with PPP and SLIP. 92518316Swollman */ 92619880Swollman ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS) 92719880Swollman ? ifs.int_addr 92819880Swollman : 0)); 92918316Swollman if (ifp != 0) { 93018316Swollman ifp->int_state |= IS_CHECKED; 93118316Swollman 93218316Swollman if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags) 93318316Swollman & (IFF_BROADCAST 93418316Swollman | IFF_LOOPBACK 93518316Swollman | IFF_POINTOPOINT 93618316Swollman | IFF_MULTICAST)) 93718316Swollman || 0 != ((ifp->int_state ^ ifs.int_state) 93818316Swollman & IS_ALIAS) 93918316Swollman || ifp->int_addr != ifs.int_addr 94018316Swollman || ifp->int_brdaddr != ifs.int_brdaddr 94118316Swollman || ifp->int_dstaddr != ifs.int_dstaddr 94218316Swollman || ifp->int_mask != ifs.int_mask 94318316Swollman || ifp->int_metric != ifs.int_metric) { 94418316Swollman /* Forget old information about 94518316Swollman * a changed interface. 94618316Swollman */ 94719880Swollman trace_act("interface %s has changed", 94818316Swollman ifp->int_name); 94918316Swollman ifdel(ifp); 95018316Swollman ifp = 0; 95118316Swollman } 95218316Swollman } 95318316Swollman 95418316Swollman if (ifp != 0) { 95518316Swollman /* The primary representative of an alias worries 95618316Swollman * about how things are working. 95718316Swollman */ 95818316Swollman if (ifp->int_state & IS_ALIAS) 95918316Swollman continue; 96018316Swollman 96118316Swollman /* note interfaces that have been turned off 96218316Swollman */ 96346303Smarkm if (!iff_up(ifs.int_if_flags)) { 96446303Smarkm if (iff_up(ifp->int_if_flags)) { 96518316Swollman msglog("interface %s to %s turned off", 96618316Swollman ifp->int_name, 96719880Swollman naddr_ntoa(ifp->int_dstaddr)); 96818316Swollman if_bad(ifp); 96946303Smarkm ifp->int_if_flags &= ~IFF_UP; 97046303Smarkm } else if (now.tv_sec>(ifp->int_data.ts 97146303Smarkm + CHECK_BAD_INTERVAL)) { 97246303Smarkm trace_act("interface %s has been off" 97346303Smarkm " %ld seconds; forget it", 97446303Smarkm ifp->int_name, 97546303Smarkm now.tv_sec-ifp->int_data.ts); 97646303Smarkm ifdel(ifp); 97718316Swollman } 97818316Swollman continue; 97918316Swollman } 98018316Swollman /* or that were off and are now ok */ 98146303Smarkm if (!iff_up(ifp->int_if_flags)) { 98246303Smarkm ifp->int_if_flags |= IFF_UP; 98318316Swollman (void)if_ok(ifp, ""); 98418316Swollman } 98518316Swollman 98618316Swollman /* If it has been long enough, 98718316Swollman * see if the interface is broken. 98818316Swollman */ 98918316Swollman if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL) 99018316Swollman continue; 99118316Swollman 99218316Swollman in = ifs.int_data.ipackets - ifp->int_data.ipackets; 99318316Swollman ierr = ifs.int_data.ierrors - ifp->int_data.ierrors; 99418316Swollman out = ifs.int_data.opackets - ifp->int_data.opackets; 99518316Swollman oerr = ifs.int_data.oerrors - ifp->int_data.oerrors; 99618316Swollman#ifdef sgi 99718316Swollman /* Through at least IRIX 6.2, PPP and SLIP 99846303Smarkm * count packets dropped by the filters. 99918316Swollman * But FDDI rings stuck non-operational count 100018316Swollman * dropped packets as they wait for improvement. 100118316Swollman */ 100218316Swollman if (!(ifp->int_if_flags & IFF_POINTOPOINT)) 100318316Swollman oerr += (ifs.int_data.odrops 100418316Swollman - ifp->int_data.odrops); 100518316Swollman#endif 100618316Swollman /* If the interface just awoke, restart the counters. 100718316Swollman */ 100818316Swollman if (ifp->int_data.ts == 0) { 100918316Swollman ifp->int_data = ifs.int_data; 101018316Swollman continue; 101118316Swollman } 101218316Swollman ifp->int_data = ifs.int_data; 101318316Swollman 101437908Scharnier /* Withhold judgment when the short error 101518316Swollman * counters wrap or the interface is reset. 101618316Swollman */ 101718316Swollman if (ierr < 0 || in < 0 || oerr < 0 || out < 0) { 101818316Swollman LIM_SEC(ifinit_timer, 101918316Swollman now.tv_sec+CHECK_BAD_INTERVAL); 102018316Swollman continue; 102118316Swollman } 102218316Swollman 102318316Swollman /* Withhold judgement when there is no traffic 102418316Swollman */ 102518316Swollman if (in == 0 && out == 0 && ierr == 0 && oerr == 0) 102618316Swollman continue; 102718316Swollman 102818316Swollman /* It is bad if input or output is not working. 102918316Swollman * Require presistent problems before marking it dead. 103018316Swollman */ 103118316Swollman if ((in <= ierr && ierr > 0) 103218316Swollman || (out <= oerr && oerr > 0)) { 103318316Swollman if (!(ifp->int_state & IS_SICK)) { 103418316Swollman trace_act("interface %s to %s" 103518316Swollman " sick: in=%d ierr=%d" 103619880Swollman " out=%d oerr=%d", 103718316Swollman ifp->int_name, 103819880Swollman naddr_ntoa(ifp->int_dstaddr), 103918316Swollman in, ierr, out, oerr); 104018316Swollman if_sick(ifp); 104118316Swollman continue; 104218316Swollman } 104318316Swollman if (!(ifp->int_state & IS_BROKE)) { 104419880Swollman msglog("interface %s to %s broken:" 104518316Swollman " in=%d ierr=%d out=%d oerr=%d", 104618316Swollman ifp->int_name, 104719880Swollman naddr_ntoa(ifp->int_dstaddr), 104818316Swollman in, ierr, out, oerr); 104918316Swollman if_bad(ifp); 105018316Swollman } 105118316Swollman continue; 105218316Swollman } 105318316Swollman 105418316Swollman /* otherwise, it is active and healthy 105518316Swollman */ 105618316Swollman ifp->int_act_time = now.tv_sec; 105718316Swollman (void)if_ok(ifp, ""); 105818316Swollman continue; 105918316Swollman } 106018316Swollman 106118316Swollman /* This is a new interface. 106218316Swollman * If it is dead, forget it. 106318316Swollman */ 106446303Smarkm if (!iff_up(ifs.int_if_flags)) 106518316Swollman continue; 106618316Swollman 106719880Swollman /* If it duplicates an existing interface, 106819880Swollman * complain about it, mark the other one 106919880Swollman * duplicated, and forget this one. 107018316Swollman */ 107119880Swollman ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, 107219880Swollman ifs.int_if_flags); 107319880Swollman if (ifp != 0) { 107446303Smarkm /* Ignore duplicates of itself, caused by having 107546303Smarkm * IP aliases on the same network. 107646303Smarkm */ 107746303Smarkm if (!strcmp(ifp->int_name, ifs.int_name)) 107846303Smarkm continue; 107946303Smarkm 108018316Swollman if (!(prev_complaints & COMP_DUP)) { 108118316Swollman complaints |= COMP_DUP; 108220339Swollman msglog("%s (%s%s%s) is duplicated by" 108320339Swollman " %s (%s%s%s)", 108420339Swollman ifs.int_name, 108520339Swollman addrname(ifs.int_addr,ifs.int_mask,1), 108620339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 108720339Swollman ? "-->" : ""), 108820339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 108920339Swollman ? naddr_ntoa(ifs.int_dstaddr) : ""), 109020339Swollman ifp->int_name, 109120339Swollman addrname(ifp->int_addr,ifp->int_mask,1), 109220339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 109320339Swollman ? "-->" : ""), 109420339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 109520339Swollman ? naddr_ntoa(ifp->int_dstaddr) : "")); 109618316Swollman } 109718316Swollman ifp->int_state |= IS_DUP; 109819880Swollman continue; 109918316Swollman } 110018316Swollman 110119880Swollman if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST)) 110219880Swollman && !(ifs.int_state & IS_PASSIVE)) { 110319880Swollman trace_act("%s is neither broadcast, point-to-point," 110419880Swollman " nor loopback", 110519880Swollman ifs.int_name); 110619880Swollman if (!(ifs.int_state & IFF_MULTICAST)) 110719880Swollman ifs.int_state |= IS_NO_RDISC; 110819880Swollman } 110918316Swollman 111019880Swollman 111119880Swollman /* It is new and ok. Add it to the list of interfaces 111218316Swollman */ 111346303Smarkm ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp"); 111446303Smarkm memcpy(ifp, &ifs, sizeof(*ifp)); 111519880Swollman get_parms(ifp); 111619880Swollman if_link(ifp); 111718316Swollman trace_if("Add", ifp); 111818316Swollman 111918316Swollman /* Notice likely bad netmask. 112018316Swollman */ 112118316Swollman if (!(prev_complaints & COMP_NETMASK) 112219880Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 112319880Swollman && ifp->int_addr != RIP_DEFAULT) { 112418316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 112518316Swollman if (ifp1->int_mask == ifp->int_mask) 112618316Swollman continue; 112718316Swollman if (ifp1->int_if_flags & IFF_POINTOPOINT) 112818316Swollman continue; 112919880Swollman if (ifp1->int_dstaddr == RIP_DEFAULT) 113019880Swollman continue; 113164483Ssheldonh /* ignore aliases on the right network */ 113264483Ssheldonh if (!strcmp(ifp->int_name, ifp1->int_name)) 113364483Ssheldonh continue; 113419880Swollman if (on_net(ifp->int_dstaddr, 113518316Swollman ifp1->int_net, ifp1->int_mask) 113619880Swollman || on_net(ifp1->int_dstaddr, 113718316Swollman ifp->int_net, ifp->int_mask)) { 113818316Swollman msglog("possible netmask problem" 113919880Swollman " between %s:%s and %s:%s", 114018316Swollman ifp->int_name, 114118316Swollman addrname(htonl(ifp->int_net), 114218316Swollman ifp->int_mask, 1), 114318316Swollman ifp1->int_name, 114418316Swollman addrname(htonl(ifp1->int_net), 114518316Swollman ifp1->int_mask, 1)); 114618316Swollman complaints |= COMP_NETMASK; 114718316Swollman } 114818316Swollman } 114918316Swollman } 115018316Swollman 115118316Swollman if (!(ifp->int_state & IS_ALIAS)) { 115219880Swollman /* Count the # of directly connected networks. 115319880Swollman */ 115418316Swollman if (!(ifp->int_if_flags & IFF_LOOPBACK)) 115518316Swollman tot_interfaces++; 115618316Swollman if (!IS_RIP_OFF(ifp->int_state)) 115718316Swollman rip_interfaces++; 115819880Swollman 115919880Swollman /* turn on router discovery and RIP If needed */ 116019880Swollman if_ok_rdisc(ifp); 116119880Swollman rip_on(ifp); 116218316Swollman } 116318316Swollman } 116418316Swollman 116519880Swollman /* If we are multi-homed and have at least two interfaces 116618316Swollman * listening to RIP, then output by default. 116718316Swollman */ 116818316Swollman if (!supplier_set && rip_interfaces > 1) 116918316Swollman set_supplier(); 117018316Swollman 117118316Swollman /* If we are multi-homed, optionally advertise a route to 117218316Swollman * our main address. 117318316Swollman */ 117418316Swollman if (advertise_mhome 117518316Swollman || (tot_interfaces > 1 117618316Swollman && mhome 117718316Swollman && (ifp = ifwithaddr(myaddr, 0, 0)) != 0 117818316Swollman && foundloopback)) { 117918316Swollman advertise_mhome = 1; 118018316Swollman rt = rtget(myaddr, HOST_MASK); 118118316Swollman if (rt != 0) { 118218316Swollman if (rt->rt_ifp != ifp 118318316Swollman || rt->rt_router != loopaddr) { 118418316Swollman rtdelete(rt); 118518316Swollman rt = 0; 118618316Swollman } else { 118746303Smarkm loop_rts.rts_ifp = ifp; 118846303Smarkm loop_rts.rts_metric = 0; 118946303Smarkm loop_rts.rts_time = rt->rt_time; 119018316Swollman rtchange(rt, rt->rt_state | RS_MHOME, 119146303Smarkm &loop_rts, 0); 119218316Swollman } 119318316Swollman } 119446303Smarkm if (rt == 0) { 119546303Smarkm loop_rts.rts_ifp = ifp; 119646303Smarkm loop_rts.rts_metric = 0; 119746303Smarkm rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts); 119846303Smarkm } 119918316Swollman } 120018316Swollman 120118316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp1) { 120218316Swollman ifp1 = ifp->int_next; /* because we may delete it */ 120318316Swollman 120418316Swollman /* Forget any interfaces that have disappeared. 120518316Swollman */ 120618316Swollman if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { 120719880Swollman trace_act("interface %s has disappeared", 120818316Swollman ifp->int_name); 120918316Swollman ifdel(ifp); 121018316Swollman continue; 121118316Swollman } 121218316Swollman 121318316Swollman if ((ifp->int_state & IS_BROKE) 121418316Swollman && !(ifp->int_state & IS_PASSIVE)) 121518316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 121618316Swollman 121718316Swollman /* If we ever have a RIPv1 interface, assume we always will. 121818316Swollman * It might come back if it ever goes away. 121918316Swollman */ 122018316Swollman if (!(ifp->int_state & IS_NO_RIPV1_OUT) && supplier) 122118316Swollman have_ripv1_out = 1; 122218316Swollman if (!(ifp->int_state & IS_NO_RIPV1_IN)) 122318316Swollman have_ripv1_in = 1; 122418316Swollman } 122518316Swollman 122618316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 122718316Swollman /* Ensure there is always a network route for interfaces, 122818316Swollman * after any dead interfaces have been deleted, which 122918316Swollman * might affect routes for point-to-point links. 123018316Swollman */ 123119880Swollman if (!addrouteforif(ifp)) 123219880Swollman continue; 123318316Swollman 123418316Swollman /* Add routes to the local end of point-to-point interfaces 123518316Swollman * using loopback. 123618316Swollman */ 123718316Swollman if ((ifp->int_if_flags & IFF_POINTOPOINT) 123818316Swollman && !(ifp->int_state & IS_REMOTE) 123918316Swollman && foundloopback) { 124018316Swollman /* Delete any routes to the network address through 124118316Swollman * foreign routers. Remove even static routes. 124218316Swollman */ 124346303Smarkm del_static(ifp->int_addr, HOST_MASK, 0, 0); 124418316Swollman rt = rtget(ifp->int_addr, HOST_MASK); 124518316Swollman if (rt != 0 && rt->rt_router != loopaddr) { 124618316Swollman rtdelete(rt); 124718316Swollman rt = 0; 124818316Swollman } 124918316Swollman if (rt != 0) { 125018316Swollman if (!(rt->rt_state & RS_LOCAL) 125118316Swollman || rt->rt_metric > ifp->int_metric) { 125218316Swollman ifp1 = ifp; 125318316Swollman } else { 125418316Swollman ifp1 = rt->rt_ifp; 125518316Swollman } 125646303Smarkm loop_rts.rts_ifp = ifp1; 125746303Smarkm loop_rts.rts_metric = 0; 125846303Smarkm loop_rts.rts_time = rt->rt_time; 125946303Smarkm rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) 126046303Smarkm | (RS_IF|RS_LOCAL)), 126146303Smarkm &loop_rts, 0); 126218316Swollman } else { 126346303Smarkm loop_rts.rts_ifp = ifp; 126446303Smarkm loop_rts.rts_metric = 0; 126518316Swollman rtadd(ifp->int_addr, HOST_MASK, 126646303Smarkm (RS_IF | RS_LOCAL), &loop_rts); 126718316Swollman } 126818316Swollman } 126918316Swollman } 127018316Swollman 127118316Swollman /* add the authority routes */ 127218316Swollman for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) { 127318316Swollman rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); 127418316Swollman if (rt != 0 127518316Swollman && !(rt->rt_state & RS_NO_NET_SYN) 127618316Swollman && !(rt->rt_state & RS_NET_INT)) { 127718316Swollman rtdelete(rt); 127818316Swollman rt = 0; 127918316Swollman } 128046303Smarkm if (rt == 0) { 128146303Smarkm loop_rts.rts_ifp = 0; 128246303Smarkm loop_rts.rts_metric = intnetp->intnet_metric-1; 128318316Swollman rtadd(intnetp->intnet_addr, intnetp->intnet_mask, 128446303Smarkm RS_NET_SYN | RS_NET_INT, &loop_rts); 128546303Smarkm } 128618316Swollman } 128718316Swollman 128818316Swollman prev_complaints = complaints; 128918316Swollman} 129018316Swollman 129118316Swollman 129218316Swollmanstatic void 129318316Swollmancheck_net_syn(struct interface *ifp) 129418316Swollman{ 129518316Swollman struct rt_entry *rt; 129646303Smarkm static struct rt_spare new; 129718316Swollman 129818316Swollman 129918316Swollman /* Turn on the need to automatically synthesize a network route 130018316Swollman * for this interface only if we are running RIPv1 on some other 130118316Swollman * interface that is on a different class-A,B,or C network. 130218316Swollman */ 130318316Swollman if (have_ripv1_out || have_ripv1_in) { 130418316Swollman ifp->int_state |= IS_NEED_NET_SYN; 130518316Swollman rt = rtget(ifp->int_std_addr, ifp->int_std_mask); 130618316Swollman if (rt != 0 130718316Swollman && 0 == (rt->rt_state & RS_NO_NET_SYN) 130818316Swollman && (!(rt->rt_state & RS_NET_SYN) 130918316Swollman || rt->rt_metric > ifp->int_metric)) { 131018316Swollman rtdelete(rt); 131118316Swollman rt = 0; 131218316Swollman } 131346303Smarkm if (rt == 0) { 131446303Smarkm new.rts_ifp = ifp; 131546303Smarkm new.rts_gate = ifp->int_addr; 131646303Smarkm new.rts_router = ifp->int_addr; 131746303Smarkm new.rts_metric = ifp->int_metric; 131818316Swollman rtadd(ifp->int_std_addr, ifp->int_std_mask, 131946303Smarkm RS_NET_SYN, &new); 132046303Smarkm } 132118316Swollman 132218316Swollman } else { 132318316Swollman ifp->int_state &= ~IS_NEED_NET_SYN; 132418316Swollman 132518316Swollman rt = rtget(ifp->int_std_addr, 132618316Swollman ifp->int_std_mask); 132718316Swollman if (rt != 0 132818316Swollman && (rt->rt_state & RS_NET_SYN) 132918316Swollman && rt->rt_ifp == ifp) 133018316Swollman rtbad_sub(rt); 133118316Swollman } 133218316Swollman} 133318316Swollman 133418316Swollman 133518316Swollman/* Add route for interface if not currently installed. 133618316Swollman * Create route to other end if a point-to-point link, 133718316Swollman * otherwise a route to this (sub)network. 133818316Swollman */ 133919880Swollmanint /* 0=bad interface */ 134018316Swollmanaddrouteforif(struct interface *ifp) 134118316Swollman{ 134218316Swollman struct rt_entry *rt; 134346303Smarkm static struct rt_spare new; 134446303Smarkm naddr dst; 134518316Swollman 134618316Swollman 134718316Swollman /* skip sick interfaces 134818316Swollman */ 134918316Swollman if (ifp->int_state & IS_BROKE) 135019880Swollman return 0; 135118316Swollman 135218316Swollman /* If the interface on a subnet, then install a RIPv1 route to 135318316Swollman * the network as well (unless it is sick). 135418316Swollman */ 135518316Swollman if (ifp->int_state & IS_SUBNET) 135618316Swollman check_net_syn(ifp); 135718316Swollman 135819880Swollman dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) 135919880Swollman ? ifp->int_dstaddr 136019880Swollman : htonl(ifp->int_net)); 136118316Swollman 136246303Smarkm new.rts_ifp = ifp; 136346303Smarkm new.rts_router = ifp->int_addr; 136446303Smarkm new.rts_gate = ifp->int_addr; 136546303Smarkm new.rts_metric = ifp->int_metric; 136646303Smarkm new.rts_time = now.tv_sec; 136746303Smarkm 136819880Swollman /* If we are going to send packets to the gateway, 136919880Swollman * it must be reachable using our physical interfaces 137019880Swollman */ 137119880Swollman if ((ifp->int_state & IS_REMOTE) 137220339Swollman && !(ifp->int_state & IS_EXTERNAL) 137319880Swollman && !check_remote(ifp)) 137419880Swollman return 0; 137518316Swollman 137618316Swollman /* We are finished if the correct main interface route exists. 137718316Swollman * The right route must be for the right interface, not synthesized 137818316Swollman * from a subnet, be a "gateway" or not as appropriate, and so forth. 137918316Swollman */ 138046303Smarkm del_static(dst, ifp->int_mask, 0, 0); 138118316Swollman rt = rtget(dst, ifp->int_mask); 138218316Swollman if (rt != 0) { 138318316Swollman if ((rt->rt_ifp != ifp 138418316Swollman || rt->rt_router != ifp->int_addr) 138518316Swollman && (!(ifp->int_state & IS_DUP) 138618316Swollman || rt->rt_ifp == 0 138718316Swollman || (rt->rt_ifp->int_state & IS_BROKE))) { 138818316Swollman rtdelete(rt); 138918316Swollman rt = 0; 139018316Swollman } else { 139118316Swollman rtchange(rt, ((rt->rt_state | RS_IF) 139218316Swollman & ~(RS_NET_SYN | RS_LOCAL)), 139346303Smarkm &new, 0); 139418316Swollman } 139518316Swollman } 139618316Swollman if (rt == 0) { 139718316Swollman if (ifp->int_transitions++ > 0) 139819880Swollman trace_act("re-install interface %s", 139918316Swollman ifp->int_name); 140018316Swollman 140146303Smarkm rtadd(dst, ifp->int_mask, RS_IF, &new); 140218316Swollman } 140319880Swollman 140419880Swollman return 1; 140518316Swollman} 1406