if.c revision 126250
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 126250 2004-02-25 23:45:57Z bms $ 3418316Swollman */ 3518316Swollman 3618316Swollman#include "defs.h" 3718316Swollman#include "pathnames.h" 3818316Swollman 39126250Sbms#ifdef __NetBSD__ 4046303Smarkm__RCSID("$NetBSD$"); 41126250Sbms#elif defined(__FreeBSD__) 42126250Sbms__RCSID("$FreeBSD: head/sbin/routed/if.c 126250 2004-02-25 23:45:57Z bms $"); 43126250Sbms#else 44126250Sbms__RCSID("$Revision: 2.27 $"); 45126250Sbms#ident "$Revision: 2.27 $" 4646303Smarkm#endif 4750969Speter#ident "$FreeBSD: head/sbin/routed/if.c 126250 2004-02-25 23:45:57Z bms $" 4819880Swollmanstruct interface *ifnet; /* all interfaces */ 4919880Swollman 5019880Swollman/* hash table for all interfaces, big enough to tolerate ridiculous 5119880Swollman * numbers of IP aliases. Crazy numbers of aliases such as 7000 5219880Swollman * still will not do well, but not just in looking up interfaces 5319880Swollman * by name or address. 5419880Swollman */ 5519880Swollman#define AHASH_LEN 211 /* must be prime */ 5621378Swollman#define AHASH(a) &ahash_tbl[(a)%AHASH_LEN] 5721378Swollmanstruct interface *ahash_tbl[AHASH_LEN]; 5819880Swollman 5919880Swollman#define BHASH_LEN 211 /* must be prime */ 6021378Swollman#define BHASH(a) &bhash_tbl[(a)%BHASH_LEN] 6121378Swollmanstruct interface *bhash_tbl[BHASH_LEN]; 6219880Swollman 6319880Swollmanstruct interface *remote_if; /* remote interfaces */ 6419880Swollman 6519880Swollman/* hash for physical interface names. 6619880Swollman * Assume there are never more 100 or 200 real interfaces, and that 6720606Swollman * aliases are put on the end of the hash chains. 6819880Swollman */ 6919880Swollman#define NHASH_LEN 97 7021378Swollmanstruct interface *nhash_tbl[NHASH_LEN]; 7119880Swollman 7218316Swollmanint tot_interfaces; /* # of remote and local interfaces */ 7318316Swollmanint rip_interfaces; /* # of interfaces doing RIP */ 7418316Swollmanint foundloopback; /* valid flag for loopaddr */ 7518316Swollmannaddr loopaddr; /* our address on loopback */ 7646303Smarkmstruct rt_spare loop_rts; 7718316Swollman 7818316Swollmanstruct timeval ifinit_timer; 7920606Swollmanstatic struct timeval last_ifinit; 8046303Smarkm#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec \ 8146303Smarkm && last_ifinit.tv_usec == now.tv_usec \ 8246303Smarkm && timercmp(&ifinit_timer, &now, >)) 8318316Swollman 8418316Swollmanint have_ripv1_out; /* have a RIPv1 interface */ 8518316Swollmanint have_ripv1_in; 8618316Swollman 8718316Swollman 8821378Swollmanstatic struct interface** 8946303Smarkmnhash(char *p) 9021378Swollman{ 9146303Smarkm u_int i; 9221378Swollman 9321378Swollman for (i = 0; *p != '\0'; p++) { 9421378Swollman i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1); 9521378Swollman i ^= *p; 9621378Swollman } 9721378Swollman return &nhash_tbl[i % NHASH_LEN]; 9821378Swollman} 9921378Swollman 10021378Swollman 10120606Swollman/* Link a new interface into the lists and hash tables. 10220606Swollman */ 10319880Swollmanvoid 10419880Swollmanif_link(struct interface *ifp) 10519880Swollman{ 10619880Swollman struct interface **hifp; 10719880Swollman 10819880Swollman ifp->int_prev = &ifnet; 10919880Swollman ifp->int_next = ifnet; 11019880Swollman if (ifnet != 0) 11119880Swollman ifnet->int_prev = &ifp->int_next; 11219880Swollman ifnet = ifp; 11319880Swollman 11419880Swollman hifp = AHASH(ifp->int_addr); 11519880Swollman ifp->int_ahash_prev = hifp; 11619880Swollman if ((ifp->int_ahash = *hifp) != 0) 11719880Swollman (*hifp)->int_ahash_prev = &ifp->int_ahash; 11819880Swollman *hifp = ifp; 11919880Swollman 12019880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 12119880Swollman hifp = BHASH(ifp->int_brdaddr); 12219880Swollman ifp->int_bhash_prev = hifp; 12319880Swollman if ((ifp->int_bhash = *hifp) != 0) 12419880Swollman (*hifp)->int_bhash_prev = &ifp->int_bhash; 12519880Swollman *hifp = ifp; 12619880Swollman } 12719880Swollman 12819880Swollman if (ifp->int_state & IS_REMOTE) { 12919880Swollman ifp->int_rlink_prev = &remote_if; 13019880Swollman ifp->int_rlink = remote_if; 13119880Swollman if (remote_if != 0) 13219880Swollman remote_if->int_rlink_prev = &ifp->int_rlink; 13319880Swollman remote_if = ifp; 13419880Swollman } 13519880Swollman 13621378Swollman hifp = nhash(ifp->int_name); 13719880Swollman if (ifp->int_state & IS_ALIAS) { 13820606Swollman /* put aliases on the end of the hash chain */ 13919880Swollman while (*hifp != 0) 14019880Swollman hifp = &(*hifp)->int_nhash; 14119880Swollman } 14219880Swollman ifp->int_nhash_prev = hifp; 14319880Swollman if ((ifp->int_nhash = *hifp) != 0) 14419880Swollman (*hifp)->int_nhash_prev = &ifp->int_nhash; 14519880Swollman *hifp = ifp; 14619880Swollman} 14719880Swollman 14819880Swollman 14918316Swollman/* Find the interface with an address 15018316Swollman */ 15118316Swollmanstruct interface * 15218316Swollmanifwithaddr(naddr addr, 15318316Swollman int bcast, /* notice IFF_BROADCAST address */ 15418316Swollman int remote) /* include IS_REMOTE interfaces */ 15518316Swollman{ 15618316Swollman struct interface *ifp, *possible = 0; 15718316Swollman 15819880Swollman remote = (remote == 0) ? IS_REMOTE : 0; 15918316Swollman 16019880Swollman for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) { 16119880Swollman if (ifp->int_addr != addr) 16219880Swollman continue; 16319880Swollman if ((ifp->int_state & remote) != 0) 16419880Swollman continue; 16519880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 16619880Swollman return ifp; 16719880Swollman possible = ifp; 16819880Swollman } 16918316Swollman 17019880Swollman if (possible || !bcast) 17119880Swollman return possible; 17219880Swollman 17319880Swollman for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) { 17419880Swollman if (ifp->int_brdaddr != addr) 17519880Swollman continue; 17619880Swollman if ((ifp->int_state & remote) != 0) 17719880Swollman continue; 17819880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 17919880Swollman return ifp; 18019880Swollman possible = ifp; 18118316Swollman } 18218316Swollman 18318316Swollman return possible; 18418316Swollman} 18518316Swollman 18618316Swollman 18718316Swollman/* find the interface with a name 18818316Swollman */ 18918316Swollmanstruct interface * 19018316Swollmanifwithname(char *name, /* "ec0" or whatever */ 19118316Swollman naddr addr) /* 0 or network address */ 19218316Swollman{ 19318316Swollman struct interface *ifp; 19418316Swollman 19520606Swollman for (;;) { 19621378Swollman for (ifp = *nhash(name); ifp != 0; ifp = ifp->int_nhash) { 19720606Swollman /* If the network address is not specified, 19820606Swollman * ignore any alias interfaces. Otherwise, look 19920606Swollman * for the interface with the target name and address. 20020606Swollman */ 20120606Swollman if (!strcmp(ifp->int_name, name) 20220606Swollman && ((addr == 0 && !(ifp->int_state & IS_ALIAS)) 20320606Swollman || (ifp->int_addr == addr))) 20420606Swollman return ifp; 20520606Swollman } 20620606Swollman 20720606Swollman /* If there is no known interface, maybe there is a 20820606Swollman * new interface. So just once look for new interfaces. 20919880Swollman */ 21046303Smarkm if (IF_RESCAN_DELAY()) 21120606Swollman return 0; 21220606Swollman ifinit(); 21318316Swollman } 21418316Swollman} 21518316Swollman 21618316Swollman 21718316Swollmanstruct interface * 218126250Sbmsifwithindex(u_short ifindex, 21946303Smarkm int rescan_ok) 22018316Swollman{ 22118316Swollman struct interface *ifp; 22218316Swollman 22346303Smarkm for (;;) { 22446303Smarkm for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 225126250Sbms if (ifp->int_index == ifindex) 22646303Smarkm return ifp; 22746303Smarkm } 22818316Swollman 22946303Smarkm /* If there is no known interface, maybe there is a 23046303Smarkm * new interface. So just once look for new interfaces. 23146303Smarkm */ 23246303Smarkm if (!rescan_ok 23346303Smarkm || IF_RESCAN_DELAY()) 23446303Smarkm return 0; 23546303Smarkm ifinit(); 23618316Swollman } 23718316Swollman} 23818316Swollman 23918316Swollman 24018316Swollman/* Find an interface from which the specified address 24118316Swollman * should have come from. Used for figuring out which 24220339Swollman * interface a packet came in on. 24318316Swollman */ 24418316Swollmanstruct interface * 24518316Swollmaniflookup(naddr addr) 24618316Swollman{ 24718316Swollman struct interface *ifp, *maybe; 248126250Sbms int once = 0; 24918316Swollman 25018316Swollman maybe = 0; 25120339Swollman for (;;) { 25220339Swollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 25320339Swollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 25420339Swollman /* finished with a match */ 25520339Swollman if (ifp->int_dstaddr == addr) 25620339Swollman return ifp; 25718316Swollman 25820339Swollman } else { 25920339Swollman /* finished with an exact match */ 26020339Swollman if (ifp->int_addr == addr) 26120339Swollman return ifp; 26218316Swollman 26320339Swollman /* Look for the longest approximate match. 26420339Swollman */ 26520339Swollman if (on_net(addr, ifp->int_net, ifp->int_mask) 26620339Swollman && (maybe == 0 26720339Swollman || ifp->int_mask > maybe->int_mask)) 26820339Swollman maybe = ifp; 26920339Swollman } 27018316Swollman } 27120339Swollman 272126250Sbms if (maybe != 0 || once || IF_RESCAN_DELAY()) 27320339Swollman return maybe; 274126250Sbms once = 1; 27520339Swollman 27620339Swollman /* If there is no known interface, maybe there is a 27720339Swollman * new interface. So just once look for new interfaces. 27820339Swollman */ 27920339Swollman ifinit(); 28018316Swollman } 28118316Swollman} 28218316Swollman 28318316Swollman 28418316Swollman/* Return the classical netmask for an IP address. 28518316Swollman */ 28620339Swollmannaddr /* host byte order */ 28720339Swollmanstd_mask(naddr addr) /* network byte order */ 28818316Swollman{ 28990868Smike addr = ntohl(addr); /* was a host, not a network */ 29018316Swollman 29118316Swollman if (addr == 0) /* default route has mask 0 */ 29218316Swollman return 0; 29318316Swollman if (IN_CLASSA(addr)) 29418316Swollman return IN_CLASSA_NET; 29518316Swollman if (IN_CLASSB(addr)) 29618316Swollman return IN_CLASSB_NET; 29718316Swollman return IN_CLASSC_NET; 29818316Swollman} 29918316Swollman 30018316Swollman 30118316Swollman/* Find the netmask that would be inferred by RIPv1 listeners 30218316Swollman * on the given interface for a given network. 30318316Swollman * If no interface is specified, look for the best fitting interface. 30418316Swollman */ 30518316Swollmannaddr 30618316Swollmanripv1_mask_net(naddr addr, /* in network byte order */ 30718316Swollman struct interface *ifp) /* as seen on this interface */ 30818316Swollman{ 30946303Smarkm struct r1net *r1p; 31018316Swollman naddr mask = 0; 31118316Swollman 31218316Swollman if (addr == 0) /* default always has 0 mask */ 31318316Swollman return mask; 31418316Swollman 31546303Smarkm if (ifp != 0 && ifp->int_ripv1_mask != HOST_MASK) { 31618316Swollman /* If the target network is that of the associated interface 31718316Swollman * on which it arrived, then use the netmask of the interface. 31818316Swollman */ 31918316Swollman if (on_net(addr, ifp->int_net, ifp->int_std_mask)) 32018316Swollman mask = ifp->int_ripv1_mask; 32118316Swollman 32218316Swollman } else { 32318316Swollman /* Examine all interfaces, and if it the target seems 32418316Swollman * to have the same network number of an interface, use the 32518316Swollman * netmask of that interface. If there is more than one 32618316Swollman * such interface, prefer the interface with the longest 32718316Swollman * match. 32818316Swollman */ 32918316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 33018316Swollman if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) 33146303Smarkm && ifp->int_ripv1_mask > mask 33246303Smarkm && ifp->int_ripv1_mask != HOST_MASK) 33318316Swollman mask = ifp->int_ripv1_mask; 33418316Swollman } 33546303Smarkm 33618316Swollman } 33718316Swollman 33846303Smarkm /* check special definitions */ 33946303Smarkm if (mask == 0) { 34046303Smarkm for (r1p = r1nets; r1p != 0; r1p = r1p->r1net_next) { 34146303Smarkm if (on_net(addr, r1p->r1net_net, r1p->r1net_match) 34246303Smarkm && r1p->r1net_mask > mask) 34346303Smarkm mask = r1p->r1net_mask; 34446303Smarkm } 34518316Swollman 34646303Smarkm /* Otherwise, make the classic A/B/C guess. 34746303Smarkm */ 34846303Smarkm if (mask == 0) 34946303Smarkm mask = std_mask(addr); 35046303Smarkm } 35146303Smarkm 35218316Swollman return mask; 35318316Swollman} 35418316Swollman 35518316Swollman 35618316Swollmannaddr 35718316Swollmanripv1_mask_host(naddr addr, /* in network byte order */ 35818316Swollman struct interface *ifp) /* as seen on this interface */ 35918316Swollman{ 36018316Swollman naddr mask = ripv1_mask_net(addr, ifp); 36118316Swollman 36218316Swollman 36318316Swollman /* If the computed netmask does not mask the address, 36418316Swollman * then assume it is a host address 36518316Swollman */ 36618316Swollman if ((ntohl(addr) & ~mask) != 0) 36718316Swollman mask = HOST_MASK; 36818316Swollman return mask; 36918316Swollman} 37018316Swollman 37118316Swollman 372108533Sschweikh/* See if an IP address looks reasonable as a destination. 37318316Swollman */ 37418316Swollmanint /* 0=bad */ 37518316Swollmancheck_dst(naddr addr) 37618316Swollman{ 37790868Smike addr = ntohl(addr); 37818316Swollman 37918316Swollman if (IN_CLASSA(addr)) { 38018316Swollman if (addr == 0) 38118316Swollman return 1; /* default */ 38218316Swollman 38318316Swollman addr >>= IN_CLASSA_NSHIFT; 38418316Swollman return (addr != 0 && addr != IN_LOOPBACKNET); 38518316Swollman } 38618316Swollman 38718316Swollman return (IN_CLASSB(addr) || IN_CLASSC(addr)); 38818316Swollman} 38918316Swollman 39018316Swollman 39119880Swollman/* See a new interface duplicates an existing interface. 39219880Swollman */ 39319880Swollmanstruct interface * 39420339Swollmancheck_dup(naddr addr, /* IP address, so network byte order */ 39520339Swollman naddr dstaddr, /* ditto */ 39620339Swollman naddr mask, /* mask, so host byte order */ 39719880Swollman int if_flags) 39819880Swollman{ 39919880Swollman struct interface *ifp; 40019880Swollman 40119880Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 40219880Swollman if (ifp->int_mask != mask) 40319880Swollman continue; 40419880Swollman 40546303Smarkm if (!iff_up(ifp->int_if_flags)) 40619880Swollman continue; 40719880Swollman 40846303Smarkm /* The local address can only be shared with a point-to-point 40946303Smarkm * link. 41019880Swollman */ 411126250Sbms if ((!(ifp->int_state & IS_REMOTE) || !(if_flags & IS_REMOTE)) 412126250Sbms && ifp->int_addr == addr 41319880Swollman && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) 41419880Swollman return ifp; 41519880Swollman 41619880Swollman if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask)) 41719880Swollman return ifp; 41819880Swollman } 41919880Swollman return 0; 42019880Swollman} 42119880Swollman 42219880Swollman 42319880Swollman/* See that a remote gateway is reachable. 42419880Swollman * Note that the answer can change as real interfaces come and go. 42519880Swollman */ 42619880Swollmanint /* 0=bad */ 42719880Swollmancheck_remote(struct interface *ifp) 42819880Swollman{ 42919880Swollman struct rt_entry *rt; 43019880Swollman 43119880Swollman /* do not worry about other kinds */ 43219880Swollman if (!(ifp->int_state & IS_REMOTE)) 43319880Swollman return 1; 43419880Swollman 43519880Swollman rt = rtfind(ifp->int_addr); 43619880Swollman if (rt != 0 43719880Swollman && rt->rt_ifp != 0 43819880Swollman &&on_net(ifp->int_addr, 43919880Swollman rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) 44019880Swollman return 1; 44119880Swollman 44219880Swollman /* the gateway cannot be reached directly from one of our 44319880Swollman * interfaces 44419880Swollman */ 44519880Swollman if (!(ifp->int_state & IS_BROKE)) { 44619880Swollman msglog("unreachable gateway %s in "_PATH_GATEWAYS, 44719880Swollman naddr_ntoa(ifp->int_addr)); 44819880Swollman if_bad(ifp); 44919880Swollman } 45019880Swollman return 0; 45119880Swollman} 45219880Swollman 45319880Swollman 45418316Swollman/* Delete an interface. 45518316Swollman */ 45618316Swollmanstatic void 45718316Swollmanifdel(struct interface *ifp) 45818316Swollman{ 45918316Swollman struct ip_mreq m; 46018316Swollman struct interface *ifp1; 46118316Swollman 46218316Swollman 46318316Swollman trace_if("Del", ifp); 46418316Swollman 46518316Swollman ifp->int_state |= IS_BROKE; 46618316Swollman 46718316Swollman /* unlink the interface 46818316Swollman */ 46919880Swollman *ifp->int_prev = ifp->int_next; 47018316Swollman if (ifp->int_next != 0) 47118316Swollman ifp->int_next->int_prev = ifp->int_prev; 47219880Swollman *ifp->int_ahash_prev = ifp->int_ahash; 47319880Swollman if (ifp->int_ahash != 0) 47419880Swollman ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev; 47521378Swollman *ifp->int_nhash_prev = ifp->int_nhash; 47621378Swollman if (ifp->int_nhash != 0) 47721378Swollman ifp->int_nhash->int_nhash_prev = ifp->int_nhash_prev; 47819880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 47919880Swollman *ifp->int_bhash_prev = ifp->int_bhash; 48019880Swollman if (ifp->int_bhash != 0) 48119880Swollman ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev; 48219880Swollman } 48319880Swollman if (ifp->int_state & IS_REMOTE) { 48419880Swollman *ifp->int_rlink_prev = ifp->int_rlink; 48519880Swollman if (ifp->int_rlink != 0) 48619880Swollman ifp->int_rlink->int_rlink_prev = ifp->int_rlink_prev; 48719880Swollman } 48818316Swollman 48918316Swollman if (!(ifp->int_state & IS_ALIAS)) { 49019880Swollman /* delete aliases when the main interface dies 49118316Swollman */ 49218316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 49318316Swollman if (ifp1 != ifp 49418316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 49518316Swollman ifdel(ifp1); 49618316Swollman } 49718316Swollman 49818316Swollman if ((ifp->int_if_flags & IFF_MULTICAST) 49918316Swollman#ifdef MCAST_PPP_BUG 50018316Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 50118316Swollman#endif 50218316Swollman && rip_sock >= 0) { 50318316Swollman m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 504126250Sbms#ifdef MCAST_IFINDEX 505126250Sbms m.imr_interface.s_addr = htonl(ifp->int_index); 506126250Sbms#else 50718316Swollman m.imr_interface.s_addr = ((ifp->int_if_flags 50818316Swollman & IFF_POINTOPOINT) 50918316Swollman ? ifp->int_dstaddr 51018316Swollman : ifp->int_addr); 511126250Sbms#endif 51218316Swollman if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP, 51318316Swollman &m, sizeof(m)) < 0 51418316Swollman && errno != EADDRNOTAVAIL 51518316Swollman && !TRACEACTIONS) 51618316Swollman LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)"); 51719880Swollman if (rip_sock_mcast == ifp) 51819880Swollman rip_sock_mcast = 0; 51918316Swollman } 52018316Swollman if (ifp->int_rip_sock >= 0) { 52118316Swollman (void)close(ifp->int_rip_sock); 52218316Swollman ifp->int_rip_sock = -1; 52318316Swollman fix_select(); 52418316Swollman } 52518316Swollman 52618316Swollman tot_interfaces--; 52718316Swollman if (!IS_RIP_OFF(ifp->int_state)) 52818316Swollman rip_interfaces--; 52918316Swollman 53018316Swollman /* Zap all routes associated with this interface. 53146303Smarkm * Assume routes just using gateways beyond this interface 53246303Smarkm * will timeout naturally, and have probably already died. 53318316Swollman */ 53418316Swollman (void)rn_walktree(rhead, walk_bad, 0); 53518316Swollman 53618316Swollman set_rdisc_mg(ifp, 0); 53718316Swollman if_bad_rdisc(ifp); 53818316Swollman } 53918316Swollman 54018316Swollman free(ifp); 54118316Swollman} 54218316Swollman 54318316Swollman 54418316Swollman/* Mark an interface ill. 54518316Swollman */ 54618316Swollmanvoid 54718316Swollmanif_sick(struct interface *ifp) 54818316Swollman{ 54918316Swollman if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) { 55018316Swollman ifp->int_state |= IS_SICK; 55119880Swollman ifp->int_act_time = NEVER; 55218316Swollman trace_if("Chg", ifp); 55318316Swollman 55418316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 55518316Swollman } 55618316Swollman} 55718316Swollman 55818316Swollman 55918316Swollman/* Mark an interface dead. 56018316Swollman */ 56118316Swollmanvoid 56218316Swollmanif_bad(struct interface *ifp) 56318316Swollman{ 56418316Swollman struct interface *ifp1; 56518316Swollman 56618316Swollman 56718316Swollman if (ifp->int_state & IS_BROKE) 56818316Swollman return; 56918316Swollman 57018316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 57118316Swollman 57218316Swollman ifp->int_state |= (IS_BROKE | IS_SICK); 57319880Swollman ifp->int_act_time = NEVER; 57419880Swollman ifp->int_query_time = NEVER; 57546303Smarkm ifp->int_data.ts = now.tv_sec; 57618316Swollman 57718316Swollman trace_if("Chg", ifp); 57818316Swollman 57918316Swollman if (!(ifp->int_state & IS_ALIAS)) { 58018316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 58118316Swollman if (ifp1 != ifp 58218316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 58318316Swollman if_bad(ifp1); 58418316Swollman } 58518316Swollman (void)rn_walktree(rhead, walk_bad, 0); 58618316Swollman if_bad_rdisc(ifp); 58718316Swollman } 58818316Swollman} 58918316Swollman 59018316Swollman 59118316Swollman/* Mark an interface alive 59218316Swollman */ 59318316Swollmanint /* 1=it was dead */ 59418316Swollmanif_ok(struct interface *ifp, 59546303Smarkm const char *type) 59618316Swollman{ 59718316Swollman struct interface *ifp1; 59818316Swollman 59918316Swollman 60018316Swollman if (!(ifp->int_state & IS_BROKE)) { 60118316Swollman if (ifp->int_state & IS_SICK) { 60219880Swollman trace_act("%sinterface %s to %s working better", 60318316Swollman type, 60419880Swollman ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 60518316Swollman ifp->int_state &= ~IS_SICK; 60618316Swollman } 60718316Swollman return 0; 60818316Swollman } 60918316Swollman 61018316Swollman msglog("%sinterface %s to %s restored", 61119880Swollman type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 61218316Swollman ifp->int_state &= ~(IS_BROKE | IS_SICK); 61318316Swollman ifp->int_data.ts = 0; 61418316Swollman 61518316Swollman if (!(ifp->int_state & IS_ALIAS)) { 61618316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 61718316Swollman if (ifp1 != ifp 61818316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 61918316Swollman if_ok(ifp1, type); 62018316Swollman } 62118316Swollman if_ok_rdisc(ifp); 62218316Swollman } 62319880Swollman 62419880Swollman if (ifp->int_state & IS_REMOTE) { 62519880Swollman if (!addrouteforif(ifp)) 62619880Swollman return 0; 62719880Swollman } 62818316Swollman return 1; 62918316Swollman} 63018316Swollman 63118316Swollman 63246303Smarkm/* disassemble routing message 63318316Swollman */ 63418316Swollmanvoid 63518316Swollmanrt_xaddrs(struct rt_addrinfo *info, 63618316Swollman struct sockaddr *sa, 63718316Swollman struct sockaddr *lim, 63818316Swollman int addrs) 63918316Swollman{ 64018316Swollman int i; 64146303Smarkm#ifdef _HAVE_SA_LEN 64246303Smarkm static struct sockaddr sa_zero; 64346303Smarkm#endif 64418316Swollman#ifdef sgi 64518316Swollman#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \ 64618316Swollman : sizeof(__uint64_t)) 64718316Swollman#else 64818316Swollman#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ 64918316Swollman : sizeof(long)) 65018316Swollman#endif 65118316Swollman 65218316Swollman 65346303Smarkm memset(info, 0, sizeof(*info)); 65418316Swollman info->rti_addrs = addrs; 65518316Swollman for (i = 0; i < RTAX_MAX && sa < lim; i++) { 65618316Swollman if ((addrs & (1 << i)) == 0) 65718316Swollman continue; 65818316Swollman#ifdef _HAVE_SA_LEN 65946303Smarkm info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; 66046303Smarkm sa = (struct sockaddr *)((char*)(sa) 66146303Smarkm + ROUNDUP(sa->sa_len)); 66218316Swollman#else 66346303Smarkm info->rti_info[i] = sa; 66446303Smarkm sa = (struct sockaddr *)((char*)(sa) 66546303Smarkm + ROUNDUP(_FAKE_SA_LEN_DST(sa))); 66627503Sjulian#endif 66718316Swollman } 66818316Swollman} 66918316Swollman 67018316Swollman 67118316Swollman/* Find the network interfaces which have configured themselves. 67218316Swollman * This must be done regularly, if only for extra addresses 67318316Swollman * that come and go on interfaces. 67418316Swollman */ 67518316Swollmanvoid 67618316Swollmanifinit(void) 67718316Swollman{ 67818316Swollman static char *sysctl_buf; 67918316Swollman static size_t sysctl_buf_size = 0; 68018316Swollman uint complaints = 0; 68118316Swollman static u_int prev_complaints = 0; 68218316Swollman# define COMP_NOT_INET 0x001 68319880Swollman# define COMP_NOADDR 0x002 68419880Swollman# define COMP_BADADDR 0x004 68519880Swollman# define COMP_NODST 0x008 68619880Swollman# define COMP_NOBADR 0x010 68719880Swollman# define COMP_NOMASK 0x020 68819880Swollman# define COMP_DUP 0x040 68919880Swollman# define COMP_BAD_METRIC 0x080 69019880Swollman# define COMP_NETMASK 0x100 69118316Swollman 69218316Swollman struct interface ifs, ifs0, *ifp, *ifp1; 69318316Swollman struct rt_entry *rt; 69418316Swollman size_t needed; 69518316Swollman int mib[6]; 69618316Swollman struct if_msghdr *ifm; 69718316Swollman struct ifa_msghdr *ifam, *ifam_lim, *ifam2; 69818316Swollman int in, ierr, out, oerr; 69918316Swollman struct intnet *intnetp; 70018316Swollman struct rt_addrinfo info; 70118316Swollman#ifdef SIOCGIFMETRIC 70218316Swollman struct ifreq ifr; 70318316Swollman#endif 70418316Swollman 70518316Swollman 70620606Swollman last_ifinit = now; 70718316Swollman ifinit_timer.tv_sec = now.tv_sec + (supplier 70818316Swollman ? CHECK_ACT_INTERVAL 70918316Swollman : CHECK_QUIET_INTERVAL); 71018316Swollman 71137908Scharnier /* mark all interfaces so we can get rid of those that disappear */ 71218316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) 71318316Swollman ifp->int_state &= ~(IS_CHECKED | IS_DUP); 71418316Swollman 71518316Swollman /* Fetch the interface list, without too many system calls 71618316Swollman * since we do it repeatedly. 71718316Swollman */ 71818316Swollman mib[0] = CTL_NET; 71918316Swollman mib[1] = PF_ROUTE; 72018316Swollman mib[2] = 0; 72118316Swollman mib[3] = AF_INET; 72218316Swollman mib[4] = NET_RT_IFLIST; 72318316Swollman mib[5] = 0; 72418316Swollman for (;;) { 72518316Swollman if ((needed = sysctl_buf_size) != 0) { 72618316Swollman if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 72718316Swollman break; 72846303Smarkm /* retry if the table grew */ 72918316Swollman if (errno != ENOMEM && errno != EFAULT) 73046303Smarkm BADERR(1, "ifinit: sysctl(RT_IFLIST)"); 73118316Swollman free(sysctl_buf); 73218316Swollman needed = 0; 73318316Swollman } 73418316Swollman if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 73546303Smarkm BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate"); 73646303Smarkm sysctl_buf = rtmalloc(sysctl_buf_size = needed, 73746303Smarkm "ifinit sysctl"); 73818316Swollman } 73918316Swollman 74018316Swollman ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed); 74118316Swollman for (ifam = (struct ifa_msghdr *)sysctl_buf; 74218316Swollman ifam < ifam_lim; 74318316Swollman ifam = ifam2) { 74418316Swollman 74518316Swollman ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); 74618316Swollman 747126250Sbms#ifdef RTM_OIFINFO 748126250Sbms if (ifam->ifam_type == RTM_OIFINFO) 749126250Sbms continue; /* just ignore compat message */ 750126250Sbms#endif 75118316Swollman if (ifam->ifam_type == RTM_IFINFO) { 75219880Swollman struct sockaddr_dl *sdl; 75319880Swollman 75418316Swollman ifm = (struct if_msghdr *)ifam; 75518316Swollman /* make prototype structure for the IP aliases 75618316Swollman */ 75746303Smarkm memset(&ifs0, 0, sizeof(ifs0)); 75818316Swollman ifs0.int_rip_sock = -1; 75918316Swollman ifs0.int_index = ifm->ifm_index; 76018316Swollman ifs0.int_if_flags = ifm->ifm_flags; 76118316Swollman ifs0.int_state = IS_CHECKED; 76220339Swollman ifs0.int_query_time = NEVER; 76318316Swollman ifs0.int_act_time = now.tv_sec; 76418316Swollman ifs0.int_data.ts = now.tv_sec; 76518316Swollman ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; 76618316Swollman ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors; 76718316Swollman ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets; 76818316Swollman ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors; 76918316Swollman#ifdef sgi 77018316Swollman ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops; 77118316Swollman#endif 77218316Swollman sdl = (struct sockaddr_dl *)(ifm + 1); 77318316Swollman sdl->sdl_data[sdl->sdl_nlen] = 0; 77419880Swollman strncpy(ifs0.int_name, sdl->sdl_data, 77519880Swollman MIN(sizeof(ifs0.int_name), sdl->sdl_nlen)); 77618316Swollman continue; 77718316Swollman } 77818316Swollman if (ifam->ifam_type != RTM_NEWADDR) { 77918316Swollman logbad(1,"ifinit: out of sync"); 78018316Swollman continue; 78118316Swollman } 78218316Swollman rt_xaddrs(&info, (struct sockaddr *)(ifam+1), 78318316Swollman (struct sockaddr *)ifam2, 78418316Swollman ifam->ifam_addrs); 78518316Swollman 78619880Swollman /* Prepare for the next address of this interface, which 78719880Swollman * will be an alias. 78819880Swollman * Do not output RIP or Router-Discovery packets via aliases. 78919880Swollman */ 79046303Smarkm memcpy(&ifs, &ifs0, sizeof(ifs)); 79146303Smarkm ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC); 79219880Swollman 79318316Swollman if (INFO_IFA(&info) == 0) { 79446303Smarkm if (iff_up(ifs.int_if_flags)) { 79518316Swollman if (!(prev_complaints & COMP_NOADDR)) 79618316Swollman msglog("%s has no address", 79719880Swollman ifs.int_name); 79818316Swollman complaints |= COMP_NOADDR; 79918316Swollman } 80018316Swollman continue; 80118316Swollman } 80218316Swollman if (INFO_IFA(&info)->sa_family != AF_INET) { 80346303Smarkm if (iff_up(ifs.int_if_flags)) { 80418316Swollman if (!(prev_complaints & COMP_NOT_INET)) 80519880Swollman trace_act("%s: not AF_INET", 80619880Swollman ifs.int_name); 80718316Swollman complaints |= COMP_NOT_INET; 80818316Swollman } 80918316Swollman continue; 81018316Swollman } 81118316Swollman 81218316Swollman ifs.int_addr = S_ADDR(INFO_IFA(&info)); 81318316Swollman 81418316Swollman if (ntohl(ifs.int_addr)>>24 == 0 81518316Swollman || ntohl(ifs.int_addr)>>24 == 0xff) { 81646303Smarkm if (iff_up(ifs.int_if_flags)) { 81718316Swollman if (!(prev_complaints & COMP_BADADDR)) 81818316Swollman msglog("%s has a bad address", 81919880Swollman ifs.int_name); 82018316Swollman complaints |= COMP_BADADDR; 82118316Swollman } 82218316Swollman continue; 82318316Swollman } 82418316Swollman 82519880Swollman if (ifs.int_if_flags & IFF_LOOPBACK) { 82619880Swollman ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC; 82718316Swollman ifs.int_dstaddr = ifs.int_addr; 82819880Swollman ifs.int_mask = HOST_MASK; 82919880Swollman ifs.int_ripv1_mask = HOST_MASK; 83019880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 83119880Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 83219880Swollman if (!foundloopback) { 83319880Swollman foundloopback = 1; 83419880Swollman loopaddr = ifs.int_addr; 83546303Smarkm loop_rts.rts_gate = loopaddr; 83646303Smarkm loop_rts.rts_router = loopaddr; 83718316Swollman } 83818316Swollman 83918316Swollman } else if (ifs.int_if_flags & IFF_POINTOPOINT) { 84018316Swollman if (INFO_BRD(&info) == 0 84118316Swollman || INFO_BRD(&info)->sa_family != AF_INET) { 84246303Smarkm if (iff_up(ifs.int_if_flags)) { 84318316Swollman if (!(prev_complaints & COMP_NODST)) 84418316Swollman msglog("%s has a bad" 84518316Swollman " destination address", 84619880Swollman ifs.int_name); 84718316Swollman complaints |= COMP_NODST; 84818316Swollman } 84918316Swollman continue; 85018316Swollman } 85118316Swollman ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); 85218316Swollman if (ntohl(ifs.int_dstaddr)>>24 == 0 85318316Swollman || ntohl(ifs.int_dstaddr)>>24 == 0xff) { 85446303Smarkm if (iff_up(ifs.int_if_flags)) { 85518316Swollman if (!(prev_complaints & COMP_NODST)) 85618316Swollman msglog("%s has a bad" 85718316Swollman " destination address", 85819880Swollman ifs.int_name); 85918316Swollman complaints |= COMP_NODST; 86018316Swollman } 86118316Swollman continue; 86218316Swollman } 86318316Swollman ifs.int_mask = HOST_MASK; 86418316Swollman ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); 86519880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 86618316Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 86718316Swollman 86819880Swollman } else { 86919880Swollman if (INFO_MASK(&info) == 0) { 87046303Smarkm if (iff_up(ifs.int_if_flags)) { 87119880Swollman if (!(prev_complaints & COMP_NOMASK)) 87219880Swollman msglog("%s has no netmask", 87319880Swollman ifs.int_name); 87419880Swollman complaints |= COMP_NOMASK; 87519880Swollman } 87619880Swollman continue; 87719880Swollman } 87818316Swollman ifs.int_dstaddr = ifs.int_addr; 87919880Swollman ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); 88019880Swollman ifs.int_ripv1_mask = ifs.int_mask; 88119880Swollman ifs.int_std_mask = std_mask(ifs.int_addr); 88219880Swollman ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; 88319880Swollman if (ifs.int_mask != ifs.int_std_mask) 88419880Swollman ifs.int_state |= IS_SUBNET; 88519880Swollman 88619880Swollman if (ifs.int_if_flags & IFF_BROADCAST) { 88719880Swollman if (INFO_BRD(&info) == 0) { 88846303Smarkm if (iff_up(ifs.int_if_flags)) { 88919880Swollman if (!(prev_complaints 89019880Swollman & COMP_NOBADR)) 89119880Swollman msglog("%s has" 89219880Swollman "no broadcast address", 89319880Swollman ifs.int_name); 89419880Swollman complaints |= COMP_NOBADR; 89519880Swollman } 89619880Swollman continue; 89719880Swollman } 89819880Swollman ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); 89918316Swollman } 90018316Swollman } 90118316Swollman ifs.int_std_net = ifs.int_net & ifs.int_std_mask; 90218316Swollman ifs.int_std_addr = htonl(ifs.int_std_net); 90318316Swollman 90418316Swollman /* Use a minimum metric of one. Treat the interface metric 90518316Swollman * (default 0) as an increment to the hop count of one. 90618316Swollman * 90718316Swollman * The metric obtained from the routing socket dump of 90818316Swollman * interface addresses is wrong. It is not set by the 90918316Swollman * SIOCSIFMETRIC ioctl. 91018316Swollman */ 91118316Swollman#ifdef SIOCGIFMETRIC 91219880Swollman strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name)); 91318316Swollman if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) { 91418316Swollman DBGERR(1, "ioctl(SIOCGIFMETRIC)"); 91518316Swollman ifs.int_metric = 0; 91618316Swollman } else { 91718316Swollman ifs.int_metric = ifr.ifr_metric; 91818316Swollman } 91918316Swollman#else 92018316Swollman ifs.int_metric = ifam->ifam_metric; 92118316Swollman#endif 92218316Swollman if (ifs.int_metric > HOPCNT_INFINITY) { 92318316Swollman ifs.int_metric = 0; 92418316Swollman if (!(prev_complaints & COMP_BAD_METRIC) 92546303Smarkm && iff_up(ifs.int_if_flags)) { 92618316Swollman complaints |= COMP_BAD_METRIC; 92718316Swollman msglog("%s has a metric of %d", 92819880Swollman ifs.int_name, ifs.int_metric); 92918316Swollman } 93018316Swollman } 93118316Swollman 93218316Swollman /* See if this is a familiar interface. 93318316Swollman * If so, stop worrying about it if it is the same. 93418316Swollman * Start it over if it now is to somewhere else, as happens 93518316Swollman * frequently with PPP and SLIP. 93618316Swollman */ 93719880Swollman ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS) 93819880Swollman ? ifs.int_addr 93919880Swollman : 0)); 94018316Swollman if (ifp != 0) { 94118316Swollman ifp->int_state |= IS_CHECKED; 94218316Swollman 94318316Swollman if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags) 94418316Swollman & (IFF_BROADCAST 94518316Swollman | IFF_LOOPBACK 94618316Swollman | IFF_POINTOPOINT 94718316Swollman | IFF_MULTICAST)) 94818316Swollman || 0 != ((ifp->int_state ^ ifs.int_state) 94918316Swollman & IS_ALIAS) 95018316Swollman || ifp->int_addr != ifs.int_addr 95118316Swollman || ifp->int_brdaddr != ifs.int_brdaddr 95218316Swollman || ifp->int_dstaddr != ifs.int_dstaddr 95318316Swollman || ifp->int_mask != ifs.int_mask 95418316Swollman || ifp->int_metric != ifs.int_metric) { 95518316Swollman /* Forget old information about 95618316Swollman * a changed interface. 95718316Swollman */ 95819880Swollman trace_act("interface %s has changed", 95918316Swollman ifp->int_name); 96018316Swollman ifdel(ifp); 96118316Swollman ifp = 0; 96218316Swollman } 96318316Swollman } 96418316Swollman 96518316Swollman if (ifp != 0) { 96618316Swollman /* The primary representative of an alias worries 96718316Swollman * about how things are working. 96818316Swollman */ 96918316Swollman if (ifp->int_state & IS_ALIAS) 97018316Swollman continue; 97118316Swollman 97218316Swollman /* note interfaces that have been turned off 97318316Swollman */ 97446303Smarkm if (!iff_up(ifs.int_if_flags)) { 97546303Smarkm if (iff_up(ifp->int_if_flags)) { 97618316Swollman msglog("interface %s to %s turned off", 97718316Swollman ifp->int_name, 97819880Swollman naddr_ntoa(ifp->int_dstaddr)); 97918316Swollman if_bad(ifp); 98046303Smarkm ifp->int_if_flags &= ~IFF_UP; 98146303Smarkm } else if (now.tv_sec>(ifp->int_data.ts 98246303Smarkm + CHECK_BAD_INTERVAL)) { 98346303Smarkm trace_act("interface %s has been off" 98446303Smarkm " %ld seconds; forget it", 98546303Smarkm ifp->int_name, 98646303Smarkm now.tv_sec-ifp->int_data.ts); 98746303Smarkm ifdel(ifp); 98818316Swollman } 98918316Swollman continue; 99018316Swollman } 99118316Swollman /* or that were off and are now ok */ 99246303Smarkm if (!iff_up(ifp->int_if_flags)) { 99346303Smarkm ifp->int_if_flags |= IFF_UP; 99418316Swollman (void)if_ok(ifp, ""); 99518316Swollman } 99618316Swollman 99718316Swollman /* If it has been long enough, 99818316Swollman * see if the interface is broken. 99918316Swollman */ 100018316Swollman if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL) 100118316Swollman continue; 100218316Swollman 100318316Swollman in = ifs.int_data.ipackets - ifp->int_data.ipackets; 100418316Swollman ierr = ifs.int_data.ierrors - ifp->int_data.ierrors; 100518316Swollman out = ifs.int_data.opackets - ifp->int_data.opackets; 100618316Swollman oerr = ifs.int_data.oerrors - ifp->int_data.oerrors; 100718316Swollman#ifdef sgi 100818316Swollman /* Through at least IRIX 6.2, PPP and SLIP 100946303Smarkm * count packets dropped by the filters. 101018316Swollman * But FDDI rings stuck non-operational count 101118316Swollman * dropped packets as they wait for improvement. 101218316Swollman */ 101318316Swollman if (!(ifp->int_if_flags & IFF_POINTOPOINT)) 101418316Swollman oerr += (ifs.int_data.odrops 101518316Swollman - ifp->int_data.odrops); 101618316Swollman#endif 101718316Swollman /* If the interface just awoke, restart the counters. 101818316Swollman */ 101918316Swollman if (ifp->int_data.ts == 0) { 102018316Swollman ifp->int_data = ifs.int_data; 102118316Swollman continue; 102218316Swollman } 102318316Swollman ifp->int_data = ifs.int_data; 102418316Swollman 102537908Scharnier /* Withhold judgment when the short error 102618316Swollman * counters wrap or the interface is reset. 102718316Swollman */ 102818316Swollman if (ierr < 0 || in < 0 || oerr < 0 || out < 0) { 102918316Swollman LIM_SEC(ifinit_timer, 103018316Swollman now.tv_sec+CHECK_BAD_INTERVAL); 103118316Swollman continue; 103218316Swollman } 103318316Swollman 103418316Swollman /* Withhold judgement when there is no traffic 103518316Swollman */ 103618316Swollman if (in == 0 && out == 0 && ierr == 0 && oerr == 0) 103718316Swollman continue; 103818316Swollman 103918316Swollman /* It is bad if input or output is not working. 104018316Swollman * Require presistent problems before marking it dead. 104118316Swollman */ 104218316Swollman if ((in <= ierr && ierr > 0) 104318316Swollman || (out <= oerr && oerr > 0)) { 104418316Swollman if (!(ifp->int_state & IS_SICK)) { 104518316Swollman trace_act("interface %s to %s" 104618316Swollman " sick: in=%d ierr=%d" 104719880Swollman " out=%d oerr=%d", 104818316Swollman ifp->int_name, 104919880Swollman naddr_ntoa(ifp->int_dstaddr), 105018316Swollman in, ierr, out, oerr); 105118316Swollman if_sick(ifp); 105218316Swollman continue; 105318316Swollman } 105418316Swollman if (!(ifp->int_state & IS_BROKE)) { 105519880Swollman msglog("interface %s to %s broken:" 105618316Swollman " in=%d ierr=%d out=%d oerr=%d", 105718316Swollman ifp->int_name, 105819880Swollman naddr_ntoa(ifp->int_dstaddr), 105918316Swollman in, ierr, out, oerr); 106018316Swollman if_bad(ifp); 106118316Swollman } 106218316Swollman continue; 106318316Swollman } 106418316Swollman 106518316Swollman /* otherwise, it is active and healthy 106618316Swollman */ 106718316Swollman ifp->int_act_time = now.tv_sec; 106818316Swollman (void)if_ok(ifp, ""); 106918316Swollman continue; 107018316Swollman } 107118316Swollman 107218316Swollman /* This is a new interface. 107318316Swollman * If it is dead, forget it. 107418316Swollman */ 107546303Smarkm if (!iff_up(ifs.int_if_flags)) 107618316Swollman continue; 107718316Swollman 107819880Swollman /* If it duplicates an existing interface, 107919880Swollman * complain about it, mark the other one 108019880Swollman * duplicated, and forget this one. 108118316Swollman */ 108219880Swollman ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, 108319880Swollman ifs.int_if_flags); 108419880Swollman if (ifp != 0) { 108546303Smarkm /* Ignore duplicates of itself, caused by having 108646303Smarkm * IP aliases on the same network. 108746303Smarkm */ 108846303Smarkm if (!strcmp(ifp->int_name, ifs.int_name)) 108946303Smarkm continue; 109046303Smarkm 109118316Swollman if (!(prev_complaints & COMP_DUP)) { 109218316Swollman complaints |= COMP_DUP; 109320339Swollman msglog("%s (%s%s%s) is duplicated by" 109420339Swollman " %s (%s%s%s)", 109520339Swollman ifs.int_name, 109620339Swollman addrname(ifs.int_addr,ifs.int_mask,1), 109720339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 109820339Swollman ? "-->" : ""), 109920339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 110020339Swollman ? naddr_ntoa(ifs.int_dstaddr) : ""), 110120339Swollman ifp->int_name, 110220339Swollman addrname(ifp->int_addr,ifp->int_mask,1), 110320339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 110420339Swollman ? "-->" : ""), 110520339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 110620339Swollman ? naddr_ntoa(ifp->int_dstaddr) : "")); 110718316Swollman } 110818316Swollman ifp->int_state |= IS_DUP; 110919880Swollman continue; 111018316Swollman } 111118316Swollman 111219880Swollman if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST)) 111319880Swollman && !(ifs.int_state & IS_PASSIVE)) { 111419880Swollman trace_act("%s is neither broadcast, point-to-point," 111519880Swollman " nor loopback", 111619880Swollman ifs.int_name); 111719880Swollman if (!(ifs.int_state & IFF_MULTICAST)) 111819880Swollman ifs.int_state |= IS_NO_RDISC; 111919880Swollman } 112018316Swollman 112119880Swollman 112219880Swollman /* It is new and ok. Add it to the list of interfaces 112318316Swollman */ 112446303Smarkm ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp"); 112546303Smarkm memcpy(ifp, &ifs, sizeof(*ifp)); 112619880Swollman get_parms(ifp); 112719880Swollman if_link(ifp); 112818316Swollman trace_if("Add", ifp); 112918316Swollman 113018316Swollman /* Notice likely bad netmask. 113118316Swollman */ 113218316Swollman if (!(prev_complaints & COMP_NETMASK) 113319880Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 113419880Swollman && ifp->int_addr != RIP_DEFAULT) { 113518316Swollman for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 113618316Swollman if (ifp1->int_mask == ifp->int_mask) 113718316Swollman continue; 113818316Swollman if (ifp1->int_if_flags & IFF_POINTOPOINT) 113918316Swollman continue; 114019880Swollman if (ifp1->int_dstaddr == RIP_DEFAULT) 114119880Swollman continue; 114264483Ssheldonh /* ignore aliases on the right network */ 114364483Ssheldonh if (!strcmp(ifp->int_name, ifp1->int_name)) 114464483Ssheldonh continue; 114519880Swollman if (on_net(ifp->int_dstaddr, 114618316Swollman ifp1->int_net, ifp1->int_mask) 114719880Swollman || on_net(ifp1->int_dstaddr, 114818316Swollman ifp->int_net, ifp->int_mask)) { 114918316Swollman msglog("possible netmask problem" 115019880Swollman " between %s:%s and %s:%s", 115118316Swollman ifp->int_name, 115218316Swollman addrname(htonl(ifp->int_net), 115318316Swollman ifp->int_mask, 1), 115418316Swollman ifp1->int_name, 115518316Swollman addrname(htonl(ifp1->int_net), 115618316Swollman ifp1->int_mask, 1)); 115718316Swollman complaints |= COMP_NETMASK; 115818316Swollman } 115918316Swollman } 116018316Swollman } 116118316Swollman 116218316Swollman if (!(ifp->int_state & IS_ALIAS)) { 116319880Swollman /* Count the # of directly connected networks. 116419880Swollman */ 116518316Swollman if (!(ifp->int_if_flags & IFF_LOOPBACK)) 116618316Swollman tot_interfaces++; 116718316Swollman if (!IS_RIP_OFF(ifp->int_state)) 116818316Swollman rip_interfaces++; 116919880Swollman 117019880Swollman /* turn on router discovery and RIP If needed */ 117119880Swollman if_ok_rdisc(ifp); 117219880Swollman rip_on(ifp); 117318316Swollman } 117418316Swollman } 117518316Swollman 117619880Swollman /* If we are multi-homed and have at least two interfaces 117718316Swollman * listening to RIP, then output by default. 117818316Swollman */ 117918316Swollman if (!supplier_set && rip_interfaces > 1) 118018316Swollman set_supplier(); 118118316Swollman 118218316Swollman /* If we are multi-homed, optionally advertise a route to 118318316Swollman * our main address. 118418316Swollman */ 118518316Swollman if (advertise_mhome 118618316Swollman || (tot_interfaces > 1 118718316Swollman && mhome 118818316Swollman && (ifp = ifwithaddr(myaddr, 0, 0)) != 0 118918316Swollman && foundloopback)) { 119018316Swollman advertise_mhome = 1; 119118316Swollman rt = rtget(myaddr, HOST_MASK); 119218316Swollman if (rt != 0) { 119318316Swollman if (rt->rt_ifp != ifp 119418316Swollman || rt->rt_router != loopaddr) { 119518316Swollman rtdelete(rt); 119618316Swollman rt = 0; 119718316Swollman } else { 119846303Smarkm loop_rts.rts_ifp = ifp; 119946303Smarkm loop_rts.rts_metric = 0; 120046303Smarkm loop_rts.rts_time = rt->rt_time; 120118316Swollman rtchange(rt, rt->rt_state | RS_MHOME, 120246303Smarkm &loop_rts, 0); 120318316Swollman } 120418316Swollman } 120546303Smarkm if (rt == 0) { 120646303Smarkm loop_rts.rts_ifp = ifp; 120746303Smarkm loop_rts.rts_metric = 0; 120846303Smarkm rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts); 120946303Smarkm } 121018316Swollman } 121118316Swollman 121218316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp1) { 121318316Swollman ifp1 = ifp->int_next; /* because we may delete it */ 121418316Swollman 121518316Swollman /* Forget any interfaces that have disappeared. 121618316Swollman */ 121718316Swollman if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { 121819880Swollman trace_act("interface %s has disappeared", 121918316Swollman ifp->int_name); 122018316Swollman ifdel(ifp); 122118316Swollman continue; 122218316Swollman } 122318316Swollman 122418316Swollman if ((ifp->int_state & IS_BROKE) 122518316Swollman && !(ifp->int_state & IS_PASSIVE)) 122618316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 122718316Swollman 122818316Swollman /* If we ever have a RIPv1 interface, assume we always will. 122918316Swollman * It might come back if it ever goes away. 123018316Swollman */ 123118316Swollman if (!(ifp->int_state & IS_NO_RIPV1_OUT) && supplier) 123218316Swollman have_ripv1_out = 1; 123318316Swollman if (!(ifp->int_state & IS_NO_RIPV1_IN)) 123418316Swollman have_ripv1_in = 1; 123518316Swollman } 123618316Swollman 123718316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 123818316Swollman /* Ensure there is always a network route for interfaces, 123918316Swollman * after any dead interfaces have been deleted, which 124018316Swollman * might affect routes for point-to-point links. 124118316Swollman */ 124219880Swollman if (!addrouteforif(ifp)) 124319880Swollman continue; 124418316Swollman 124518316Swollman /* Add routes to the local end of point-to-point interfaces 124618316Swollman * using loopback. 124718316Swollman */ 124818316Swollman if ((ifp->int_if_flags & IFF_POINTOPOINT) 124918316Swollman && !(ifp->int_state & IS_REMOTE) 125018316Swollman && foundloopback) { 125118316Swollman /* Delete any routes to the network address through 125218316Swollman * foreign routers. Remove even static routes. 125318316Swollman */ 125446303Smarkm del_static(ifp->int_addr, HOST_MASK, 0, 0); 125518316Swollman rt = rtget(ifp->int_addr, HOST_MASK); 125618316Swollman if (rt != 0 && rt->rt_router != loopaddr) { 125718316Swollman rtdelete(rt); 125818316Swollman rt = 0; 125918316Swollman } 126018316Swollman if (rt != 0) { 126118316Swollman if (!(rt->rt_state & RS_LOCAL) 126218316Swollman || rt->rt_metric > ifp->int_metric) { 126318316Swollman ifp1 = ifp; 126418316Swollman } else { 126518316Swollman ifp1 = rt->rt_ifp; 126618316Swollman } 126746303Smarkm loop_rts.rts_ifp = ifp1; 126846303Smarkm loop_rts.rts_metric = 0; 126946303Smarkm loop_rts.rts_time = rt->rt_time; 127046303Smarkm rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) 127146303Smarkm | (RS_IF|RS_LOCAL)), 127246303Smarkm &loop_rts, 0); 127318316Swollman } else { 127446303Smarkm loop_rts.rts_ifp = ifp; 127546303Smarkm loop_rts.rts_metric = 0; 127618316Swollman rtadd(ifp->int_addr, HOST_MASK, 127746303Smarkm (RS_IF | RS_LOCAL), &loop_rts); 127818316Swollman } 127918316Swollman } 128018316Swollman } 128118316Swollman 128218316Swollman /* add the authority routes */ 128318316Swollman for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) { 128418316Swollman rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); 128518316Swollman if (rt != 0 128618316Swollman && !(rt->rt_state & RS_NO_NET_SYN) 128718316Swollman && !(rt->rt_state & RS_NET_INT)) { 128818316Swollman rtdelete(rt); 128918316Swollman rt = 0; 129018316Swollman } 129146303Smarkm if (rt == 0) { 129246303Smarkm loop_rts.rts_ifp = 0; 129346303Smarkm loop_rts.rts_metric = intnetp->intnet_metric-1; 129418316Swollman rtadd(intnetp->intnet_addr, intnetp->intnet_mask, 129546303Smarkm RS_NET_SYN | RS_NET_INT, &loop_rts); 129646303Smarkm } 129718316Swollman } 129818316Swollman 129918316Swollman prev_complaints = complaints; 130018316Swollman} 130118316Swollman 130218316Swollman 130318316Swollmanstatic void 130418316Swollmancheck_net_syn(struct interface *ifp) 130518316Swollman{ 130618316Swollman struct rt_entry *rt; 130746303Smarkm static struct rt_spare new; 130818316Swollman 130918316Swollman 131018316Swollman /* Turn on the need to automatically synthesize a network route 131118316Swollman * for this interface only if we are running RIPv1 on some other 131218316Swollman * interface that is on a different class-A,B,or C network. 131318316Swollman */ 131418316Swollman if (have_ripv1_out || have_ripv1_in) { 131518316Swollman ifp->int_state |= IS_NEED_NET_SYN; 131618316Swollman rt = rtget(ifp->int_std_addr, ifp->int_std_mask); 131718316Swollman if (rt != 0 131818316Swollman && 0 == (rt->rt_state & RS_NO_NET_SYN) 131918316Swollman && (!(rt->rt_state & RS_NET_SYN) 132018316Swollman || rt->rt_metric > ifp->int_metric)) { 132118316Swollman rtdelete(rt); 132218316Swollman rt = 0; 132318316Swollman } 132446303Smarkm if (rt == 0) { 132546303Smarkm new.rts_ifp = ifp; 132646303Smarkm new.rts_gate = ifp->int_addr; 132746303Smarkm new.rts_router = ifp->int_addr; 132846303Smarkm new.rts_metric = ifp->int_metric; 132918316Swollman rtadd(ifp->int_std_addr, ifp->int_std_mask, 133046303Smarkm RS_NET_SYN, &new); 133146303Smarkm } 133218316Swollman 133318316Swollman } else { 133418316Swollman ifp->int_state &= ~IS_NEED_NET_SYN; 133518316Swollman 133618316Swollman rt = rtget(ifp->int_std_addr, 133718316Swollman ifp->int_std_mask); 133818316Swollman if (rt != 0 133918316Swollman && (rt->rt_state & RS_NET_SYN) 134018316Swollman && rt->rt_ifp == ifp) 134118316Swollman rtbad_sub(rt); 134218316Swollman } 134318316Swollman} 134418316Swollman 134518316Swollman 134618316Swollman/* Add route for interface if not currently installed. 134718316Swollman * Create route to other end if a point-to-point link, 134818316Swollman * otherwise a route to this (sub)network. 134918316Swollman */ 135019880Swollmanint /* 0=bad interface */ 135118316Swollmanaddrouteforif(struct interface *ifp) 135218316Swollman{ 135318316Swollman struct rt_entry *rt; 135446303Smarkm static struct rt_spare new; 135546303Smarkm naddr dst; 135618316Swollman 135718316Swollman 135818316Swollman /* skip sick interfaces 135918316Swollman */ 136018316Swollman if (ifp->int_state & IS_BROKE) 136119880Swollman return 0; 136218316Swollman 136318316Swollman /* If the interface on a subnet, then install a RIPv1 route to 136418316Swollman * the network as well (unless it is sick). 136518316Swollman */ 136618316Swollman if (ifp->int_state & IS_SUBNET) 136718316Swollman check_net_syn(ifp); 136818316Swollman 136919880Swollman dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) 137019880Swollman ? ifp->int_dstaddr 137119880Swollman : htonl(ifp->int_net)); 137218316Swollman 137346303Smarkm new.rts_ifp = ifp; 137446303Smarkm new.rts_router = ifp->int_addr; 137546303Smarkm new.rts_gate = ifp->int_addr; 137646303Smarkm new.rts_metric = ifp->int_metric; 137746303Smarkm new.rts_time = now.tv_sec; 137846303Smarkm 137919880Swollman /* If we are going to send packets to the gateway, 138019880Swollman * it must be reachable using our physical interfaces 138119880Swollman */ 138219880Swollman if ((ifp->int_state & IS_REMOTE) 138320339Swollman && !(ifp->int_state & IS_EXTERNAL) 138419880Swollman && !check_remote(ifp)) 138519880Swollman return 0; 138618316Swollman 138718316Swollman /* We are finished if the correct main interface route exists. 138818316Swollman * The right route must be for the right interface, not synthesized 138918316Swollman * from a subnet, be a "gateway" or not as appropriate, and so forth. 139018316Swollman */ 139146303Smarkm del_static(dst, ifp->int_mask, 0, 0); 139218316Swollman rt = rtget(dst, ifp->int_mask); 139318316Swollman if (rt != 0) { 139418316Swollman if ((rt->rt_ifp != ifp 139518316Swollman || rt->rt_router != ifp->int_addr) 139618316Swollman && (!(ifp->int_state & IS_DUP) 139718316Swollman || rt->rt_ifp == 0 139818316Swollman || (rt->rt_ifp->int_state & IS_BROKE))) { 139918316Swollman rtdelete(rt); 140018316Swollman rt = 0; 140118316Swollman } else { 140218316Swollman rtchange(rt, ((rt->rt_state | RS_IF) 140318316Swollman & ~(RS_NET_SYN | RS_LOCAL)), 140446303Smarkm &new, 0); 140518316Swollman } 140618316Swollman } 140718316Swollman if (rt == 0) { 140818316Swollman if (ifp->int_transitions++ > 0) 140919880Swollman trace_act("re-install interface %s", 141018316Swollman ifp->int_name); 141118316Swollman 141246303Smarkm rtadd(dst, ifp->int_mask, RS_IF, &new); 141318316Swollman } 141419880Swollman 141519880Swollman return 1; 141618316Swollman} 1417